|
| 1 | +module git |
| 2 | + |
| 3 | +import time |
| 4 | + |
| 5 | +//#include "stdint.h" |
| 6 | + |
| 7 | +#flag darwin -I/opt/homebrew/include |
| 8 | +#flag darwin -L/opt/homebrew/lib |
| 9 | + |
| 10 | +#flag darwin -lgit2 |
| 11 | + |
| 12 | +#include "git2/types.h" |
| 13 | +#include "git2/common.h" |
| 14 | +#include "git2/global.h" |
| 15 | +#include "git2/repository.h" |
| 16 | + |
| 17 | +#include "git2.h" |
| 18 | + |
| 19 | +fn C.git_libgit2_init() |
| 20 | +fn C.git_libgit2_shutdown() |
| 21 | +fn C.git_repository_init(repo voidptr, path &char, is_bare bool) int |
| 22 | +fn C.git_repository_open(repo voidptr, path &char) int |
| 23 | + |
| 24 | +fn C.git_libgit2_features() |
| 25 | +fn C.git_commit_lookup(voidptr, voidptr, &C.git_oid) int |
| 26 | + |
| 27 | +struct C.git_repository {} |
| 28 | + |
| 29 | +struct C.git_commit {} |
| 30 | + |
| 31 | +struct C.git_signature { |
| 32 | + name &char |
| 33 | + email &char |
| 34 | +} |
| 35 | + |
| 36 | +struct C.git_oid {} |
| 37 | + |
| 38 | +struct C.git_reference {} |
| 39 | + |
| 40 | +struct C.git_revwalk {} |
| 41 | + |
| 42 | +struct C.git_object {} |
| 43 | + |
| 44 | +struct C.git_error { |
| 45 | + message &char |
| 46 | +} |
| 47 | + |
| 48 | +fn C.git_commit_message(voidptr) &char |
| 49 | +fn C.git_reference_lookup(&&C.git_reference, &C.git_repository, &char) |
| 50 | +fn C.git_reference_symbolic_target(&C.git_reference) &char |
| 51 | +fn C.git_revwalk_next(&C.git_oid, &C.git_revwalk) int |
| 52 | +fn C.git_revwalk_new(&&C.git_revwalk, &C.git_repository) int |
| 53 | +fn C.git_revwalk_push(&C.git_revwalk, &C.git_oid) int |
| 54 | +fn C.git_reference_name_to_id(&C.git_oid, &C.git_repository, &char) |
| 55 | +fn C.git_oid_tostr_s(&C.git_oid) &char |
| 56 | +fn C.git_commit_author(&C.git_commit) &C.git_signature |
| 57 | +fn C.git_branch_lookup(&&C.git_reference, &C.git_repository, &char, int) int |
| 58 | +fn C.git_error_last() &C.git_error |
| 59 | +fn C.git_reference_peel(&&C.git_object, &C.git_reference, int) int |
| 60 | + |
| 61 | +// fn C.git_commit_tree(&&C.git_tree, &C.git_commit) |
| 62 | +fn C.git_commit_tree(voidptr, &C.git_commit) |
| 63 | +fn C.git_tree_entrycount(&C.git_tree) int |
| 64 | +fn C.git_tree_entry_byindex(&C.git_tree, int) &C.git_tree_entry |
| 65 | +fn C.git_tree_entry_name(&C.git_tree_entry) &char |
| 66 | +fn C.git_blob_lookup(&&C.git_blob, &C.git_repository, &C.git_oid) int |
| 67 | +fn C.git_tree_entry_id(&C.git_tree_entry) &C.git_oid |
| 68 | +fn C.git_blob_rawcontent(&C.git_blob) voidptr |
| 69 | +fn C.git_blob_rawsize(&C.git_blob) int |
| 70 | +fn C.git_blob_free(&C.git_blob) |
| 71 | + |
| 72 | +fn init() { |
| 73 | + C.git_libgit2_init() |
| 74 | +} |
| 75 | + |
| 76 | +fn shutdown() { |
| 77 | + C.git_libgit2_shutdown() |
| 78 | +} |
| 79 | + |
| 80 | +pub struct Repo { |
| 81 | + obj &C.git_repository |
| 82 | + |
| 83 | + path string |
| 84 | +} |
| 85 | + |
| 86 | +fn (r Repo) str() string { |
| 87 | + return 'Repo{ path:${r.path} }' |
| 88 | +} |
| 89 | + |
| 90 | +[params] |
| 91 | +struct LogParams { |
| 92 | + n int |
| 93 | + dir string // -C "dir" |
| 94 | + branch string |
| 95 | +} |
| 96 | + |
| 97 | +struct Commit { |
| 98 | +mut: |
| 99 | + msg string |
| 100 | + hash string |
| 101 | + author_name string |
| 102 | + author_email string |
| 103 | +} |
| 104 | + |
| 105 | +fn (r Repo) log(p LogParams) []Commit { |
| 106 | + oid := C.git_oid{} |
| 107 | + C.git_reference_name_to_id(&oid, r.obj, c'HEAD') |
| 108 | + commit := &C.git_commit(unsafe { nil }) |
| 109 | + walker := &C.git_revwalk(unsafe { nil }) |
| 110 | + if C.git_revwalk_new(&walker, r.obj) != 0 { |
| 111 | + println('failed to create walker') |
| 112 | + return [] |
| 113 | + } |
| 114 | + C.git_revwalk_push(walker, &oid) |
| 115 | + mut commits := []Commit{cap: 10} |
| 116 | + mut i := 0 |
| 117 | + mut cur_oid := C.git_oid{} |
| 118 | + for C.git_revwalk_next(&cur_oid, walker) == 0 { |
| 119 | + mut gitly_commit := Commit{} |
| 120 | + // println('RET =${ret0}') |
| 121 | + // println(C.GIT_ITEROVER) |
| 122 | + C.git_commit_lookup(&commit, r.obj, &cur_oid) |
| 123 | + // Get commit message |
| 124 | + msg := C.git_commit_message(commit) |
| 125 | + // Get commit id (hash) |
| 126 | + commit_id := C.git_oid_tostr_s(&cur_oid) |
| 127 | + // Get commit author |
| 128 | + author := C.git_commit_author(commit) |
| 129 | + unsafe { |
| 130 | + if msg == nil || commit_id == nil || author == nil || author.name == nil { |
| 131 | + println('nil log, skipping') |
| 132 | + continue |
| 133 | + } |
| 134 | + } |
| 135 | + gitly_commit.msg = unsafe { cstring_to_vstring(msg) } |
| 136 | + gitly_commit.hash = unsafe { cstring_to_vstring(commit_id) } |
| 137 | + gitly_commit.author_name = unsafe { cstring_to_vstring(author.name) } |
| 138 | + gitly_commit.author_email = unsafe { cstring_to_vstring(author.email) } |
| 139 | + println(gitly_commit) |
| 140 | + commits << gitly_commit |
| 141 | + |
| 142 | + i++ |
| 143 | + if p.n > 0 && i >= p.n { |
| 144 | + // Reached the limit `n` (like `git log -n10`) |
| 145 | + break |
| 146 | + } |
| 147 | + } |
| 148 | + return commits |
| 149 | +} |
| 150 | + |
| 151 | +fn new_repo(path string) Repo { |
| 152 | + repo_obj := &C.git_repository(unsafe { nil }) |
| 153 | + // ret := C.git_repository_init(&repo_obj, path.str, false) |
| 154 | + ret := C.git_repository_open(&repo_obj, path.str) |
| 155 | + println('ff ${ret}') |
| 156 | + // git_reference_free(head_ref); |
| 157 | + return Repo{ |
| 158 | + obj: repo_obj |
| 159 | + path: path |
| 160 | + } |
| 161 | +} |
| 162 | + |
| 163 | +fn (r &Repo) current_branch() string { |
| 164 | + head_ref := &C.git_reference(unsafe { nil }) |
| 165 | + C.git_reference_lookup(&head_ref, r.obj, c'HEAD') |
| 166 | + symbolic_ref := C.git_reference_symbolic_target(head_ref) |
| 167 | + branch := unsafe { cstring_to_vstring(symbolic_ref) } |
| 168 | + return branch.after('refs/heads/') |
| 169 | +} |
| 170 | + |
| 171 | +pub fn (r &Repo) show_file_blob(branch string, file_path string) !string { |
| 172 | + mut blob := &C.git_blob(unsafe { nil }) |
| 173 | + mut branch_ref := &C.git_reference(unsafe { nil }) |
| 174 | + if C.git_branch_lookup(&branch_ref, r.obj, branch.str, C.GIT_BRANCH_LOCAL) != 0 { |
| 175 | + C.printf(c'Failed to lookup branch: %s\n', C.git_error_last().message) |
| 176 | + return error('sdf') |
| 177 | + } |
| 178 | + |
| 179 | + mut treeish := &C.git_object(unsafe { nil }) |
| 180 | + if C.git_reference_peel(&treeish, branch_ref, C.GIT_OBJECT_COMMIT) != 0 { |
| 181 | + C.printf(c'Failed to peel reference to commit: %s\n', C.git_error_last().message) |
| 182 | + return error('sdf') |
| 183 | + } |
| 184 | + |
| 185 | + commit := &C.git_commit(treeish) |
| 186 | + C.git_commit_tree(&treeish, commit) |
| 187 | + if commit == unsafe { nil } { |
| 188 | + C.printf(c'Failed to get commit tree\n') |
| 189 | + return error('sdf') |
| 190 | + } |
| 191 | + |
| 192 | + tree := unsafe { &C.git_tree(treeish) } |
| 193 | + |
| 194 | + // Iterate through the tree entries to find the file |
| 195 | + entry_count := C.git_tree_entrycount(tree) |
| 196 | + // println('number of entires ${entry_count}') |
| 197 | + for i := 0; i < entry_count; i++ { |
| 198 | + entry := C.git_tree_entry_byindex(tree, i) |
| 199 | + entry_name := C.git_tree_entry_name(entry) |
| 200 | + C.printf(c'%s\n', entry_name) |
| 201 | + |
| 202 | + if unsafe { C.strcmp(entry_name, file_path.str) } == 0 { |
| 203 | + // Found the file |
| 204 | + if C.git_blob_lookup(&blob, r.obj, C.git_tree_entry_id(entry)) != 0 { |
| 205 | + C.printf(c'Failed to lookup blob: %s\n', C.git_error_last().message) |
| 206 | + return error('sdf') |
| 207 | + } |
| 208 | + |
| 209 | + content := C.git_blob_rawcontent(blob) |
| 210 | + size := C.git_blob_rawsize(blob) |
| 211 | + |
| 212 | + C.printf(c'Content of %s (from branch %s):\n', file_path.str, branch.str) |
| 213 | + // C.fwrite(content, 1, size, C.stdout) |
| 214 | + |
| 215 | + text := unsafe { cstring_to_vstring(content) } |
| 216 | + C.git_blob_free(blob) |
| 217 | + return text |
| 218 | + } |
| 219 | + } |
| 220 | + return '' |
| 221 | +} |
| 222 | + |
| 223 | +/* |
| 224 | +fn main() { |
| 225 | + t0 := time.now() |
| 226 | + r := new_repo('/Users/alex/code/gitly/repos/admin/vlang2') |
| 227 | + /* |
| 228 | + println(time.since(t0)) |
| 229 | + println('1current branch=') |
| 230 | + b := r.current_branch() |
| 231 | + println(b) |
| 232 | + t := time.now() |
| 233 | + r.log(n: 10) |
| 234 | + println(time.since(t)) |
| 235 | + */ |
| 236 | + println('GIT SHOW') |
| 237 | +
|
| 238 | + t := time.now() |
| 239 | + println(r.show_file_blob('master', 'README.md')!) |
| 240 | + println(time.since(t)) |
| 241 | + C.git_libgit2_features() |
| 242 | + println(r) |
| 243 | +} |
| 244 | +*/ |
0 commit comments