]>
Commit | Line | Data |
---|---|---|
c323ac7d LT |
1 | #include "cache.h" |
2 | #include "object.h" | |
3 | #include "delta.h" | |
a733cb60 | 4 | #include "pack.h" |
c38138cd | 5 | #include "csum-file.h" |
21fcd1bd | 6 | #include <sys/time.h> |
c323ac7d | 7 | |
024701f1 | 8 | static const char pack_usage[] = "git-pack-objects [-q] [--non-empty] [--local] [--incremental] [--window=N] [--depth=N] {--stdout | base-name} < object-list"; |
c323ac7d | 9 | |
c323ac7d LT |
10 | struct object_entry { |
11 | unsigned char sha1[20]; | |
12 | unsigned long size; | |
13 | unsigned long offset; | |
14 | unsigned int depth; | |
27225f2e | 15 | unsigned int hash; |
a733cb60 | 16 | enum object_type type; |
c323ac7d LT |
17 | unsigned long delta_size; |
18 | struct object_entry *delta; | |
19 | }; | |
20 | ||
5f3de58f | 21 | static unsigned char object_list_sha1[20]; |
1c4a2912 | 22 | static int non_empty = 0; |
64560374 | 23 | static int local = 0; |
eb019375 | 24 | static int incremental = 0; |
c323ac7d LT |
25 | static struct object_entry **sorted_by_sha, **sorted_by_type; |
26 | static struct object_entry *objects = NULL; | |
27 | static int nr_objects = 0, nr_alloc = 0; | |
c323ac7d | 28 | static const char *base_name; |
e1808845 | 29 | static unsigned char pack_file_sha1[20]; |
024701f1 | 30 | static int progress = 1; |
c323ac7d | 31 | |
c323ac7d LT |
32 | static void *delta_against(void *buf, unsigned long size, struct object_entry *entry) |
33 | { | |
34 | unsigned long othersize, delta_size; | |
35 | char type[10]; | |
36 | void *otherbuf = read_sha1_file(entry->delta->sha1, type, &othersize); | |
37 | void *delta_buf; | |
38 | ||
39 | if (!otherbuf) | |
40 | die("unable to read %s", sha1_to_hex(entry->delta->sha1)); | |
8ee378a0 | 41 | delta_buf = diff_delta(otherbuf, othersize, |
dcde55bc | 42 | buf, size, &delta_size, 0); |
75c42d8c | 43 | if (!delta_buf || delta_size != entry->delta_size) |
c323ac7d LT |
44 | die("delta size changed"); |
45 | free(buf); | |
46 | free(otherbuf); | |
47 | return delta_buf; | |
48 | } | |
49 | ||
a733cb60 LT |
50 | /* |
51 | * The per-object header is a pretty dense thing, which is | |
52 | * - first byte: low four bits are "size", then three bits of "type", | |
53 | * and the high bit is "size continues". | |
54 | * - each byte afterwards: low seven bits are size continuation, | |
55 | * with the high bit being "size continues" | |
56 | */ | |
57 | static int encode_header(enum object_type type, unsigned long size, unsigned char *hdr) | |
58 | { | |
01247d87 | 59 | int n = 1; |
a733cb60 LT |
60 | unsigned char c; |
61 | ||
62 | if (type < OBJ_COMMIT || type > OBJ_DELTA) | |
63 | die("bad type %d", type); | |
64 | ||
01247d87 LT |
65 | c = (type << 4) | (size & 15); |
66 | size >>= 4; | |
67 | while (size) { | |
a733cb60 | 68 | *hdr++ = c | 0x80; |
01247d87 LT |
69 | c = size & 0x7f; |
70 | size >>= 7; | |
71 | n++; | |
a733cb60 LT |
72 | } |
73 | *hdr = c; | |
74 | return n; | |
75 | } | |
76 | ||
c38138cd | 77 | static unsigned long write_object(struct sha1file *f, struct object_entry *entry) |
c323ac7d LT |
78 | { |
79 | unsigned long size; | |
80 | char type[10]; | |
81 | void *buf = read_sha1_file(entry->sha1, type, &size); | |
a733cb60 | 82 | unsigned char header[10]; |
c323ac7d | 83 | unsigned hdrlen, datalen; |
a733cb60 | 84 | enum object_type obj_type; |
c323ac7d LT |
85 | |
86 | if (!buf) | |
87 | die("unable to read %s", sha1_to_hex(entry->sha1)); | |
88 | if (size != entry->size) | |
89 | die("object %s size inconsistency (%lu vs %lu)", sha1_to_hex(entry->sha1), size, entry->size); | |
90 | ||
91 | /* | |
e1ddc976 JH |
92 | * The object header is a byte of 'type' followed by zero or |
93 | * more bytes of length. For deltas, the 20 bytes of delta sha1 | |
94 | * follows that. | |
c323ac7d | 95 | */ |
a733cb60 | 96 | obj_type = entry->type; |
c323ac7d | 97 | if (entry->delta) { |
c323ac7d LT |
98 | buf = delta_against(buf, size, entry); |
99 | size = entry->delta_size; | |
a733cb60 | 100 | obj_type = OBJ_DELTA; |
c323ac7d | 101 | } |
a733cb60 | 102 | hdrlen = encode_header(obj_type, size, header); |
c38138cd | 103 | sha1write(f, header, hdrlen); |
a733cb60 LT |
104 | if (entry->delta) { |
105 | sha1write(f, entry->delta, 20); | |
106 | hdrlen += 20; | |
107 | } | |
c38138cd | 108 | datalen = sha1write_compressed(f, buf, size); |
c323ac7d LT |
109 | free(buf); |
110 | return hdrlen + datalen; | |
111 | } | |
112 | ||
9d5ab962 JH |
113 | static unsigned long write_one(struct sha1file *f, |
114 | struct object_entry *e, | |
115 | unsigned long offset) | |
116 | { | |
117 | if (e->offset) | |
118 | /* offset starts from header size and cannot be zero | |
119 | * if it is written already. | |
120 | */ | |
121 | return offset; | |
122 | e->offset = offset; | |
123 | offset += write_object(f, e); | |
82f9d58a | 124 | /* if we are deltified, write out its base object. */ |
9d5ab962 JH |
125 | if (e->delta) |
126 | offset = write_one(f, e->delta, offset); | |
127 | return offset; | |
128 | } | |
129 | ||
c323ac7d LT |
130 | static void write_pack_file(void) |
131 | { | |
132 | int i; | |
d22b9290 | 133 | struct sha1file *f; |
a733cb60 | 134 | unsigned long offset; |
c323ac7d | 135 | unsigned long mb; |
a733cb60 | 136 | struct pack_header hdr; |
c323ac7d | 137 | |
d22b9290 LT |
138 | if (!base_name) |
139 | f = sha1fd(1, "<stdout>"); | |
140 | else | |
5f3de58f | 141 | f = sha1create("%s-%s.%s", base_name, sha1_to_hex(object_list_sha1), "pack"); |
a733cb60 | 142 | hdr.hdr_signature = htonl(PACK_SIGNATURE); |
01247d87 | 143 | hdr.hdr_version = htonl(PACK_VERSION); |
a733cb60 LT |
144 | hdr.hdr_entries = htonl(nr_objects); |
145 | sha1write(f, &hdr, sizeof(hdr)); | |
146 | offset = sizeof(hdr); | |
9d5ab962 JH |
147 | for (i = 0; i < nr_objects; i++) |
148 | offset = write_one(f, objects + i, offset); | |
149 | ||
e1808845 | 150 | sha1close(f, pack_file_sha1, 1); |
c323ac7d LT |
151 | mb = offset >> 20; |
152 | offset &= 0xfffff; | |
153 | } | |
154 | ||
155 | static void write_index_file(void) | |
156 | { | |
157 | int i; | |
5f3de58f | 158 | struct sha1file *f = sha1create("%s-%s.%s", base_name, sha1_to_hex(object_list_sha1), "idx"); |
c323ac7d LT |
159 | struct object_entry **list = sorted_by_sha; |
160 | struct object_entry **last = list + nr_objects; | |
161 | unsigned int array[256]; | |
162 | ||
163 | /* | |
164 | * Write the first-level table (the list is sorted, | |
165 | * but we use a 256-entry lookup to be able to avoid | |
e1808845 | 166 | * having to do eight extra binary search iterations). |
c323ac7d LT |
167 | */ |
168 | for (i = 0; i < 256; i++) { | |
169 | struct object_entry **next = list; | |
170 | while (next < last) { | |
171 | struct object_entry *entry = *next; | |
172 | if (entry->sha1[0] != i) | |
173 | break; | |
174 | next++; | |
175 | } | |
176 | array[i] = htonl(next - sorted_by_sha); | |
177 | list = next; | |
178 | } | |
c38138cd | 179 | sha1write(f, array, 256 * sizeof(int)); |
c323ac7d LT |
180 | |
181 | /* | |
182 | * Write the actual SHA1 entries.. | |
183 | */ | |
184 | list = sorted_by_sha; | |
49397104 | 185 | for (i = 0; i < nr_objects; i++) { |
c323ac7d LT |
186 | struct object_entry *entry = *list++; |
187 | unsigned int offset = htonl(entry->offset); | |
c38138cd LT |
188 | sha1write(f, &offset, 4); |
189 | sha1write(f, entry->sha1, 20); | |
c323ac7d | 190 | } |
e1808845 LT |
191 | sha1write(f, pack_file_sha1, 20); |
192 | sha1close(f, NULL, 1); | |
c323ac7d LT |
193 | } |
194 | ||
5f3de58f | 195 | static int add_object_entry(unsigned char *sha1, unsigned int hash) |
c323ac7d LT |
196 | { |
197 | unsigned int idx = nr_objects; | |
198 | struct object_entry *entry; | |
199 | ||
64560374 LT |
200 | if (incremental || local) { |
201 | struct packed_git *p; | |
202 | ||
203 | for (p = packed_git; p; p = p->next) { | |
204 | struct pack_entry e; | |
205 | ||
206 | if (find_pack_entry_one(sha1, &e, p)) { | |
207 | if (incremental) | |
208 | return 0; | |
209 | if (local && !p->pack_local) | |
210 | return 0; | |
211 | } | |
212 | } | |
213 | } | |
eb019375 | 214 | |
c323ac7d LT |
215 | if (idx >= nr_alloc) { |
216 | unsigned int needed = (idx + 1024) * 3 / 2; | |
217 | objects = xrealloc(objects, needed * sizeof(*entry)); | |
218 | nr_alloc = needed; | |
219 | } | |
220 | entry = objects + idx; | |
221 | memset(entry, 0, sizeof(*entry)); | |
222 | memcpy(entry->sha1, sha1, 20); | |
27225f2e | 223 | entry->hash = hash; |
c323ac7d | 224 | nr_objects = idx+1; |
5f3de58f | 225 | return 1; |
c323ac7d LT |
226 | } |
227 | ||
228 | static void check_object(struct object_entry *entry) | |
229 | { | |
36e4d74a JH |
230 | char type[20]; |
231 | ||
232 | if (!sha1_object_info(entry->sha1, type, &entry->size)) { | |
233 | if (!strcmp(type, "commit")) { | |
a733cb60 | 234 | entry->type = OBJ_COMMIT; |
36e4d74a | 235 | } else if (!strcmp(type, "tree")) { |
a733cb60 | 236 | entry->type = OBJ_TREE; |
36e4d74a | 237 | } else if (!strcmp(type, "blob")) { |
a733cb60 | 238 | entry->type = OBJ_BLOB; |
a69d0943 | 239 | } else if (!strcmp(type, "tag")) { |
a733cb60 | 240 | entry->type = OBJ_TAG; |
36e4d74a JH |
241 | } else |
242 | die("unable to pack object %s of type %s", | |
243 | sha1_to_hex(entry->sha1), type); | |
244 | } | |
245 | else | |
246 | die("unable to get type of object %s", | |
247 | sha1_to_hex(entry->sha1)); | |
c323ac7d LT |
248 | } |
249 | ||
250 | static void get_object_details(void) | |
251 | { | |
252 | int i; | |
253 | struct object_entry *entry = objects; | |
254 | ||
255 | for (i = 0; i < nr_objects; i++) | |
256 | check_object(entry++); | |
257 | } | |
258 | ||
259 | typedef int (*entry_sort_t)(const struct object_entry *, const struct object_entry *); | |
260 | ||
261 | static entry_sort_t current_sort; | |
262 | ||
263 | static int sort_comparator(const void *_a, const void *_b) | |
264 | { | |
265 | struct object_entry *a = *(struct object_entry **)_a; | |
266 | struct object_entry *b = *(struct object_entry **)_b; | |
267 | return current_sort(a,b); | |
268 | } | |
269 | ||
270 | static struct object_entry **create_sorted_list(entry_sort_t sort) | |
271 | { | |
272 | struct object_entry **list = xmalloc(nr_objects * sizeof(struct object_entry *)); | |
273 | int i; | |
274 | ||
275 | for (i = 0; i < nr_objects; i++) | |
276 | list[i] = objects + i; | |
277 | current_sort = sort; | |
278 | qsort(list, nr_objects, sizeof(struct object_entry *), sort_comparator); | |
279 | return list; | |
280 | } | |
281 | ||
282 | static int sha1_sort(const struct object_entry *a, const struct object_entry *b) | |
283 | { | |
284 | return memcmp(a->sha1, b->sha1, 20); | |
285 | } | |
286 | ||
287 | static int type_size_sort(const struct object_entry *a, const struct object_entry *b) | |
288 | { | |
289 | if (a->type < b->type) | |
290 | return -1; | |
291 | if (a->type > b->type) | |
292 | return 1; | |
27225f2e LT |
293 | if (a->hash < b->hash) |
294 | return -1; | |
295 | if (a->hash > b->hash) | |
296 | return 1; | |
c323ac7d LT |
297 | if (a->size < b->size) |
298 | return -1; | |
299 | if (a->size > b->size) | |
300 | return 1; | |
301 | return a < b ? -1 : (a > b); | |
302 | } | |
303 | ||
304 | struct unpacked { | |
305 | struct object_entry *entry; | |
306 | void *data; | |
307 | }; | |
308 | ||
309 | /* | |
521a4f4c LT |
310 | * We search for deltas _backwards_ in a list sorted by type and |
311 | * by size, so that we see progressively smaller and smaller files. | |
312 | * That's because we prefer deltas to be from the bigger file | |
313 | * to the smaller - deletes are potentially cheaper, but perhaps | |
314 | * more importantly, the bigger file is likely the more recent | |
315 | * one. | |
c323ac7d | 316 | */ |
d116a45a | 317 | static int try_delta(struct unpacked *cur, struct unpacked *old, unsigned max_depth) |
c323ac7d LT |
318 | { |
319 | struct object_entry *cur_entry = cur->entry; | |
320 | struct object_entry *old_entry = old->entry; | |
521a4f4c | 321 | unsigned long size, oldsize, delta_size, sizediff; |
75c42d8c | 322 | long max_size; |
c323ac7d LT |
323 | void *delta_buf; |
324 | ||
325 | /* Don't bother doing diffs between different types */ | |
326 | if (cur_entry->type != old_entry->type) | |
327 | return -1; | |
328 | ||
c323ac7d | 329 | size = cur_entry->size; |
75c42d8c LT |
330 | if (size < 50) |
331 | return -1; | |
c323ac7d | 332 | oldsize = old_entry->size; |
521a4f4c LT |
333 | sizediff = oldsize > size ? oldsize - size : size - oldsize; |
334 | if (sizediff > size / 8) | |
c323ac7d | 335 | return -1; |
d116a45a LT |
336 | if (old_entry->depth >= max_depth) |
337 | return 0; | |
c323ac7d LT |
338 | |
339 | /* | |
340 | * NOTE! | |
341 | * | |
342 | * We always delta from the bigger to the smaller, since that's | |
343 | * more space-efficient (deletes don't have to say _what_ they | |
344 | * delete). | |
345 | */ | |
75c42d8c LT |
346 | max_size = size / 2 - 20; |
347 | if (cur_entry->delta) | |
348 | max_size = cur_entry->delta_size-1; | |
27225f2e LT |
349 | if (sizediff >= max_size) |
350 | return -1; | |
8ee378a0 JH |
351 | delta_buf = diff_delta(old->data, oldsize, |
352 | cur->data, size, &delta_size, max_size); | |
c323ac7d | 353 | if (!delta_buf) |
75c42d8c LT |
354 | return 0; |
355 | cur_entry->delta = old_entry; | |
356 | cur_entry->delta_size = delta_size; | |
d116a45a | 357 | cur_entry->depth = old_entry->depth + 1; |
c323ac7d | 358 | free(delta_buf); |
eb41ab11 | 359 | return 0; |
c323ac7d LT |
360 | } |
361 | ||
d116a45a | 362 | static void find_deltas(struct object_entry **list, int window, int depth) |
c323ac7d | 363 | { |
521a4f4c | 364 | int i, idx; |
c323ac7d LT |
365 | unsigned int array_size = window * sizeof(struct unpacked); |
366 | struct unpacked *array = xmalloc(array_size); | |
21fcd1bd | 367 | int eye_candy; |
c323ac7d LT |
368 | |
369 | memset(array, 0, array_size); | |
521a4f4c LT |
370 | i = nr_objects; |
371 | idx = 0; | |
21fcd1bd JH |
372 | eye_candy = i - (nr_objects / 20); |
373 | ||
521a4f4c | 374 | while (--i >= 0) { |
c323ac7d LT |
375 | struct object_entry *entry = list[i]; |
376 | struct unpacked *n = array + idx; | |
377 | unsigned long size; | |
378 | char type[10]; | |
379 | int j; | |
380 | ||
21fcd1bd JH |
381 | if (progress && i <= eye_candy) { |
382 | eye_candy -= nr_objects / 20; | |
383 | fputc('.', stderr); | |
384 | } | |
c323ac7d LT |
385 | free(n->data); |
386 | n->entry = entry; | |
387 | n->data = read_sha1_file(entry->sha1, type, &size); | |
388 | if (size != entry->size) | |
389 | die("object %s inconsistent object length (%lu vs %lu)", sha1_to_hex(entry->sha1), size, entry->size); | |
78817c15 LT |
390 | j = window; |
391 | while (--j > 0) { | |
392 | unsigned int other_idx = idx + j; | |
c323ac7d | 393 | struct unpacked *m; |
78817c15 LT |
394 | if (other_idx >= window) |
395 | other_idx -= window; | |
c323ac7d LT |
396 | m = array + other_idx; |
397 | if (!m->entry) | |
398 | break; | |
d116a45a | 399 | if (try_delta(n, m, depth) < 0) |
c323ac7d LT |
400 | break; |
401 | } | |
521a4f4c LT |
402 | idx++; |
403 | if (idx >= window) | |
404 | idx = 0; | |
c323ac7d | 405 | } |
adee7bdf SV |
406 | |
407 | for (i = 0; i < window; ++i) | |
408 | free(array[i].data); | |
409 | free(array); | |
c323ac7d LT |
410 | } |
411 | ||
f3123c4a JH |
412 | static void prepare_pack(int window, int depth) |
413 | { | |
414 | get_object_details(); | |
415 | ||
21fcd1bd JH |
416 | if (progress) |
417 | fprintf(stderr, "Packing %d objects", nr_objects); | |
f3123c4a JH |
418 | sorted_by_type = create_sorted_list(type_size_sort); |
419 | if (window && depth) | |
420 | find_deltas(sorted_by_type, window+1, depth); | |
21fcd1bd JH |
421 | if (progress) |
422 | fputc('\n', stderr); | |
f3123c4a JH |
423 | write_pack_file(); |
424 | } | |
425 | ||
426 | static int reuse_cached_pack(unsigned char *sha1, int pack_to_stdout) | |
427 | { | |
428 | static const char cache[] = "pack-cache/pack-%s.%s"; | |
429 | char *cached_pack, *cached_idx; | |
430 | int ifd, ofd, ifd_ix = -1; | |
431 | ||
432 | cached_pack = git_path(cache, sha1_to_hex(sha1), "pack"); | |
433 | ifd = open(cached_pack, O_RDONLY); | |
434 | if (ifd < 0) | |
435 | return 0; | |
436 | ||
437 | if (!pack_to_stdout) { | |
438 | cached_idx = git_path(cache, sha1_to_hex(sha1), "idx"); | |
439 | ifd_ix = open(cached_idx, O_RDONLY); | |
440 | if (ifd_ix < 0) { | |
441 | close(ifd); | |
442 | return 0; | |
443 | } | |
444 | } | |
445 | ||
446 | fprintf(stderr, "Reusing %d objects pack %s\n", nr_objects, | |
447 | sha1_to_hex(sha1)); | |
448 | ||
449 | if (pack_to_stdout) { | |
450 | if (copy_fd(ifd, 1)) | |
451 | exit(1); | |
452 | close(ifd); | |
453 | } | |
454 | else { | |
455 | char name[PATH_MAX]; | |
456 | snprintf(name, sizeof(name), | |
457 | "%s-%s.%s", base_name, sha1_to_hex(sha1), "pack"); | |
458 | ofd = open(name, O_CREAT | O_EXCL | O_WRONLY, 0666); | |
459 | if (ofd < 0) | |
460 | die("unable to open %s (%s)", name, strerror(errno)); | |
461 | if (copy_fd(ifd, ofd)) | |
462 | exit(1); | |
463 | close(ifd); | |
464 | ||
465 | snprintf(name, sizeof(name), | |
466 | "%s-%s.%s", base_name, sha1_to_hex(sha1), "idx"); | |
467 | ofd = open(name, O_CREAT | O_EXCL | O_WRONLY, 0666); | |
468 | if (ofd < 0) | |
469 | die("unable to open %s (%s)", name, strerror(errno)); | |
470 | if (copy_fd(ifd_ix, ofd)) | |
471 | exit(1); | |
472 | close(ifd_ix); | |
473 | puts(sha1_to_hex(sha1)); | |
474 | } | |
475 | ||
476 | return 1; | |
477 | } | |
478 | ||
c323ac7d LT |
479 | int main(int argc, char **argv) |
480 | { | |
5f3de58f | 481 | SHA_CTX ctx; |
27225f2e | 482 | char line[PATH_MAX + 20]; |
d22b9290 | 483 | int window = 10, depth = 10, pack_to_stdout = 0; |
84c8d8ae | 484 | struct object_entry **list; |
c323ac7d | 485 | int i; |
21fcd1bd JH |
486 | struct timeval prev_tv; |
487 | int eye_candy = 0; | |
488 | int eye_candy_incr = 500; | |
489 | ||
c323ac7d | 490 | |
53228a5f JH |
491 | setup_git_directory(); |
492 | ||
c323ac7d LT |
493 | for (i = 1; i < argc; i++) { |
494 | const char *arg = argv[i]; | |
495 | ||
496 | if (*arg == '-') { | |
1c4a2912 LT |
497 | if (!strcmp("--non-empty", arg)) { |
498 | non_empty = 1; | |
499 | continue; | |
500 | } | |
64560374 LT |
501 | if (!strcmp("--local", arg)) { |
502 | local = 1; | |
503 | continue; | |
504 | } | |
eb019375 LT |
505 | if (!strcmp("--incremental", arg)) { |
506 | incremental = 1; | |
507 | continue; | |
508 | } | |
c323ac7d LT |
509 | if (!strncmp("--window=", arg, 9)) { |
510 | char *end; | |
f846bbff | 511 | window = strtoul(arg+9, &end, 0); |
c323ac7d LT |
512 | if (!arg[9] || *end) |
513 | usage(pack_usage); | |
514 | continue; | |
515 | } | |
d116a45a LT |
516 | if (!strncmp("--depth=", arg, 8)) { |
517 | char *end; | |
518 | depth = strtoul(arg+8, &end, 0); | |
519 | if (!arg[8] || *end) | |
520 | usage(pack_usage); | |
521 | continue; | |
522 | } | |
024701f1 JH |
523 | if (!strcmp("-q", arg)) { |
524 | progress = 0; | |
525 | continue; | |
526 | } | |
d22b9290 LT |
527 | if (!strcmp("--stdout", arg)) { |
528 | pack_to_stdout = 1; | |
529 | continue; | |
530 | } | |
c323ac7d LT |
531 | usage(pack_usage); |
532 | } | |
533 | if (base_name) | |
534 | usage(pack_usage); | |
535 | base_name = arg; | |
536 | } | |
537 | ||
d22b9290 | 538 | if (pack_to_stdout != !base_name) |
c323ac7d LT |
539 | usage(pack_usage); |
540 | ||
64560374 | 541 | prepare_packed_git(); |
21fcd1bd JH |
542 | if (progress) { |
543 | fprintf(stderr, "Generating pack...\n"); | |
544 | gettimeofday(&prev_tv, NULL); | |
545 | } | |
c323ac7d | 546 | while (fgets(line, sizeof(line), stdin) != NULL) { |
27225f2e LT |
547 | unsigned int hash; |
548 | char *p; | |
c323ac7d | 549 | unsigned char sha1[20]; |
27225f2e | 550 | |
21fcd1bd JH |
551 | if (progress && (eye_candy <= nr_objects)) { |
552 | fprintf(stderr, "Counting objects...%d\r", nr_objects); | |
553 | if (eye_candy && (50 <= eye_candy_incr)) { | |
554 | struct timeval tv; | |
555 | int time_diff; | |
556 | gettimeofday(&tv, NULL); | |
557 | time_diff = (tv.tv_sec - prev_tv.tv_sec); | |
558 | time_diff <<= 10; | |
559 | time_diff += (tv.tv_usec - prev_tv.tv_usec); | |
560 | if ((1 << 9) < time_diff) | |
561 | eye_candy_incr += 50; | |
562 | else if (50 < eye_candy_incr) | |
563 | eye_candy_incr -= 50; | |
564 | } | |
565 | eye_candy += eye_candy_incr; | |
566 | } | |
c323ac7d | 567 | if (get_sha1_hex(line, sha1)) |
ef07618f | 568 | die("expected sha1, got garbage:\n %s", line); |
27225f2e LT |
569 | hash = 0; |
570 | p = line+40; | |
571 | while (*p) { | |
572 | unsigned char c = *p++; | |
573 | if (isspace(c)) | |
574 | continue; | |
575 | hash = hash * 11 + c; | |
576 | } | |
84c8d8ae | 577 | add_object_entry(sha1, hash); |
c323ac7d | 578 | } |
21fcd1bd JH |
579 | if (progress) |
580 | fprintf(stderr, "Done counting %d objects.\n", nr_objects); | |
1c4a2912 LT |
581 | if (non_empty && !nr_objects) |
582 | return 0; | |
c323ac7d LT |
583 | |
584 | sorted_by_sha = create_sorted_list(sha1_sort); | |
84c8d8ae JH |
585 | SHA1_Init(&ctx); |
586 | list = sorted_by_sha; | |
587 | for (i = 0; i < nr_objects; i++) { | |
588 | struct object_entry *entry = *list++; | |
589 | SHA1_Update(&ctx, entry->sha1, 20); | |
590 | } | |
591 | SHA1_Final(object_list_sha1, &ctx); | |
592 | ||
f3123c4a JH |
593 | if (reuse_cached_pack(object_list_sha1, pack_to_stdout)) |
594 | ; | |
595 | else { | |
596 | prepare_pack(window, depth); | |
597 | if (!pack_to_stdout) { | |
598 | write_index_file(); | |
599 | puts(sha1_to_hex(object_list_sha1)); | |
600 | } | |
5f3de58f | 601 | } |
c323ac7d LT |
602 | return 0; |
603 | } |