summaryrefslogtreecommitdiff
path: root/sys/src/cmd/git/query.c
diff options
context:
space:
mode:
authorOri Bernstein <ori@eigenstate.org>2021-05-16 18:49:45 -0700
committerOri Bernstein <ori@eigenstate.org>2021-05-16 18:49:45 -0700
commit1ee1bfaa8c5644092e0c1ca3985ee74813bbfb1d (patch)
tree9be6163e8bcd0bd43b4016e2bfeb9571a548536e /sys/src/cmd/git/query.c
parent013b2cad191eef50fd4e69c38f1544c5083b640d (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.c196
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);
+}
+