ref: 83fe095033418ea6b95204c41e22d96ec133243f
parent: 837c596bdf90e7a723864b65a3bac84155ee66f6
author: Ori Bernstein <ori@eigenstate.org>
date: Sat Dec 14 12:11:01 EST 2024
git/get: support side-band and multi-ack
--- a/sys/src/cmd/git/get.c
+++ b/sys/src/cmd/git/get.c
@@ -166,16 +166,59 @@
}
}
+void
+fmtcaps(Conn *c, char *caps, int ncaps)
+{
+ char *p, *e;
+
+ p = caps;
+ e = caps + ncaps;
+ *p = 0;
+ if(c->multiack)
+ p = seprint(p, e, " multi_ack");
+ if(c->sideband64k)
+ p = seprint(p, e, " side-band-64k");
+ else if(c->sideband)
+ p = seprint(p, e, " side-band");
+ assert(p != e);
+}
+
int
+sbread(Conn *c, char *buf, int nbuf, char **pbuf)
+{
+ int n;
+
+ assert(nbuf >= Pktmax);
+ if(!c->sideband && !c->sideband64k){
+ *pbuf = buf;
+ return readn(c->rfd, buf, nbuf);
+ }else{
+ *pbuf = buf+1;
+ while(1){
+ n = readpkt(c, buf, nbuf);
+ if(n <= 0)
+ return n;
+ else if(buf[0] == 1 && n > 1)
+ return n - 1;
+ else if(buf[0] == 3)
+ fprint(2, "error: %s\n", buf+1);
+ else if(buf[0] < 1 || buf[0] > 3)
+ fprint(2, "unknown sideband(%c:%d) data: %s\n", buf[0], buf[0], buf+1);
+
+ }
+ }
+}
+
+int
fetchpack(Conn *c)
{
- char buf[Pktmax], *sp[3], *ep;
- char *packtmp, *idxtmp, **ref, *caps;
+ char spinner[] = {'|', '/', '-', '\\'};
+ char buf[Pktmax], caps[512], *sp[3], *ep;
+ char *packtmp, *idxtmp, **ref, *rp;
Hash h, *have, *want;
int nref, refsz, first, nsent;
- int i, l, n, req, pfd;
+ int i, j, l, n, spin, req, pfd;
vlong packsz;
- Capset cs;
Objset hadobj;
Object *o;
Objq haveq;
@@ -195,9 +238,9 @@
break;
if(first && n > strlen(buf)){
- parsecaps(buf + strlen(buf) + 1, &cs);
- if(cs.symfrom[0] != 0)
- print("symref %s %s\n", cs.symfrom, cs.symto);
+ parsecaps(buf + strlen(buf) + 1, c);
+ if(c->symfrom[0] != 0)
+ print("symref %s %s\n", c->symfrom, c->symto);
}
first = 0;
@@ -227,10 +270,13 @@
if(writephase(c) == -1)
sysfatal("write: %r");
req = 0;
- caps = " multi_ack";
+ fmtcaps(c, caps, sizeof(caps));
for(i = 0; i < nref; i++){
if(hasheq(&have[i], &want[i]))
continue;
+ for(j = 0; j < i; j++)
+ if(hasheq(&want[i], &want[j]))
+ goto Next;
if((o = readobject(want[i])) != nil){
unref(o);
continue;
@@ -237,8 +283,9 @@
}
if(fmtpkt(c, "want %H%s\n", want[i], caps) == -1)
sysfatal("could not send want for %H", want[i]);
- caps = "";
+ caps[0] = 0;
req = 1;
+Next: continue;
}
flushpkt(c);
@@ -261,6 +308,7 @@
enqueueparent(&haveq, o);
osadd(&hadobj, o);
unref(o);
+ nsent++;
}
/*
* While we could short circuit this and check if upstream has
@@ -274,7 +322,7 @@
if(oshas(&hadobj, e.o->hash))
continue;
if((o = readobject(e.o->hash)) == nil)
- sysfatal("missing object we should have: %H", have[i]);
+ sysfatal("missing object we should have: %H", e.o->hash);
if(fmtpkt(c, "have %H", o->hash) == -1)
sysfatal("write: %r");
enqueueparent(&haveq, o);
@@ -292,9 +340,6 @@
goto showrefs;
if(readphase(c) == -1)
sysfatal("read: %r");
- if((n = readpkt(c, buf, sizeof(buf))) == -1)
- sysfatal("read: %r");
- buf[n] = 0;
if((packtmp = smprint(".git/objects/pack/fetch.%d.pack", getpid())) == nil)
sysfatal("smprint: %r");
@@ -305,38 +350,56 @@
if((pfd = create(packtmp, ORDWR, 0664)) == -1)
sysfatal("could not create %s: %r", packtmp);
- fprint(2, "fetching...\n");
- /*
- * Work around torvalds git bug: we get duplicate have lines
- * somtimes, even though the protocol is supposed to start the
- * pack file immediately.
- *
- * Skip ahead until we read 'PACK' off the wire
- */
- while(1){
- if(readn(c->rfd, buf, 4) != 4)
- sysfatal("fetch packfile: short read");
- buf[4] = 0;
- if(strncmp(buf, "PACK", 4) == 0)
- break;
- l = strtol(buf, &ep, 16);
- if(ep != buf + 4)
- sysfatal("fetch packfile: junk pktline");
- if(readn(c->rfd, buf, l-4) != l-4)
- sysfatal("fetch packfile: short read");
+ fprint(2, "fetching... ");
+ packsz = 0;
+ if(c->multiack){
+ for(i = 0; i < nsent; i++){
+ if(readpkt(c, buf, sizeof(buf)) == -1)
+ sysfatal("read: %r");
+ if(strncmp(buf, "NAK\n", 4) == 0)
+ break;
+ if(strncmp(buf, "ACK ", 4) != 0)
+ sysfatal("bad response: '%s'", buf);
+ }
+ }
+ if(readpkt(c, buf, sizeof(buf)) == -1)
+ sysfatal("read: %r");
+ if(!c->sideband && !c->sideband64k && !c->multiack){
+ /*
+ * Work around torvalds git bug: we get duplicate have lines
+ * somtimes, even though the protocol is supposed to start the
+ * pack file immediately.
+ *
+ * Skip ahead until we read 'PACK' off the wire
+ */
+ while(1){
+ if(readn(c->rfd, buf, 4) != 4)
+ sysfatal("fetch packfile: short read");
+ if(strncmp(buf, "PACK", 4) == 0)
+ break;
+ buf[4] = 0;
+ l = strtol(buf, &ep, 16);
+ if(ep != buf + 4)
+ sysfatal("fetch packfile: junk pktline");
+ if(readn(c->rfd, buf, l-4) != l-4)
+ sysfatal("fetch packfile: short read");
+ }
+ if(write(pfd, "PACK", 4) != 4)
+ sysfatal("write pack header: %r");
+ packsz = 4;
}
- if(write(pfd, "PACK", 4) != 4)
- sysfatal("write pack header: %r");
- packsz = 4;
+ spin = 0;
while(1){
- n = read(c->rfd, buf, sizeof buf);
+ n = sbread(c, buf, sizeof buf, &rp);
if(n == 0)
break;
- if(n == -1 || write(pfd, buf, n) != n)
+ if(n == -1 || write(pfd, rp, n) != n)
sysfatal("fetch packfile: %r");
+ if(interactive && spin++ % 100 == 0)
+ fprint(2, "\b%c", spinner[spin/100 % nelem(spinner)]);
packsz += n;
}
-
+ fprint(2, "\n");
closeconn(c);
if(seek(pfd, 0, 0) == -1)
fail(packtmp, idxtmp, "packfile seek: %r");
--- a/sys/src/cmd/git/git.h
+++ b/sys/src/cmd/git/git.h
@@ -4,7 +4,6 @@
#include <flate.h>
#include <regexp.h>
-typedef struct Capset Capset;
typedef struct Conn Conn;
typedef struct Hash Hash;
typedef struct Delta Delta;
@@ -82,19 +81,19 @@
uchar h[20];
};
-struct Capset {
- char symfrom[256];
- char symto[256];
- int sideband;
- int sideband64k;
- int report;
-};
-
struct Conn {
int type;
int rfd;
int wfd;
+ /* capabilities */
+ char symfrom[256];
+ char symto[256];
+ char multiack;
+ char sideband;
+ char sideband64k;
+ char report;
+
/* only used by http */
int cfd;
char *url; /* note, first GET uses a different url */
@@ -338,7 +337,7 @@
int readphase(Conn *);
int writephase(Conn *);
void closeconn(Conn *);
-void parsecaps(char *, Capset *);
+void parsecaps(char *, Conn *);
/* queues */
void qinit(Objq*);
--- a/sys/src/cmd/git/proto.c
+++ b/sys/src/cmd/git/proto.c
@@ -27,27 +27,28 @@
}
void
-parsecaps(char *caps, Capset *cs)
+parsecaps(char *caps, Conn *c)
{
- char *p, *n, *c, *t;
+ char *p, *n, *s, *t;
- memset(cs, 0, sizeof(*cs));
for(p = caps; p != nil; p = n){
n = strchr(p, ' ');
if(n != nil)
*n++ = 0;
if(matchcap(p, "report-status", 1) != nil)
- cs->report = 1;
+ c->report = 1;
+ if(matchcap(p, "multi_ack", 1) != nil)
+ c->multiack = 1;
else if(matchcap(p, "side-band", 1) != nil)
- cs->sideband = 1;
+ c->sideband = 1;
else if(matchcap(p, "side-band-64k", 1) != nil)
- cs->sideband64k = 1;
- else if((c = matchcap(p, "symref=", 0)) != nil){
- if((t = strchr(c, ':')) == nil)
+ c->sideband64k = 1;
+ else if((s = matchcap(p, "symref=", 0)) != nil){
+ if((t = strchr(s, ':')) == nil)
continue;
*t++ = '\0';
- snprint(cs->symfrom, sizeof(cs->symfrom), c);
- snprint(cs->symto, sizeof(cs->symto), t);
+ snprint(c->symfrom, sizeof(c->symfrom), s);
+ snprint(c->symto, sizeof(c->symto), t);
}
}
}
@@ -108,7 +109,7 @@
sysfatal("pktline: bad length '%s'", len);
n -= 4;
if(n >= nbuf)
- sysfatal("pktline: undersize buffer");
+ abort();//sysfatal("pktline: undersize buffer");
if(readn(c->rfd, buf, n) != n)
return -1;
if(n > 4 && strncmp(buf, "ERR ", 4) == 0){
@@ -468,7 +469,6 @@
localrepo(char *uri, char *path, int npath)
{
int fd;
-
snprint(path, npath, "%s/.git/../", uri);
fd = open(path, OREAD);
if(fd < 0)
--- a/sys/src/cmd/git/send.c
+++ b/sys/src/cmd/git/send.c
@@ -91,11 +91,9 @@
Hash h, *theirs, *ours;
Object *a, *b, *p, *o;
char **refs;
- Capset cs;
Map *map, *m;
first = 1;
- memset(&cs, 0, sizeof(Capset));
nours = readours(&ours, &refs);
theirs = nil;
ntheirs = 0;
@@ -113,7 +111,7 @@
if(n == 0)
break;
if(first && n > strlen(buf))
- parsecaps(buf + strlen(buf) + 1, &cs);
+ parsecaps(buf + strlen(buf) + 1, c);
first = 0;
if(getfields(buf, sp, nelem(sp), 1, " \t\r\n") != 2)
@@ -179,7 +177,7 @@
* Github doesn't advertise any capabilities, so we can't check
* for compatibility. We just need to add it blindly.
*/
- if(i == 0 && cs.report){
+ if(i == 0 && c->report){
buf[n++] = '\0';
n += snprint(buf + n, sizeof(buf) - n, " report-status");
}
@@ -195,7 +193,7 @@
if(writepack(c->wfd, ours, nours, theirs, ntheirs, &h) == -1)
return -1;
- if(!cs.report)
+ if(!c->report)
return 0;
if(readphase(c) == -1)
--
⑨