static struct object_array want_obj;
static struct object_array extra_edge_obj;
static unsigned int timeout;
+static int keepalive = 5;
/* 0 for no sideband,
* otherwise maximum packet size (up to 65520 bytes).
*/
return sz;
}
-static FILE *pack_pipe = NULL;
-static void show_commit(struct commit *commit, void *data)
-{
- if (commit->object.flags & BOUNDARY)
- fputc('-', pack_pipe);
- if (fputs(sha1_to_hex(commit->object.sha1), pack_pipe) < 0)
- die("broken output pipe");
- fputc('\n', pack_pipe);
- fflush(pack_pipe);
- free(commit->buffer);
- commit->buffer = NULL;
-}
-
-static void show_object(struct object *obj,
- const struct name_path *path, const char *component,
- void *cb_data)
-{
- show_object_with_name(pack_pipe, obj, path, component);
-}
-
-static void show_edge(struct commit *commit)
-{
- fprintf(pack_pipe, "-%s\n", sha1_to_hex(commit->object.sha1));
-}
-
-static int do_rev_list(int in, int out, void *user_data)
-{
- int i;
- struct rev_info revs;
-
- pack_pipe = xfdopen(out, "w");
- init_revisions(&revs, NULL);
- revs.tag_objects = 1;
- revs.tree_objects = 1;
- revs.blob_objects = 1;
- if (use_thin_pack)
- revs.edge_hint = 1;
-
- for (i = 0; i < want_obj.nr; i++) {
- struct object *o = want_obj.objects[i].item;
- /* why??? */
- o->flags &= ~UNINTERESTING;
- add_pending_object(&revs, o, NULL);
- }
- for (i = 0; i < have_obj.nr; i++) {
- struct object *o = have_obj.objects[i].item;
- o->flags |= UNINTERESTING;
- add_pending_object(&revs, o, NULL);
- }
- setup_revisions(0, NULL, &revs, NULL);
- if (prepare_revision_walk(&revs))
- die("revision walk setup failed");
- mark_edges_uninteresting(revs.commits, &revs, show_edge);
- if (use_thin_pack)
- for (i = 0; i < extra_edge_obj.nr; i++)
- fprintf(pack_pipe, "-%s\n", sha1_to_hex(
- extra_edge_obj.objects[i].item->sha1));
- traverse_commit_list(&revs, show_commit, show_object, NULL);
- fflush(pack_pipe);
- fclose(pack_pipe);
- return 0;
-}
-
static void create_pack_file(void)
{
- struct async rev_list;
struct child_process pack_objects;
char data[8193], progress[128];
char abort_msg[] = "aborting due to possible repository "
"corruption on the remote side.";
int buffered = -1;
ssize_t sz;
- const char *argv[10];
- int arg = 0;
+ const char *argv[12];
+ int i, arg = 0;
+ FILE *pipe_fd;
+ char *shallow_file = NULL;
- argv[arg++] = "pack-objects";
- if (!shallow_nr) {
- argv[arg++] = "--revs";
- if (use_thin_pack)
- argv[arg++] = "--thin";
+ if (shallow_nr) {
+ shallow_file = setup_temporary_shallow();
+ argv[arg++] = "--shallow-file";
+ argv[arg++] = shallow_file;
}
+ argv[arg++] = "pack-objects";
+ argv[arg++] = "--revs";
+ if (use_thin_pack)
+ argv[arg++] = "--thin";
argv[arg++] = "--stdout";
if (!no_progress)
if (start_command(&pack_objects))
die("git upload-pack: unable to fork git-pack-objects");
- if (shallow_nr) {
- memset(&rev_list, 0, sizeof(rev_list));
- rev_list.proc = do_rev_list;
- rev_list.out = pack_objects.in;
- if (start_async(&rev_list))
- die("git upload-pack: unable to fork git-rev-list");
- }
- else {
- FILE *pipe_fd = xfdopen(pack_objects.in, "w");
- int i;
-
- for (i = 0; i < want_obj.nr; i++)
- fprintf(pipe_fd, "%s\n",
- sha1_to_hex(want_obj.objects[i].item->sha1));
- fprintf(pipe_fd, "--not\n");
- for (i = 0; i < have_obj.nr; i++)
- fprintf(pipe_fd, "%s\n",
- sha1_to_hex(have_obj.objects[i].item->sha1));
- fprintf(pipe_fd, "\n");
- fflush(pipe_fd);
- fclose(pipe_fd);
- }
-
+ pipe_fd = xfdopen(pack_objects.in, "w");
+
+ for (i = 0; i < want_obj.nr; i++)
+ fprintf(pipe_fd, "%s\n",
+ sha1_to_hex(want_obj.objects[i].item->sha1));
+ fprintf(pipe_fd, "--not\n");
+ for (i = 0; i < have_obj.nr; i++)
+ fprintf(pipe_fd, "%s\n",
+ sha1_to_hex(have_obj.objects[i].item->sha1));
+ for (i = 0; i < extra_edge_obj.nr; i++)
+ fprintf(pipe_fd, "%s\n",
+ sha1_to_hex(extra_edge_obj.objects[i].item->sha1));
+ fprintf(pipe_fd, "\n");
+ fflush(pipe_fd);
+ fclose(pipe_fd);
/* We read from pack_objects.err to capture stderr output for
* progress bar, and pack_objects.out to capture the pack data.
while (1) {
struct pollfd pfd[2];
int pe, pu, pollsize;
+ int ret;
reset_timeout();
if (!pollsize)
break;
- if (poll(pfd, pollsize, -1) < 0) {
+ ret = poll(pfd, pollsize, 1000 * keepalive);
+ if (ret < 0) {
if (errno != EINTR) {
error("poll failed, resuming: %s",
strerror(errno));
if (sz < 0)
goto fail;
}
+
+ /*
+ * We hit the keepalive timeout without saying anything; send
+ * an empty message on the data sideband just to let the other
+ * side know we're still working on it, but don't have any data
+ * yet.
+ *
+ * If we don't have a sideband channel, there's no room in the
+ * protocol to say anything, so those clients are just out of
+ * luck.
+ */
+ if (!ret && use_sideband) {
+ static const char buf[] = "0005\1";
+ write_or_die(1, buf, 5);
+ }
}
if (finish_command(&pack_objects)) {
error("git upload-pack: git-pack-objects died with error.");
goto fail;
}
- if (shallow_nr && finish_async(&rev_list))
- goto fail; /* error was already reported */
+ if (shallow_file) {
+ if (*shallow_file)
+ unlink(shallow_file);
+ free(shallow_file);
+ }
/* flush the data */
if (0 <= buffered) {
{
if (!strcmp("uploadpack.allowtipsha1inwant", var))
allow_tip_sha1_in_want = git_config_bool(var, value);
+ else if (!strcmp("uploadpack.keepalive", var)) {
+ keepalive = git_config_int(var, value);
+ if (!keepalive)
+ keepalive = -1;
+ }
return parse_hide_refs_config(var, value, "uploadpack");
}