Created fast-import, a tool to quickly generating a pack from blobs.
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
This commit is contained in:
parent
a8e0d16d85
commit
db5e523fdd
1
.gitignore
vendored
1
.gitignore
vendored
@ -32,6 +32,7 @@ git-diff-index
|
|||||||
git-diff-stages
|
git-diff-stages
|
||||||
git-diff-tree
|
git-diff-tree
|
||||||
git-describe
|
git-describe
|
||||||
|
git-fast-import
|
||||||
git-fetch
|
git-fetch
|
||||||
git-fetch-pack
|
git-fetch-pack
|
||||||
git-findtags
|
git-findtags
|
||||||
|
1
Makefile
1
Makefile
@ -186,6 +186,7 @@ SIMPLE_PROGRAMS = \
|
|||||||
PROGRAMS = \
|
PROGRAMS = \
|
||||||
git-convert-objects$X git-fetch-pack$X git-fsck-objects$X \
|
git-convert-objects$X git-fetch-pack$X git-fsck-objects$X \
|
||||||
git-hash-object$X git-index-pack$X git-local-fetch$X \
|
git-hash-object$X git-index-pack$X git-local-fetch$X \
|
||||||
|
git-fast-import$X \
|
||||||
git-merge-base$X \
|
git-merge-base$X \
|
||||||
git-merge-index$X git-mktag$X git-mktree$X git-patch-id$X \
|
git-merge-index$X git-mktag$X git-mktree$X git-patch-id$X \
|
||||||
git-peek-remote$X git-receive-pack$X \
|
git-peek-remote$X git-receive-pack$X \
|
||||||
|
214
fast-import.c
Normal file
214
fast-import.c
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
#include "builtin.h"
|
||||||
|
#include "cache.h"
|
||||||
|
#include "object.h"
|
||||||
|
#include "blob.h"
|
||||||
|
#include "delta.h"
|
||||||
|
#include "pack.h"
|
||||||
|
#include "csum-file.h"
|
||||||
|
|
||||||
|
static int max_depth = 10;
|
||||||
|
static unsigned long object_count;
|
||||||
|
static int packfd;
|
||||||
|
static int current_depth;
|
||||||
|
static void *lastdat;
|
||||||
|
static unsigned long lastdatlen;
|
||||||
|
static unsigned char lastsha1[20];
|
||||||
|
|
||||||
|
static ssize_t yread(int fd, void *buffer, size_t length)
|
||||||
|
{
|
||||||
|
ssize_t ret = 0;
|
||||||
|
while (ret < length) {
|
||||||
|
ssize_t size = xread(fd, (char *) buffer + ret, length - ret);
|
||||||
|
if (size < 0) {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
if (size == 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret += size;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t ywrite(int fd, void *buffer, size_t length)
|
||||||
|
{
|
||||||
|
ssize_t ret = 0;
|
||||||
|
while (ret < length) {
|
||||||
|
ssize_t size = xwrite(fd, (char *) buffer + ret, length - ret);
|
||||||
|
if (size < 0) {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
if (size == 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret += size;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned long encode_header(enum object_type type, unsigned long size, unsigned char *hdr)
|
||||||
|
{
|
||||||
|
int n = 1;
|
||||||
|
unsigned char c;
|
||||||
|
|
||||||
|
if (type < OBJ_COMMIT || type > OBJ_DELTA)
|
||||||
|
die("bad type %d", type);
|
||||||
|
|
||||||
|
c = (type << 4) | (size & 15);
|
||||||
|
size >>= 4;
|
||||||
|
while (size) {
|
||||||
|
*hdr++ = c | 0x80;
|
||||||
|
c = size & 0x7f;
|
||||||
|
size >>= 7;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
*hdr = c;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_blob (void *dat, unsigned long datlen)
|
||||||
|
{
|
||||||
|
z_stream s;
|
||||||
|
void *out, *delta;
|
||||||
|
unsigned char hdr[64];
|
||||||
|
unsigned long hdrlen, deltalen;
|
||||||
|
|
||||||
|
if (lastdat && current_depth < max_depth) {
|
||||||
|
delta = diff_delta(lastdat, lastdatlen,
|
||||||
|
dat, datlen,
|
||||||
|
&deltalen, 0);
|
||||||
|
} else
|
||||||
|
delta = 0;
|
||||||
|
|
||||||
|
memset(&s, 0, sizeof(s));
|
||||||
|
deflateInit(&s, zlib_compression_level);
|
||||||
|
|
||||||
|
if (delta) {
|
||||||
|
current_depth++;
|
||||||
|
s.next_in = delta;
|
||||||
|
s.avail_in = deltalen;
|
||||||
|
hdrlen = encode_header(OBJ_DELTA, deltalen, hdr);
|
||||||
|
if (ywrite(packfd, hdr, hdrlen) != hdrlen)
|
||||||
|
die("Can't write object header: %s", strerror(errno));
|
||||||
|
if (ywrite(packfd, lastsha1, sizeof(lastsha1)) != sizeof(lastsha1))
|
||||||
|
die("Can't write object base: %s", strerror(errno));
|
||||||
|
} else {
|
||||||
|
current_depth = 0;
|
||||||
|
s.next_in = dat;
|
||||||
|
s.avail_in = datlen;
|
||||||
|
hdrlen = encode_header(OBJ_BLOB, datlen, hdr);
|
||||||
|
if (ywrite(packfd, hdr, hdrlen) != hdrlen)
|
||||||
|
die("Can't write object header: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
s.avail_out = deflateBound(&s, s.avail_in);
|
||||||
|
s.next_out = out = xmalloc(s.avail_out);
|
||||||
|
while (deflate(&s, Z_FINISH) == Z_OK)
|
||||||
|
/* nothing */;
|
||||||
|
deflateEnd(&s);
|
||||||
|
|
||||||
|
if (ywrite(packfd, out, s.total_out) != s.total_out)
|
||||||
|
die("Failed writing compressed data %s", strerror(errno));
|
||||||
|
|
||||||
|
free(out);
|
||||||
|
if (delta)
|
||||||
|
free(delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_pack_header ()
|
||||||
|
{
|
||||||
|
const char* magic = "PACK";
|
||||||
|
unsigned long version = 2;
|
||||||
|
unsigned long zero = 0;
|
||||||
|
|
||||||
|
version = htonl(version);
|
||||||
|
|
||||||
|
if (ywrite(packfd, (char*)magic, 4) != 4)
|
||||||
|
die("Can't write pack magic: %s", strerror(errno));
|
||||||
|
if (ywrite(packfd, &version, 4) != 4)
|
||||||
|
die("Can't write pack version: %s", strerror(errno));
|
||||||
|
if (ywrite(packfd, &zero, 4) != 4)
|
||||||
|
die("Can't write 0 object count: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fixup_header_footer ()
|
||||||
|
{
|
||||||
|
SHA_CTX c;
|
||||||
|
char hdr[8];
|
||||||
|
unsigned char sha1[20];
|
||||||
|
unsigned long cnt;
|
||||||
|
char *buf;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
if (lseek(packfd, 0, SEEK_SET) != 0)
|
||||||
|
die("Failed seeking to start: %s", strerror(errno));
|
||||||
|
|
||||||
|
SHA1_Init(&c);
|
||||||
|
if (yread(packfd, hdr, 8) != 8)
|
||||||
|
die("Failed reading header: %s", strerror(errno));
|
||||||
|
SHA1_Update(&c, hdr, 8);
|
||||||
|
|
||||||
|
fprintf(stderr, "%lu objects\n", object_count);
|
||||||
|
cnt = htonl(object_count);
|
||||||
|
SHA1_Update(&c, &cnt, 4);
|
||||||
|
if (ywrite(packfd, &cnt, 4) != 4)
|
||||||
|
die("Failed writing object count: %s", strerror(errno));
|
||||||
|
|
||||||
|
buf = xmalloc(128 * 1024);
|
||||||
|
for (;;) {
|
||||||
|
n = xread(packfd, buf, 128 * 1024);
|
||||||
|
if (n <= 0)
|
||||||
|
break;
|
||||||
|
SHA1_Update(&c, buf, n);
|
||||||
|
}
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
SHA1_Final(sha1, &c);
|
||||||
|
if (ywrite(packfd, sha1, sizeof(sha1)) != sizeof(sha1))
|
||||||
|
die("Failed writing pack checksum: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int argc, const char **argv)
|
||||||
|
{
|
||||||
|
packfd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666);
|
||||||
|
if (packfd < 0)
|
||||||
|
die("Can't create pack file %s: %s", argv[1], strerror(errno));
|
||||||
|
|
||||||
|
init_pack_header();
|
||||||
|
for (;;) {
|
||||||
|
unsigned long datlen;
|
||||||
|
int hdrlen;
|
||||||
|
void *dat;
|
||||||
|
char hdr[128];
|
||||||
|
unsigned char sha1[20];
|
||||||
|
SHA_CTX c;
|
||||||
|
|
||||||
|
if (yread(0, &datlen, 4) != 4)
|
||||||
|
break;
|
||||||
|
|
||||||
|
dat = xmalloc(datlen);
|
||||||
|
if (yread(0, dat, datlen) != datlen)
|
||||||
|
break;
|
||||||
|
|
||||||
|
hdrlen = sprintf(hdr, "blob %lu", datlen) + 1;
|
||||||
|
SHA1_Init(&c);
|
||||||
|
SHA1_Update(&c, hdr, hdrlen);
|
||||||
|
SHA1_Update(&c, dat, datlen);
|
||||||
|
SHA1_Final(sha1, &c);
|
||||||
|
|
||||||
|
write_blob(dat, datlen);
|
||||||
|
object_count++;
|
||||||
|
printf("%s\n", sha1_to_hex(sha1));
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
if (lastdat)
|
||||||
|
free(lastdat);
|
||||||
|
lastdat = dat;
|
||||||
|
lastdatlen = datlen;
|
||||||
|
memcpy(lastsha1, sha1, sizeof(sha1));
|
||||||
|
}
|
||||||
|
fixup_header_footer();
|
||||||
|
close(packfd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user