Merge branch 'js/forkexec'
authorJunio C Hamano <gitster@pobox.com>
Thu, 1 Nov 2007 20:47:47 +0000 (13:47 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 1 Nov 2007 20:47:47 +0000 (13:47 -0700)
* js/forkexec:
Use the asyncronous function infrastructure to run the content filter.
Avoid a dup2(2) in apply_filter() - start_command() can do it for us.
t0021-conversion.sh: Test that the clean filter really cleans content.
upload-pack: Run rev-list in an asynchronous function.
upload-pack: Move the revision walker into a separate function.
Use the asyncronous function infrastructure in builtin-fetch-pack.c.
Add infrastructure to run a function asynchronously.
upload-pack: Use start_command() to run pack-objects in create_pack_file().
Have start_command() create a pipe to read the stderr of the child.
Use start_comand() in builtin-fetch-pack.c instead of explicit fork/exec.
Use run_command() to spawn external diff programs instead of fork/exec.
Use start_command() to run content filters instead of explicit fork/exec.
Use start_command() in git_connect() instead of explicit fork/exec.
Change git_connect() to return a struct child_process instead of a pid_t.

Conflicts:

builtin-fetch-pack.c

1  2 
builtin-archive.c
builtin-fetch-pack.c
diff.c
send-pack.c
diff --combined builtin-archive.c
index 6f29c2f40a01b3c60eaa9ecfa1ca4d63fe90c8eb,76f8d3d83d141f6875c5c096bea207e2289d4fbe..14a1b3077cd7a5c4d69672bccfadc1354568dc4a
@@@ -30,7 -30,7 +30,7 @@@ static int run_remote_archiver(const ch
  {
        char *url, buf[LARGE_PACKET_MAX];
        int fd[2], i, len, rv;
-       pid_t pid;
+       struct child_process *conn;
        const char *exec = "git-upload-archive";
        int exec_at = 0;
  
@@@ -46,9 -46,7 +46,7 @@@
        }
  
        url = xstrdup(remote);
-       pid = git_connect(fd, url, exec, 0);
-       if (pid < 0)
-               return pid;
+       conn = git_connect(fd, url, exec, 0);
  
        for (i = 1; i < argc; i++) {
                if (i == exec_at)
@@@ -76,7 -74,7 +74,7 @@@
        rv = recv_sideband("archive", fd[0], 1, 2);
        close(fd[0]);
        close(fd[1]);
-       rv |= finish_connect(pid);
+       rv |= finish_connect(conn);
  
        return !!rv;
  }
@@@ -148,14 -146,12 +146,14 @@@ void *sha1_file_to_archive(const char *
        buffer = read_sha1_file(sha1, type, sizep);
        if (buffer && S_ISREG(mode)) {
                struct strbuf buf;
 +              size_t size = 0;
  
                strbuf_init(&buf, 0);
                strbuf_attach(&buf, buffer, *sizep, *sizep + 1);
                convert_to_working_tree(path, buf.buf, buf.len, &buf);
                convert_to_archive(path, buf.buf, buf.len, &buf, commit);
 -              buffer = strbuf_detach(&buf, sizep);
 +              buffer = strbuf_detach(&buf, &size);
 +              *sizep = size;
        }
  
        return buffer;
diff --combined builtin-fetch-pack.c
index 8753840a825d35249fa74ee80867f2dfd542708b,51d8a32791df1c5fe04e0e69fbfe91887e026536..862652be92f65c50aaa900fd9983f8c54840d672
@@@ -7,16 -7,16 +7,17 @@@
  #include "pack.h"
  #include "sideband.h"
  #include "fetch-pack.h"
+ #include "run-command.h"
  
  static int transfer_unpack_limit = -1;
  static int fetch_unpack_limit = -1;
  static int unpack_limit = 100;
 -static struct fetch_pack_args args;
 +static struct fetch_pack_args args = {
 +      /* .uploadpack = */ "git-upload-pack",
 +};
  
  static const char fetch_pack_usage[] =
  "git-fetch-pack [--all] [--quiet|-q] [--keep|-k] [--thin] [--upload-pack=<git-upload-pack>] [--depth=<n>] [--no-progress] [-v] [<host>:]<directory> [<refs>...]";
 -static const char *uploadpack = "git-upload-pack";
  
  #define COMPLETE      (1U << 0)
  #define COMMON                (1U << 1)
@@@ -457,53 -457,49 +458,49 @@@ static int everything_local(struct ref 
        return retval;
  }
  
- static pid_t setup_sideband(int fd[2], int xd[2])
+ static int sideband_demux(int fd, void *data)
  {
-       pid_t side_pid;
+       int *xd = data;
  
+       close(xd[1]);
+       return recv_sideband("fetch-pack", xd[0], fd, 2);
+ }
+ static void setup_sideband(int fd[2], int xd[2], struct async *demux)
+ {
        if (!use_sideband) {
                fd[0] = xd[0];
                fd[1] = xd[1];
-               return 0;
+               return;
        }
        /* xd[] is talking with upload-pack; subprocess reads from
         * xd[0], spits out band#2 to stderr, and feeds us band#1
-        * through our fd[0].
+        * through demux->out.
         */
-       if (pipe(fd) < 0)
-               die("fetch-pack: unable to set up pipe");
-       side_pid = fork();
-       if (side_pid < 0)
+       demux->proc = sideband_demux;
+       demux->data = xd;
+       if (start_async(demux))
                die("fetch-pack: unable to fork off sideband demultiplexer");
-       if (!side_pid) {
-               /* subprocess */
-               close(fd[0]);
-               if (xd[0] != xd[1])
-                       close(xd[1]);
-               if (recv_sideband("fetch-pack", xd[0], fd[1], 2))
-                       exit(1);
-               exit(0);
-       }
        close(xd[0]);
-       close(fd[1]);
+       fd[0] = demux->out;
        fd[1] = xd[1];
-       return side_pid;
  }
  
  static int get_pack(int xd[2], char **pack_lockfile)
  {
-       int status;
-       pid_t pid, side_pid;
+       struct async demux;
        int fd[2];
        const char *argv[20];
        char keep_arg[256];
        char hdr_arg[256];
        const char **av;
        int do_keep = args.keep_pack;
-       int keep_pipe[2];
+       struct child_process cmd;
  
-       side_pid = setup_sideband(fd, xd);
+       setup_sideband(fd, xd, &demux);
  
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.argv = argv;
        av = argv;
        *hdr_arg = 0;
        if (!args.keep_pack && unpack_limit) {
        }
  
        if (do_keep) {
-               if (pack_lockfile && pipe(keep_pipe))
-                       die("fetch-pack: pipe setup failure: %s", strerror(errno));
+               if (pack_lockfile)
+                       cmd.out = -1;
                *av++ = "index-pack";
                *av++ = "--stdin";
                if (!args.quiet && !args.no_progress)
                *av++ = hdr_arg;
        *av++ = NULL;
  
-       pid = fork();
-       if (pid < 0)
+       cmd.in = fd[0];
+       cmd.git_cmd = 1;
+       if (start_command(&cmd))
                die("fetch-pack: unable to fork off %s", argv[0]);
-       if (!pid) {
-               dup2(fd[0], 0);
-               if (do_keep && pack_lockfile) {
-                       dup2(keep_pipe[1], 1);
-                       close(keep_pipe[0]);
-                       close(keep_pipe[1]);
-               }
-               close(fd[0]);
-               close(fd[1]);
-               execv_git_cmd(argv);
-               die("%s exec failed", argv[0]);
-       }
-       close(fd[0]);
        close(fd[1]);
-       if (do_keep && pack_lockfile) {
-               close(keep_pipe[1]);
-               *pack_lockfile = index_pack_lockfile(keep_pipe[0]);
-               close(keep_pipe[0]);
-       }
-       while (waitpid(pid, &status, 0) < 0) {
-               if (errno != EINTR)
-                       die("waiting for %s: %s", argv[0], strerror(errno));
-       }
-       if (WIFEXITED(status)) {
-               int code = WEXITSTATUS(status);
-               if (code)
-                       die("%s died with error code %d", argv[0], code);
-               return 0;
-       }
-       if (WIFSIGNALED(status)) {
-               int sig = WTERMSIG(status);
-               die("%s died of signal %d", argv[0], sig);
-       }
-       die("%s died of unnatural causes %d", argv[0], status);
+       if (do_keep && pack_lockfile)
+               *pack_lockfile = index_pack_lockfile(cmd.out);
+       if (finish_command(&cmd))
+               die("%s failed", argv[0]);
+       if (use_sideband && finish_async(&demux))
+               die("error in sideband demultiplexer");
+       return 0;
  }
  
  static struct ref *do_fetch_pack(int fd[2],
@@@ -763,7 -735,7 +736,7 @@@ struct ref *fetch_pack(struct fetch_pac
  {
        int i, ret;
        int fd[2];
-       pid_t pid;
+       struct child_process *conn;
        struct ref *ref;
        struct stat st;
  
                        st.st_mtime = 0;
        }
  
-       pid = git_connect(fd, (char *)dest, args.uploadpack,
 -      conn = git_connect(fd, (char *)dest, uploadpack,
++      conn = git_connect(fd, (char *)dest, args.uploadpack,
                            args.verbose ? CONNECT_VERBOSE : 0);
-       if (pid < 0)
-               return NULL;
        if (heads && nr_heads)
                nr_heads = remove_duplicates(nr_heads, heads);
        ref = do_fetch_pack(fd, nr_heads, heads, pack_lockfile);
        close(fd[0]);
        close(fd[1]);
-       ret = finish_connect(pid);
+       ret = finish_connect(conn);
  
        if (!ret && nr_heads) {
                /* If the heads to pull were given, we should have
diff --combined diff.c
index af85b94d1b5183e2007b5a221054d9cdcce0faff,30b75441712edc29213589760bcb47900830fe7b..a6aaaf7e5a91f3e5ad5f85341429c80a3452504e
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -9,6 -9,7 +9,7 @@@
  #include "xdiff-interface.h"
  #include "color.h"
  #include "attr.h"
+ #include "run-command.h"
  
  #ifdef NO_FAST_WORKING_DIRECTORY
  #define FAST_WORKING_DIRECTORY 0
@@@ -1440,18 -1441,9 +1441,18 @@@ struct diff_filespec *alloc_filespec(co
        memset(spec, 0, sizeof(*spec));
        spec->path = (char *)(spec + 1);
        memcpy(spec->path, path, namelen+1);
 +      spec->count = 1;
        return spec;
  }
  
 +void free_filespec(struct diff_filespec *spec)
 +{
 +      if (!--spec->count) {
 +              diff_free_filespec_data(spec);
 +              free(spec);
 +      }
 +}
 +
  void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1,
                   unsigned short mode)
  {
@@@ -1521,7 -1513,6 +1522,7 @@@ static int reuse_worktree_file(const ch
  static int populate_from_stdin(struct diff_filespec *s)
  {
        struct strbuf buf;
 +      size_t size = 0;
  
        strbuf_init(&buf, 0);
        if (strbuf_read(&buf, 0, 0) < 0)
                                     strerror(errno));
  
        s->should_munmap = 0;
 -      s->data = strbuf_detach(&buf, &s->size);
 +      s->data = strbuf_detach(&buf, &size);
 +      s->size = size;
        s->should_free = 1;
        return 0;
  }
@@@ -1620,11 -1610,9 +1621,11 @@@ int diff_populate_filespec(struct diff_
                 */
                strbuf_init(&buf, 0);
                if (convert_to_git(s->path, s->data, s->size, &buf)) {
 +                      size_t size = 0;
                        munmap(s->data, s->size);
                        s->should_munmap = 0;
 -                      s->data = strbuf_detach(&buf, &s->size);
 +                      s->data = strbuf_detach(&buf, &size);
 +                      s->size = size;
                        s->should_free = 1;
                }
        }
@@@ -1761,40 -1749,6 +1762,6 @@@ static void remove_tempfile_on_signal(i
        raise(signo);
  }
  
- static int spawn_prog(const char *pgm, const char **arg)
- {
-       pid_t pid;
-       int status;
-       fflush(NULL);
-       pid = fork();
-       if (pid < 0)
-               die("unable to fork");
-       if (!pid) {
-               execvp(pgm, (char *const*) arg);
-               exit(255);
-       }
-       while (waitpid(pid, &status, 0) < 0) {
-               if (errno == EINTR)
-                       continue;
-               return -1;
-       }
-       /* Earlier we did not check the exit status because
-        * diff exits non-zero if files are different, and
-        * we are not interested in knowing that.  It was a
-        * mistake which made it harder to quit a diff-*
-        * session that uses the git-apply-patch-script as
-        * the GIT_EXTERNAL_DIFF.  A custom GIT_EXTERNAL_DIFF
-        * should also exit non-zero only when it wants to
-        * abort the entire diff-* session.
-        */
-       if (WIFEXITED(status) && !WEXITSTATUS(status))
-               return 0;
-       return -1;
- }
  /* An external diff command takes:
   *
   * diff-cmd name infile1 infile1-sha1 infile1-mode \
@@@ -1847,7 -1801,8 +1814,8 @@@ static void run_external_diff(const cha
                *arg++ = name;
        }
        *arg = NULL;
-       retval = spawn_prog(pgm, spawn_arg);
+       fflush(NULL);
+       retval = run_command_v_opt(spawn_arg, 0);
        remove_tempfile();
        if (retval) {
                fprintf(stderr, "external diff died, stopping at %s.\n", name);
@@@ -2444,8 -2399,10 +2412,8 @@@ struct diff_filepair *diff_queue(struc
  
  void diff_free_filepair(struct diff_filepair *p)
  {
 -      diff_free_filespec_data(p->one);
 -      diff_free_filespec_data(p->two);
 -      free(p->one);
 -      free(p->two);
 +      free_filespec(p->one);
 +      free_filespec(p->two);
        free(p);
  }
  
@@@ -2597,9 -2554,9 +2565,9 @@@ void diff_debug_filepair(const struct d
  {
        diff_debug_filespec(p->one, i, "one");
        diff_debug_filespec(p->two, i, "two");
 -      fprintf(stderr, "score %d, status %c stays %d broken %d\n",
 +      fprintf(stderr, "score %d, status %c rename_used %d broken %d\n",
                p->score, p->status ? p->status : '?',
 -              p->source_stays, p->broken_pair);
 +              p->one->rename_used, p->broken_pair);
  }
  
  void diff_debug_queue(const char *msg, struct diff_queue_struct *q)
  
  static void diff_resolve_rename_copy(void)
  {
 -      int i, j;
 -      struct diff_filepair *p, *pp;
 +      int i;
 +      struct diff_filepair *p;
        struct diff_queue_struct *q = &diff_queued_diff;
  
        diff_debug_queue("resolve-rename-copy", q);
                 * either in-place edit or rename/copy edit.
                 */
                else if (DIFF_PAIR_RENAME(p)) {
 -                      if (p->source_stays) {
 -                              p->status = DIFF_STATUS_COPIED;
 -                              continue;
 -                      }
 -                      /* See if there is some other filepair that
 -                       * copies from the same source as us.  If so
 -                       * we are a copy.  Otherwise we are either a
 -                       * copy if the path stays, or a rename if it
 -                       * does not, but we already handled "stays" case.
 +                      /*
 +                       * A rename might have re-connected a broken
 +                       * pair up, causing the pathnames to be the
 +                       * same again. If so, that's not a rename at
 +                       * all, just a modification..
 +                       *
 +                       * Otherwise, see if this source was used for
 +                       * multiple renames, in which case we decrement
 +                       * the count, and call it a copy.
                         */
 -                      for (j = i + 1; j < q->nr; j++) {
 -                              pp = q->queue[j];
 -                              if (strcmp(pp->one->path, p->one->path))
 -                                      continue; /* not us */
 -                              if (!DIFF_PAIR_RENAME(pp))
 -                                      continue; /* not a rename/copy */
 -                              /* pp is a rename/copy from the same source */
 +                      if (!strcmp(p->one->path, p->two->path))
 +                              p->status = DIFF_STATUS_MODIFIED;
 +                      else if (--p->one->rename_used > 0)
                                p->status = DIFF_STATUS_COPIED;
 -                              break;
 -                      }
 -                      if (!p->status)
 +                      else
                                p->status = DIFF_STATUS_RENAMED;
                }
                else if (hashcmp(p->one->sha1, p->two->sha1) ||
diff --combined send-pack.c
index 25053d2c2f7daa9aa392693a892db7e80c8b6469,147f44b01d4f7c9e47780ba0d565466050b0adc1..5e127a1b7b33bdc9aaafc80873c5c987573566bd
@@@ -178,35 -178,6 +178,35 @@@ static int receive_status(int in
        return ret;
  }
  
 +static void update_tracking_ref(struct remote *remote, struct ref *ref)
 +{
 +      struct refspec rs;
 +      int will_delete_ref;
 +
 +      rs.src = ref->name;
 +      rs.dst = NULL;
 +
 +      if (!ref->peer_ref)
 +              return;
 +
 +      will_delete_ref = is_null_sha1(ref->peer_ref->new_sha1);
 +
 +      if (!will_delete_ref &&
 +                      !hashcmp(ref->old_sha1, ref->peer_ref->new_sha1))
 +              return;
 +
 +      if (!remote_find_tracking(remote, &rs)) {
 +              fprintf(stderr, "updating local tracking ref '%s'\n", rs.dst);
 +              if (is_null_sha1(ref->peer_ref->new_sha1)) {
 +                      if (delete_ref(rs.dst, NULL))
 +                              error("Failed to delete");
 +              } else
 +                      update_ref("update by push", rs.dst,
 +                                      ref->new_sha1, NULL, 0, 0);
 +              free(rs.dst);
 +      }
 +}
 +
  static int send_pack(int in, int out, struct remote *remote, int nr_refspec, char **refspec)
  {
        struct ref *ref;
                return -1;
  
        if (!remote_refs) {
 -              fprintf(stderr, "No refs in common and none specified; doing nothing.\n");
 +              fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
 +                      "Perhaps you should specify a branch such as 'master'.\n");
                return 0;
        }
  
                        fprintf(stderr, "\n  from %s\n  to   %s\n",
                                old_hex, new_hex);
                }
 -              if (remote && !dry_run) {
 -                      struct refspec rs;
 -                      rs.src = ref->name;
 -                      rs.dst = NULL;
 -                      if (!remote_find_tracking(remote, &rs)) {
 -                              fprintf(stderr, " Also local %s\n", rs.dst);
 -                              if (will_delete_ref) {
 -                                      if (delete_ref(rs.dst, NULL)) {
 -                                              error("Failed to delete");
 -                                      }
 -                              } else
 -                                      update_ref("update by push", rs.dst,
 -                                              ref->new_sha1, NULL, 0, 0);
 -                              free(rs.dst);
 -                      }
 -              }
        }
  
        packet_flush(out);
                        ret = -4;
        }
  
 +      if (!dry_run && remote && ret == 0) {
 +              for (ref = remote_refs; ref; ref = ref->next)
 +                      update_tracking_ref(remote, ref);
 +      }
 +
        if (!new_refs && ret == 0)
                fprintf(stderr, "Everything up-to-date\n");
        return ret;
@@@ -384,7 -365,7 +384,7 @@@ int main(int argc, char **argv
        char *dest = NULL;
        char **heads = NULL;
        int fd[2], ret;
-       pid_t pid;
+       struct child_process *conn;
        char *remote_name = NULL;
        struct remote *remote = NULL;
  
                }
        }
  
-       pid = git_connect(fd, dest, receivepack, verbose ? CONNECT_VERBOSE : 0);
-       if (pid < 0)
-               return 1;
+       conn = git_connect(fd, dest, receivepack, verbose ? CONNECT_VERBOSE : 0);
        ret = send_pack(fd[0], fd[1], remote, nr_heads, heads);
        close(fd[0]);
        close(fd[1]);
-       ret |= finish_connect(pid);
+       ret |= finish_connect(conn);
        return !!ret;
  }