├── .github └── v-git.png ├── .gitignore ├── LICENSE ├── README.md ├── git.v └── v.mod /.github/v-git.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Henrixounez/v-git/f010781b7cada7c1e439d81ecb123940f5aac447/.github/v-git.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | main 2 | v.git 3 | *.so 4 | *.dylib 5 | *.dll -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Henrixounez 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # **V-Git**: V Interface for Git 2 | 3 | ![logo](./.github/v-git.png) 4 | 5 | ### Methods 6 | | Method | use | 7 | |-|-| 8 | |`.clone(repository string)`| Clones a `repository` in current folder | 9 | |`.clone_to(repository string, dir string)`| Clones a `repository` into a specific `directory` | 10 | |`.clone_with_options(repository string, dir string, options string)` | Clones a `repository` into a specific `directory` with additional `options` 11 | |`.init()` | Creates a Git repository | 12 | |`.init_bare()` | Creates a bare Git repository | 13 | |`.init_with_options(options string)`| Create a Git repository with additional `options` | 14 | |`.add(file string)`| Adds a `file` to Git source control | 15 | |`.add_multiple(files []string)`| Adds `files` to Git source control | 16 | |`.mv(from string, to string)`| Moves or rename a `from` file `to` a destination | 17 | |`.rm(file string)`| Removes a `file` from Git source control | 18 | |`.rm_multiple(files []string)`| Remove `files` from Git source control | 19 | |`.rm_keep_local(file string)`| Remove a `file` from Git source control but keep the `file` locally | 20 | |`.rm_multiple_keep_local(files []string)`| Remove `files` from Git source control but keep the `files` locally | 21 | |`.diff()`| *Not yet implemented* | 22 | |`.log()`| *Not yet implemented* | 23 | |`.show()`| *Not yet implemented* | 24 | |`.status() ?StatusResult`| Gives status of repository | 25 | |`.branch(options string)`| Use branch command with `options` | 26 | |`.branch_delete(branch string)`| Delete a `branch` | 27 | |`.commit(message string)`| Commit a change with a `message` | 28 | |`.commit_with_files(message string, files []string)`| Commit changes to `files` with a `message` | 29 | |`.fetch()`| Update refs from remote repository | 30 | |`.fetch_from(remote string, branch string)`| Update refs from specific `remote` repository and `branch` | 31 | |`.pull()`| Pulls updates into local branch | 32 | |`.pull_from(remote string, branch string)`| Pulls updates from specific `remote` repository and `branch` into local branch | 33 | |`.pull_with_options(remote string, branch string, options string)` | Pulls updates from specific `remote` repository and `branch` into local branch with additional `options` | 34 | |`.push()`| Pushes local commits to remote repository | 35 | |`.push_to(remote string, branch string)`| Pushes local commits to specific `remote` repository and `branch` | 36 | |`.push_set_upstream(remote string, branch string)`| Pushes local branch to `remote` repository and `branch` | 37 | |`.push_with_options(remote string, branch string, options string)` | Pushes local commits to specific `remote` repository and `branch` with additional `options` | 38 | |`.remote_add(name string, repository string)`| Adds a new remote named `name` from a remote `repository` | 39 | |`.remote_add_with_options(name string, repository string, options string)` | Adds a new remote named `name` from a remote `repository` with additional `options` | 40 | |`.remote_remove(name string)`| Removes a named `name` remote | 41 | 42 |
43 | 44 | ### Types 45 | 46 | ``` 47 | struct StatusResult { 48 | pub mut: 49 | untracked []string 50 | ignored []string 51 | modified []string 52 | added []string 53 | deleted []string 54 | renamed []StatusRenamed 55 | conflicted []string 56 | 57 | staged []string 58 | 59 | ahead int 60 | behind int 61 | 62 | current string 63 | tracking string 64 | } 65 | ``` -------------------------------------------------------------------------------- /git.v: -------------------------------------------------------------------------------- 1 | module git 2 | 3 | import os 4 | 5 | fn prepend_(p string, a []string) []string { 6 | mut copy := a 7 | copy.prepend(p) 8 | return copy 9 | } 10 | fn concat_(a []string, b []string) []string { 11 | mut copy := a 12 | copy << b 13 | return copy 14 | } 15 | 16 | pub struct Git { 17 | mut: 18 | dir string 19 | bin string 20 | } 21 | 22 | pub fn create(dir string, bin string) Git { 23 | return Git { 24 | dir 25 | bin 26 | } 27 | } 28 | 29 | 30 | 31 | fn (g Git)execute(command []string) ?string { 32 | res := os.exec(prepend_(g.bin, command).join(' ')) or { 33 | return none 34 | } 35 | if res.exit_code != 0 { 36 | eprint(res.output) 37 | return none 38 | } 39 | return res.output 40 | } 41 | 42 | pub fn (mut g Git)cwd(dir string) { 43 | if os.is_dir(dir) { 44 | g.dir = dir 45 | } else { 46 | eprintln('$dir doesnt exists') 47 | } 48 | // TODO check if folder exists 49 | } 50 | 51 | //////// 52 | 53 | // Clone a repository into a new directory 54 | pub fn (g Git)clone(repository string) { 55 | g.execute(['clone', repository]) 56 | } 57 | pub fn (g Git)clone_to(repository string, dir string) { 58 | g.execute(['clone', repository, dir]) 59 | } 60 | pub fn (g Git)clone_with_options(repository string, dir string, options string) { 61 | g.execute(['clone', repository, dir, options]) 62 | } 63 | 64 | // Create an empty Git repository or reinitialize an existing one 65 | pub fn (g Git)init() { 66 | g.init_with_options('') 67 | } 68 | pub fn (g Git)init_bare() { 69 | g.init_with_options('--bare') 70 | } 71 | pub fn (g Git)init_with_options(options string) { 72 | g.execute(['init', options]) 73 | } 74 | 75 | //////// 76 | 77 | // Add file contents to the index 78 | pub fn (g Git)add(file string) { 79 | g.execute(['add', file]) 80 | } 81 | pub fn (g Git)add_multiple(files []string) { 82 | g.execute(prepend_('add', files)) 83 | } 84 | 85 | // Move or rename a file, a directory, or a symlink 86 | pub fn (g Git)mv(from string, to string) { 87 | g.execute(['mv', from, to]) 88 | } 89 | 90 | // Remove files from the working tree and from the index 91 | pub fn (g Git)rm(file string) { 92 | g.execute(['rm', file]) 93 | } 94 | pub fn (g Git)rm_multiple(files []string) { 95 | g.execute(prepend_('rm', files)) 96 | } 97 | 98 | pub fn (g Git)rm_keep_local(file string) { 99 | g.execute(['rm', '--cached', file]) 100 | } 101 | pub fn (g Git)rm_multiple_keep_local(files []string) { 102 | g.execute(concat_(['rm' '--cached'], files)) 103 | } 104 | 105 | //////// 106 | 107 | // Show changes between commits, commit and working tree, etc 108 | pub fn (g Git)diff() { 109 | 110 | } 111 | 112 | // Show commit logs 113 | pub fn (g Git)log() { 114 | 115 | } 116 | 117 | // Show various types of objects 118 | pub fn (g Git)show() { 119 | 120 | } 121 | 122 | struct StatusRenamed { 123 | from string 124 | to string 125 | } 126 | struct StatusResult { 127 | pub mut: 128 | untracked []string 129 | ignored []string 130 | modified []string 131 | added []string 132 | deleted []string 133 | renamed []StatusRenamed 134 | conflicted []string 135 | 136 | staged []string 137 | 138 | ahead int 139 | behind int 140 | 141 | current string 142 | tracking string 143 | } 144 | 145 | // Show the working tree status 146 | pub fn (g Git)status() ?StatusResult { 147 | output := g.execute(['status', '--porcelain', '-b', '-u']) or { 148 | return none 149 | } 150 | mut result := StatusResult{} 151 | lines := output.split_into_lines() 152 | for line_ in lines { 153 | line := line_.trim(' ') 154 | splitted := line.split(' ').filter(it != '') 155 | match splitted[0] { 156 | '##' { 157 | if splitted.index('...') != -1 { 158 | branch := splitted[1].split('...') 159 | result.current = branch[0] 160 | result.tracking = branch[1] 161 | if splitted.len >= 4 { 162 | shift := splitted[2].all_after('[') 163 | nb := splitted[3].int() 164 | if shift == 'behind' { 165 | result.behind = nb 166 | } else if shift == 'ahead' { 167 | result.ahead = nb 168 | } 169 | } 170 | } 171 | } 172 | '??' { 173 | result.untracked << splitted[1] 174 | } 175 | '!!' { 176 | result.ignored << splitted[1] 177 | } 178 | 'M', 'MM' { 179 | result.modified << splitted[1] 180 | if line_[0] == `M` { 181 | result.staged << splitted[1] 182 | } 183 | } 184 | 'A' { 185 | result.added << splitted[1] 186 | if line_[0] == `A` { 187 | result.staged << splitted[1] 188 | } 189 | } 190 | 'AM' { 191 | result.added << splitted[1] 192 | } 193 | 'D' { 194 | result.deleted << splitted[1] 195 | if line_[0] == `D` { 196 | result.staged << splitted[1] 197 | } 198 | } 199 | 'R' { 200 | result.renamed << StatusRenamed{splitted[2], splitted[4]} 201 | result.staged << splitted[4] 202 | } 203 | 'UU', 'AA', 'UD', 'DU', 'DD', 'AU', 'UA' { 204 | result.conflicted << splitted[1] 205 | } 206 | 207 | else {} 208 | } 209 | } 210 | return result 211 | } 212 | 213 | //////// 214 | 215 | // List, create, or delete branches 216 | pub fn (g Git)branch(options string) { 217 | g.execute(['branch', options]) 218 | // TODO List branches 219 | } 220 | pub fn (g Git)branch_delete(branch string) { 221 | g.execute(['branch', '-D', branch]) 222 | } 223 | 224 | // Record changes to the repository 225 | pub fn (g Git)commit(message string) { 226 | g.execute(['commit', '-m', '"$message"']) 227 | } 228 | pub fn (g Git)commit_with_files(message string, files []string) { 229 | g.execute(concat_(['commit', '-m', message], files)) 230 | } 231 | 232 | // Join two or more development histories together 233 | // pub fn (g Git)merge() { 234 | 235 | // } 236 | 237 | // Reapply commits on top of another base tip 238 | // pub fn (g Git)rebase() { 239 | 240 | // } 241 | 242 | // Reset current HEAD to the specified state 243 | // pub fn (g Git)reset() { 244 | 245 | // } 246 | 247 | //////// 248 | 249 | // Download objects and refs from another repository 250 | pub fn (g Git)fetch() { 251 | g.execute(['fetch']) 252 | } 253 | pub fn (g Git)fetch_from(remote string, branch string) { 254 | g.execute(['fetch', remote, branch]) 255 | } 256 | 257 | // Fetch from and integrate with another repository or a local branch 258 | pub fn (g Git)pull() { 259 | g.execute(['pull']) 260 | } 261 | pub fn (g Git)pull_from(remote string, branch string) { 262 | g.execute(['pull', remote, branch]) 263 | } 264 | pub fn (g Git)pull_with_options(remote string, branch string, options string) { 265 | g.execute(['pull', remote, branch, options]) 266 | } 267 | 268 | // Update remote refs along with associated objects 269 | pub fn (g Git)push() { 270 | g.execute(['push']) 271 | } 272 | pub fn (g Git)push_to(remote string, branch string) { 273 | g.execute(['push', remote, branch]) 274 | } 275 | pub fn (g Git)push_set_upstream(remote string, branch string) { 276 | g.execute(['push', '--set-upstream', remote, branch]) 277 | } 278 | pub fn (g Git)push_with_options(remote string, branch string, options string) { 279 | g.execute(['push', remote, branch, options]) 280 | } 281 | 282 | 283 | // Manage set of tracked repositories 284 | pub fn (g Git)remote_add(name string, repository string) { 285 | g.execute(['remote', 'add', name, repository]) 286 | } 287 | pub fn (g Git)remote_add_with_options(name string, repository string, options string) { 288 | g.execute(['remote', 'add', name, repository, options]) 289 | } 290 | 291 | pub fn (g Git)remote_remove(name string) { 292 | g.execute(['remote', 'remove', name]) 293 | } 294 | 295 | // TODO Others remote -------------------------------------------------------------------------------- /v.mod: -------------------------------------------------------------------------------- 1 | Module { 2 | name: 'git' 3 | description: 'V Git interface' 4 | version: '0.0.0' 5 | dependencies: [] 6 | } --------------------------------------------------------------------------------