197 lines · 3.6 KB · C
RawDownload
#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; intPfmt(Fmt *f){	int i, n; 	n = 0;	for(i = 0; i < npath; i++)		n += fmtprint(f, "%s/", path[i]);	return n;} voidshowdir(Hash dh, char *dname, char m){	Dirent *p, *e;	Object *d;  	path[npath++] = dname;	if((d = readobject(dh)) == nil)		sysfatal("bad dir entry %s %H", dname, 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--;} voidshow(Dirent *e, char m){	if(e->mode & DMDIR && !e->ismod)		showdir(e->h, e->name, m);	else		print("%c %P%s\n", m, e->name);} voiddifftrees(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 = entcmp(ap, bp);		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 && !ap->ismod)					sysfatal("bad hash %H", ap->h);				if((b = readobject(bp->h)) == nil && !bp->ismod)					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, '+');} voiddiffcommits(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);} voidusage(void){	fprint(2, "usage: %s [-pcr] query\n", argv0);	exits("usage");} voidmain(int argc, char **argv){	char *query, repo[512];	char *p, *e, *objpfx;	int i, j, n, nrel;	Hash *h; 	ARGBEGIN{	case 'd':	chattygit++;	break;	case 'p':	fullpath++;	break;	case 'c':	changes++;	break;	case 'r':	reverse ^= 1;	break;	default:	usage();	break;	}ARGEND; 	fmtinstall('P', Pfmt);	if(argc == 0)		usage();	gitinit(repo, sizeof(repo), &nrel);	if(chdir(repo) == -1)		sysfatal("chdir: %r");	if((objpfx = smprint("%s/.git/fs/object/", repo)) == nil)		sysfatal("smprint: %r");	for(i = 0, n = 0; i < argc; i++)		n += strlen(argv[i]) + 1;	query = emalloc(n+1);	p = query;	e = query + n;	for(i = 0; i < argc; i++)		p = seprint(p, e, "%s ", argv[i]);	n = resolverefs(&h, query);	free(query);	if(n == -1)		sysfatal("resolve: %r");	if(changes){		for(i = 1; i < n; i++)			diffcommits(h[0], h[i]);	}else{		p = (fullpath ? objpfx : "");		for(j = 0; j < n; j++)			print("%s%H\n", p, h[reverse ? n - 1 - j : j]);	}	exits(nil);}