git.odin (1966B)
1 /* 2 Package git asks the repository questions through the git program, which is 3 the one reader of a repository worth trusting. Every answer is a string; 4 a failed ask is reported as not ok, with git's own words on stderr kept for 5 the caller that wants them. 6 */ 7 package git 8 9 import "core:strings" 10 import "jm:sh" 11 12 // run asks git, in root, and returns what it printed with trailing 13 // whitespace removed. 14 run :: proc( 15 root: string, 16 args: []string, 17 allocator := context.allocator, 18 ) -> ( 19 out: string, 20 ok: bool, 21 ) { 22 argv := make([]string, len(args) + 1, context.temp_allocator) 23 argv[0] = "git" 24 copy(argv[1:], args) 25 r := sh.exec(argv, {dir = root}, allocator) 26 if !r.ok { 27 return r.stderr, false 28 } 29 return strings.trim_right_space(r.stdout), true 30 } 31 32 // raw asks git and returns what it printed as it printed it, trailing 33 // newlines kept: a diff, a stat or a message rendered into a prompt has 34 // to be byte for byte what the Go tool renders. 35 raw :: proc( 36 root: string, 37 args: []string, 38 allocator := context.allocator, 39 ) -> ( 40 out: string, 41 ok: bool, 42 ) { 43 argv := make([]string, len(args) + 1, context.temp_allocator) 44 argv[0] = "git" 45 copy(argv[1:], args) 46 r := sh.exec(argv, {dir = root}, allocator) 47 if !r.ok { 48 return r.stderr, false 49 } 50 return r.stdout, true 51 } 52 53 // lines is run, split into lines, empty ones dropped. 54 lines :: proc( 55 root: string, 56 args: []string, 57 allocator := context.allocator, 58 ) -> ( 59 out: []string, 60 ok: bool, 61 ) { 62 text := run(root, args, context.temp_allocator) or_return 63 kept := make([dynamic]string, allocator) 64 for line in strings.split_lines(text, context.temp_allocator) { 65 trimmed := strings.trim_space(line) 66 if len(trimmed) > 0 { 67 append(&kept, strings.clone(trimmed, allocator)) 68 } 69 } 70 return kept[:], true 71 } 72 73 // toplevel is the repository a directory sits in. 74 toplevel :: proc(dir: string, allocator := context.allocator) -> (root: string, ok: bool) { 75 return run(dir, {"rev-parse", "--show-toplevel"}, allocator) 76 }