diff options
author | Ori Bernstein <ori@eigenstate.org> | 2021-05-16 18:49:45 -0700 |
---|---|---|
committer | Ori Bernstein <ori@eigenstate.org> | 2021-05-16 18:49:45 -0700 |
commit | 1ee1bfaa8c5644092e0c1ca3985ee74813bbfb1d (patch) | |
tree | 9be6163e8bcd0bd43b4016e2bfeb9571a548536e /sys/src/cmd/git/query.c | |
parent | 013b2cad191eef50fd4e69c38f1544c5083b640d (diff) |
git: got git?
Add a snapshot of git9 to 9front.
Diffstat (limited to 'sys/src/cmd/git/query.c')
-rw-r--r-- | sys/src/cmd/git/query.c | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/sys/src/cmd/git/query.c b/sys/src/cmd/git/query.c new file mode 100644 index 000000000..5f1330dad --- /dev/null +++ b/sys/src/cmd/git/query.c @@ -0,0 +1,196 @@ +#include <u.h> +#include <libc.h> + +#include "git.h" + +#pragma varargck type "P" void + +int fullpath; +int changes; +int reverse; +char *path[128]; +int npath; + +int +Pfmt(Fmt *f) +{ + int i, n; + + n = 0; + for(i = 0; i < npath; i++) + n += fmtprint(f, "%s/", path[i]); + return n; +} + +void +showdir(Hash dh, char *dname, char m) +{ + Dirent *p, *e; + Object *d; + + + path[npath++] = dname; + if((d = readobject(dh)) == nil) + sysfatal("bad hash %H", dh); + assert(d->type == GTree); + p = d->tree->ent; + e = p + d->tree->nent; + for(; p != e; p++){ + if(p->ismod) + continue; + if(p->mode & DMDIR) + showdir(p->h, p->name, m); + else + print("%c %P%s\n", m, p->name); + } + print("%c %P\n", m); + unref(d); + npath--; +} + +void +show(Dirent *e, char m) +{ + if(e->mode & DMDIR) + showdir(e->h, e->name, m); + else + print("%c %P%s\n", m, e->name); +} + +void +difftrees(Object *a, Object *b) +{ + Dirent *ap, *bp, *ae, *be; + int c; + + ap = ae = nil; + bp = be = nil; + if(a != nil){ + if(a->type != GTree) + return; + ap = a->tree->ent; + ae = ap + a->tree->nent; + } + if(b != nil){ + if(b->type != GTree) + return; + bp = b->tree->ent; + be = bp + b->tree->nent; + } + while(ap != ae && bp != be){ + c = strcmp(ap->name, bp->name); + if(c == 0){ + if(ap->mode == bp->mode && hasheq(&ap->h, &bp->h)) + goto next; + if(ap->mode != bp->mode) + print("! %P%s\n", ap->name); + else if(!(ap->mode & DMDIR) || !(bp->mode & DMDIR)) + print("@ %P%s\n", ap->name); + if((ap->mode & DMDIR) && (bp->mode & DMDIR)){ + if(npath >= nelem(path)) + sysfatal("path too deep"); + path[npath++] = ap->name; + if((a = readobject(ap->h)) == nil) + sysfatal("bad hash %H", ap->h); + if((b = readobject(bp->h)) == nil) + sysfatal("bad hash %H", bp->h); + difftrees(a, b); + unref(a); + unref(b); + npath--; + } +next: + ap++; + bp++; + }else if(c < 0) { + show(ap, '-'); + ap++; + }else if(c > 0){ + show(bp, '+'); + bp++; + } + } + for(; ap != ae; ap++) + show(ap, '-'); + for(; bp != be; bp++) + show(bp, '+'); +} + +void +diffcommits(Hash ah, Hash bh) +{ + Object *a, *b, *at, *bt; + + at = nil; + bt = nil; + if(!hasheq(&ah, &Zhash) && (a = readobject(ah)) != nil){ + if(a->type != GCommit) + sysfatal("not commit: %H", ah); + if((at = readobject(a->commit->tree)) == nil) + sysfatal("bad hash %H", a->commit->tree); + unref(a); + } + if(!hasheq(&bh, &Zhash) && (b = readobject(bh)) != nil){ + if(b->type != GCommit) + sysfatal("not commit: %H", ah); + if((bt = readobject(b->commit->tree)) == nil) + sysfatal("bad hash %H", b->commit->tree); + unref(b); + } + difftrees(at, bt); + unref(at); + unref(bt); +} + +void +usage(void) +{ + fprint(2, "usage: %s [-pcr] query\n", argv0); + exits("usage"); +} + +void +main(int argc, char **argv) +{ + int i, j, n; + Hash *h; + char *p, *e, *s; + char query[2048], repo[512]; + + ARGBEGIN{ + case 'p': fullpath++; break; + case 'c': changes++; break; + case 'r': reverse ^= 1; break; + default: usage(); break; + }ARGEND; + + gitinit(); + fmtinstall('P', Pfmt); + + if(argc == 0) + usage(); + if(findrepo(repo, sizeof(repo)) == -1) + sysfatal("find root: %r"); + if(chdir(repo) == -1) + sysfatal("chdir: %r"); + s = ""; + p = query; + e = query + nelem(query); + for(i = 0; i < argc; i++){ + p = seprint(p, e, "%s%s", s, argv[i]); + s = " "; + } + if((n = resolverefs(&h, query)) == -1) + sysfatal("resolve: %r"); + if(changes){ + if(n != 2) + sysfatal("diff: need 2 commits, got %d", n); + diffcommits(h[0], h[1]); + }else{ + p = (fullpath ? "/mnt/git/object/" : ""); + for(j = 0; j < n; j++) + print("%s%H\n", p, h[reverse ? n - 1 - j : j]); + } + exits(nil); +} + |