review

review patchsets using your default editor
Log | Files | Refs

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 }