Merge branch 'ab/hooks'
authorJunio C Hamano <gitster@pobox.com>
Fri, 19 Aug 2016 22:34:16 +0000 (15:34 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 19 Aug 2016 22:34:16 +0000 (15:34 -0700)
"git rev-parse --git-path hooks/<hook>" learned to take
core.hooksPath configuration variable (introduced during 2.9 cycle)
into account.

* ab/hooks:
rev-parse: respect core.hooksPath in --git-path

1  2 
path.c
run-command.c
diff --combined path.c
index 17551c483476050325114b8521f2960707855c59,ad81856d53cf140a722842a95e88a31bdcd83625..fe3c4d96c6d82b2c8f4e1553f1a52e410c8c02d3
--- 1/path.c
--- 2/path.c
+++ b/path.c
@@@ -5,7 -5,6 +5,7 @@@
  #include "strbuf.h"
  #include "string-list.h"
  #include "dir.h"
 +#include "worktree.h"
  
  static int get_st_mode_bits(const char *path, int *mode)
  {
@@@ -135,7 -134,7 +135,7 @@@ static struct common_dir common_list[] 
   * definite
   * definition
   *
 - * The trie would look look like:
 + * The trie would look like:
   * root: len = 0, children a and d non-NULL, value = NULL.
   *    a: len = 2, contents = bc, value = (data for "abc")
   *    d: len = 2, contents = ef, children i non-NULL, value = (data for "def")
@@@ -380,15 -379,16 +380,17 @@@ static void adjust_git_path(struct strb
                              get_index_file(), strlen(get_index_file()));
        else if (git_db_env && dir_prefix(base, "objects"))
                replace_dir(buf, git_dir_len + 7, get_object_directory());
+       else if (git_hooks_path && dir_prefix(base, "hooks"))
+               replace_dir(buf, git_dir_len + 5, git_hooks_path);
        else if (git_common_dir_env)
                update_common_dir(buf, git_dir_len, NULL);
  }
  
 -static void do_git_path(struct strbuf *buf, const char *fmt, va_list args)
 +static void do_git_path(const struct worktree *wt, struct strbuf *buf,
 +                      const char *fmt, va_list args)
  {
        int gitdir_len;
 -      strbuf_addstr(buf, get_git_dir());
 +      strbuf_addstr(buf, get_worktree_git_dir(wt));
        if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
                strbuf_addch(buf, '/');
        gitdir_len = buf->len;
@@@ -402,7 -402,7 +404,7 @@@ char *git_path_buf(struct strbuf *buf, 
        va_list args;
        strbuf_reset(buf);
        va_start(args, fmt);
 -      do_git_path(buf, fmt, args);
 +      do_git_path(NULL, buf, fmt, args);
        va_end(args);
        return buf->buf;
  }
@@@ -411,7 -411,7 +413,7 @@@ void strbuf_git_path(struct strbuf *sb
  {
        va_list args;
        va_start(args, fmt);
 -      do_git_path(sb, fmt, args);
 +      do_git_path(NULL, sb, fmt, args);
        va_end(args);
  }
  
@@@ -420,7 -420,7 +422,7 @@@ const char *git_path(const char *fmt, .
        struct strbuf *pathname = get_pathname();
        va_list args;
        va_start(args, fmt);
 -      do_git_path(pathname, fmt, args);
 +      do_git_path(NULL, pathname, fmt, args);
        va_end(args);
        return pathname->buf;
  }
@@@ -430,7 -430,7 +432,7 @@@ char *git_pathdup(const char *fmt, ...
        struct strbuf path = STRBUF_INIT;
        va_list args;
        va_start(args, fmt);
 -      do_git_path(&path, fmt, args);
 +      do_git_path(NULL, &path, fmt, args);
        va_end(args);
        return strbuf_detach(&path, NULL);
  }
@@@ -456,16 -456,6 +458,16 @@@ const char *mkpath(const char *fmt, ...
        return cleanup_path(pathname->buf);
  }
  
 +const char *worktree_git_path(const struct worktree *wt, const char *fmt, ...)
 +{
 +      struct strbuf *pathname = get_pathname();
 +      va_list args;
 +      va_start(args, fmt);
 +      do_git_path(wt, pathname, fmt, args);
 +      va_end(args);
 +      return pathname->buf;
 +}
 +
  static void do_submodule_path(struct strbuf *buf, const char *path,
                              const char *fmt, va_list args)
  {
                strbuf_addstr(buf, git_dir);
        }
        strbuf_addch(buf, '/');
 -      strbuf_addstr(&git_submodule_dir, buf->buf);
 +      strbuf_addbuf(&git_submodule_dir, buf);
  
        strbuf_vaddf(buf, fmt, args);
  
@@@ -515,35 -505,6 +517,35 @@@ void strbuf_git_path_submodule(struct s
        va_end(args);
  }
  
 +static void do_git_common_path(struct strbuf *buf,
 +                             const char *fmt,
 +                             va_list args)
 +{
 +      strbuf_addstr(buf, get_git_common_dir());
 +      if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
 +              strbuf_addch(buf, '/');
 +      strbuf_vaddf(buf, fmt, args);
 +      strbuf_cleanup_path(buf);
 +}
 +
 +const char *git_common_path(const char *fmt, ...)
 +{
 +      struct strbuf *pathname = get_pathname();
 +      va_list args;
 +      va_start(args, fmt);
 +      do_git_common_path(pathname, fmt, args);
 +      va_end(args);
 +      return pathname->buf;
 +}
 +
 +void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)
 +{
 +      va_list args;
 +      va_start(args, fmt);
 +      do_git_common_path(sb, fmt, args);
 +      va_end(args);
 +}
 +
  int validate_headref(const char *path)
  {
        struct stat st;
@@@ -743,17 -704,17 +745,17 @@@ static int calc_shared_perm(int mode
  {
        int tweak;
  
 -      if (shared_repository < 0)
 -              tweak = -shared_repository;
 +      if (get_shared_repository() < 0)
 +              tweak = -get_shared_repository();
        else
 -              tweak = shared_repository;
 +              tweak = get_shared_repository();
  
        if (!(mode & S_IWUSR))
                tweak &= ~0222;
        if (mode & S_IXUSR)
                /* Copy read bits to execute bits */
                tweak |= (tweak & 0444) >> 2;
 -      if (shared_repository < 0)
 +      if (get_shared_repository() < 0)
                mode = (mode & ~0777) | tweak;
        else
                mode |= tweak;
@@@ -766,7 -727,7 +768,7 @@@ int adjust_shared_perm(const char *path
  {
        int old_mode, new_mode;
  
 -      if (!shared_repository)
 +      if (!get_shared_repository())
                return 0;
        if (get_st_mode_bits(path, &old_mode) < 0)
                return -1;
diff --combined run-command.c
index 33bc63a1de8d41b52a0ec353cf80b0f2e65dc8fd,c72601056cf5ae7be2593ae89af4effc26a1b043..5a4dbb66d7e4d4ed4bd6cf319f132c1b4d870572
@@@ -233,7 -233,7 +233,7 @@@ static int wait_or_whine(pid_t pid, con
  
        if (waiting < 0) {
                failed_errno = errno;
 -              error("waitpid for %s failed: %s", argv0, strerror(errno));
 +              error_errno("waitpid for %s failed", argv0);
        } else if (waiting != pid) {
                error("waitpid is confused (%s)", argv0);
        } else if (WIFSIGNALED(status)) {
@@@ -420,7 -420,8 +420,7 @@@ fail_pipe
                }
        }
        if (cmd->pid < 0)
 -              error("cannot fork() for %s: %s", cmd->argv[0],
 -                      strerror(errno));
 +              error_errno("cannot fork() for %s", cmd->argv[0]);
        else if (cmd->clean_on_exit)
                mark_child_for_cleanup(cmd->pid);
  
                        cmd->dir, fhin, fhout, fherr);
        failed_errno = errno;
        if (cmd->pid < 0 && (!cmd->silent_exec_failure || errno != ENOENT))
 -              error("cannot spawn %s: %s", cmd->argv[0], strerror(errno));
 +              error_errno("cannot spawn %s", cmd->argv[0]);
        if (cmd->clean_on_exit && cmd->pid >= 0)
                mark_child_for_cleanup(cmd->pid);
  
@@@ -589,16 -590,6 +589,16 @@@ static void *run_thread(void *data
        struct async *async = data;
        intptr_t ret;
  
 +      if (async->isolate_sigpipe) {
 +              sigset_t mask;
 +              sigemptyset(&mask);
 +              sigaddset(&mask, SIGPIPE);
 +              if (pthread_sigmask(SIG_BLOCK, &mask, NULL) < 0) {
 +                      ret = error("unable to block SIGPIPE in async thread");
 +                      return (void *)ret;
 +              }
 +      }
 +
        pthread_setspecific(async_key, async);
        ret = async->proc(async->proc_in, async->proc_out, async->data);
        return (void *)ret;
@@@ -702,7 -693,7 +702,7 @@@ int start_async(struct async *async
                if (pipe(fdin) < 0) {
                        if (async->out > 0)
                                close(async->out);
 -                      return error("cannot create pipe: %s", strerror(errno));
 +                      return error_errno("cannot create pipe");
                }
                async->in = fdin[1];
        }
                                close_pair(fdin);
                        else if (async->in)
                                close(async->in);
 -                      return error("cannot create pipe: %s", strerror(errno));
 +                      return error_errno("cannot create pipe");
                }
                async->out = fdout[0];
        }
  
        async->pid = fork();
        if (async->pid < 0) {
 -              error("fork (async) failed: %s", strerror(errno));
 +              error_errno("fork (async) failed");
                goto error;
        }
        if (!async->pid) {
        {
                int err = pthread_create(&async->tid, NULL, run_thread, async);
                if (err) {
 -                      error("cannot create thread: %s", strerror(err));
 +                      error_errno("cannot create thread");
                        goto error;
                }
        }
@@@ -824,10 -815,7 +824,7 @@@ const char *find_hook(const char *name
        static struct strbuf path = STRBUF_INIT;
  
        strbuf_reset(&path);
-       if (git_hooks_path)
-               strbuf_addf(&path, "%s/%s", git_hooks_path, name);
-       else
-               strbuf_git_path(&path, "hooks/%s", name);
+       strbuf_git_path(&path, "hooks/%s", name);
        if (access(path.buf, X_OK) < 0)
                return NULL;
        return path.buf;
@@@ -864,161 -852,19 +861,161 @@@ int run_hook_le(const char *const *env
        return ret;
  }
  
 -int capture_command(struct child_process *cmd, struct strbuf *buf, size_t hint)
 +struct io_pump {
 +      /* initialized by caller */
 +      int fd;
 +      int type; /* POLLOUT or POLLIN */
 +      union {
 +              struct {
 +                      const char *buf;
 +                      size_t len;
 +              } out;
 +              struct {
 +                      struct strbuf *buf;
 +                      size_t hint;
 +              } in;
 +      } u;
 +
 +      /* returned by pump_io */
 +      int error; /* 0 for success, otherwise errno */
 +
 +      /* internal use */
 +      struct pollfd *pfd;
 +};
 +
 +static int pump_io_round(struct io_pump *slots, int nr, struct pollfd *pfd)
  {
 -      cmd->out = -1;
 +      int pollsize = 0;
 +      int i;
 +
 +      for (i = 0; i < nr; i++) {
 +              struct io_pump *io = &slots[i];
 +              if (io->fd < 0)
 +                      continue;
 +              pfd[pollsize].fd = io->fd;
 +              pfd[pollsize].events = io->type;
 +              io->pfd = &pfd[pollsize++];
 +      }
 +
 +      if (!pollsize)
 +              return 0;
 +
 +      if (poll(pfd, pollsize, -1) < 0) {
 +              if (errno == EINTR)
 +                      return 1;
 +              die_errno("poll failed");
 +      }
 +
 +      for (i = 0; i < nr; i++) {
 +              struct io_pump *io = &slots[i];
 +
 +              if (io->fd < 0)
 +                      continue;
 +
 +              if (!(io->pfd->revents & (POLLOUT|POLLIN|POLLHUP|POLLERR|POLLNVAL)))
 +                      continue;
 +
 +              if (io->type == POLLOUT) {
 +                      ssize_t len = xwrite(io->fd,
 +                                           io->u.out.buf, io->u.out.len);
 +                      if (len < 0) {
 +                              io->error = errno;
 +                              close(io->fd);
 +                              io->fd = -1;
 +                      } else {
 +                              io->u.out.buf += len;
 +                              io->u.out.len -= len;
 +                              if (!io->u.out.len) {
 +                                      close(io->fd);
 +                                      io->fd = -1;
 +                              }
 +                      }
 +              }
 +
 +              if (io->type == POLLIN) {
 +                      ssize_t len = strbuf_read_once(io->u.in.buf,
 +                                                     io->fd, io->u.in.hint);
 +                      if (len < 0)
 +                              io->error = errno;
 +                      if (len <= 0) {
 +                              close(io->fd);
 +                              io->fd = -1;
 +                      }
 +              }
 +      }
 +
 +      return 1;
 +}
 +
 +static int pump_io(struct io_pump *slots, int nr)
 +{
 +      struct pollfd *pfd;
 +      int i;
 +
 +      for (i = 0; i < nr; i++)
 +              slots[i].error = 0;
 +
 +      ALLOC_ARRAY(pfd, nr);
 +      while (pump_io_round(slots, nr, pfd))
 +              ; /* nothing */
 +      free(pfd);
 +
 +      /* There may be multiple errno values, so just pick the first. */
 +      for (i = 0; i < nr; i++) {
 +              if (slots[i].error) {
 +                      errno = slots[i].error;
 +                      return -1;
 +              }
 +      }
 +      return 0;
 +}
 +
 +
 +int pipe_command(struct child_process *cmd,
 +               const char *in, size_t in_len,
 +               struct strbuf *out, size_t out_hint,
 +               struct strbuf *err, size_t err_hint)
 +{
 +      struct io_pump io[3];
 +      int nr = 0;
 +
 +      if (in)
 +              cmd->in = -1;
 +      if (out)
 +              cmd->out = -1;
 +      if (err)
 +              cmd->err = -1;
 +
        if (start_command(cmd) < 0)
                return -1;
  
 -      if (strbuf_read(buf, cmd->out, hint) < 0) {
 -              close(cmd->out);
 +      if (in) {
 +              io[nr].fd = cmd->in;
 +              io[nr].type = POLLOUT;
 +              io[nr].u.out.buf = in;
 +              io[nr].u.out.len = in_len;
 +              nr++;
 +      }
 +      if (out) {
 +              io[nr].fd = cmd->out;
 +              io[nr].type = POLLIN;
 +              io[nr].u.in.buf = out;
 +              io[nr].u.in.hint = out_hint;
 +              nr++;
 +      }
 +      if (err) {
 +              io[nr].fd = cmd->err;
 +              io[nr].type = POLLIN;
 +              io[nr].u.in.buf = err;
 +              io[nr].u.in.hint = err_hint;
 +              nr++;
 +      }
 +
 +      if (pump_io(io, nr) < 0) {
                finish_command(cmd); /* throw away exit code */
                return -1;
        }
  
 -      close(cmd->out);
        return finish_command(cmd);
  }
  
@@@ -1056,7 -902,7 +1053,7 @@@ struct parallel_processes 
        struct strbuf buffered_output; /* of finished children */
  };
  
 -static int default_start_failure(struct strbuf *err,
 +static int default_start_failure(struct strbuf *out,
                                 void *pp_cb,
                                 void *pp_task_cb)
  {
  }
  
  static int default_task_finished(int result,
 -                               struct strbuf *err,
 +                               struct strbuf *out,
                                 void *pp_cb,
                                 void *pp_task_cb)
  {
@@@ -1148,7 -994,7 +1145,7 @@@ static void pp_cleanup(struct parallel_
         * When get_next_task added messages to the buffer in its last
         * iteration, the buffered output is non empty.
         */
 -      fputs(pp->buffered_output.buf, stderr);
 +      strbuf_write(&pp->buffered_output, stderr);
        strbuf_release(&pp->buffered_output);
  
        sigchain_pop_common();
@@@ -1233,7 -1079,7 +1230,7 @@@ static void pp_output(struct parallel_p
        int i = pp->output_owner;
        if (pp->children[i].state == GIT_CP_WORKING &&
            pp->children[i].err.len) {
 -              fputs(pp->children[i].err.buf, stderr);
 +              strbuf_write(&pp->children[i].err, stderr);
                strbuf_reset(&pp->children[i].err);
        }
  }
@@@ -1271,11 -1117,11 +1268,11 @@@ static int pp_collect_finished(struct p
                        strbuf_addbuf(&pp->buffered_output, &pp->children[i].err);
                        strbuf_reset(&pp->children[i].err);
                } else {
 -                      fputs(pp->children[i].err.buf, stderr);
 +                      strbuf_write(&pp->children[i].err, stderr);
                        strbuf_reset(&pp->children[i].err);
  
                        /* Output all other finished child processes */
 -                      fputs(pp->buffered_output.buf, stderr);
 +                      strbuf_write(&pp->buffered_output, stderr);
                        strbuf_reset(&pp->buffered_output);
  
                        /*