Code

Merge branch 'maint'
authorJunio C Hamano <gitster@pobox.com>
Mon, 6 Aug 2007 08:37:10 +0000 (01:37 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 6 Aug 2007 08:37:10 +0000 (01:37 -0700)
* maint:
  apply: remove directory that becomes empty by renaming the last file away
  setup.c:verify_non_filename(): don't die unnecessarily while disambiguating

1  2 
builtin-apply.c
setup.c

diff --combined builtin-apply.c
index 0a0b4a9e3f6550b6a4729e94242811dcb6e8d09a,9ee93936627b4df97ee5fea3af74ba0739becb98..da270755a7b9ecafa3cb47d9f6947c6dc5b2531c
@@@ -55,7 -55,7 +55,7 @@@ static enum whitespace_eol 
  } new_whitespace = warn_on_whitespace;
  static int whitespace_error;
  static int squelch_whitespace_errors = 5;
 -static int applied_after_stripping;
 +static int applied_after_fixing_ws;
  static const char *patch_input_file;
  
  static void parse_whitespace_option(const char *option)
@@@ -1661,7 -1661,7 +1661,7 @@@ static int apply_line(char *output, con
        if (add_nl_to_tail)
                output[plen++] = '\n';
        if (fixed)
 -              applied_after_stripping++;
 +              applied_after_fixing_ws++;
        return output + plen - buf;
  }
  
@@@ -1675,7 -1675,6 +1675,7 @@@ static int apply_one_fragment(struct bu
        char *new = xmalloc(size);
        const char *oldlines, *newlines;
        int oldsize = 0, newsize = 0;
 +      int new_blank_lines_at_end = 0;
        unsigned long leading, trailing;
        int pos, lines;
  
                char first;
                int len = linelen(patch, size);
                int plen;
 +              int added_blank_line = 0;
  
                if (!len)
                        break;
                        else if (first == '+')
                                first = '-';
                }
 +
                switch (first) {
                case '\n':
                        /* Newer GNU diff, empty context line */
                                break;
                /* Fall-through for ' ' */
                case '+':
 -                      if (first != '+' || !no_add)
 -                              newsize += apply_line(new + newsize, patch,
 -                                                    plen);
 +                      if (first != '+' || !no_add) {
 +                              int added = apply_line(new + newsize, patch,
 +                                                     plen);
 +                              newsize += added;
 +                              if (first == '+' &&
 +                                  added == 1 && new[newsize-1] == '\n')
 +                                      added_blank_line = 1;
 +                      }
                        break;
                case '@': case '\\':
                        /* Ignore it, we already handled it */
                                error("invalid start of line: '%c'", first);
                        return -1;
                }
 +              if (added_blank_line)
 +                      new_blank_lines_at_end++;
 +              else
 +                      new_blank_lines_at_end = 0;
                patch += len;
                size -= len;
        }
                if (match_beginning && offset)
                        offset = -1;
                if (offset >= 0) {
 -                      int diff = newsize - oldsize;
 -                      unsigned long size = desc->size + diff;
 -                      unsigned long alloc = desc->alloc;
 +                      int diff;
 +                      unsigned long size, alloc;
 +
 +                      if (new_whitespace == strip_whitespace &&
 +                          (desc->size - oldsize - offset == 0)) /* end of file? */
 +                              newsize -= new_blank_lines_at_end;
 +
 +                      diff = newsize - oldsize;
 +                      size = desc->size + diff;
 +                      alloc = desc->alloc;
  
                        /* Warn if it was necessary to reduce the number
                         * of context lines.
@@@ -2508,7 -2489,7 +2508,7 @@@ static void write_out_one_result(struc
         * thing: remove the old, write the new
         */
        if (phase == 0)
-               remove_file(patch, 0);
+               remove_file(patch, patch->is_rename);
        if (phase == 1)
                create_file(patch);
  }
@@@ -2888,17 -2869,18 +2888,17 @@@ int cmd_apply(int argc, const char **ar
                                squelched == 1 ? "" : "s");
                }
                if (new_whitespace == error_on_whitespace)
 -                      die("%d line%s add%s trailing whitespaces.",
 +                      die("%d line%s add%s whitespace errors.",
                            whitespace_error,
                            whitespace_error == 1 ? "" : "s",
                            whitespace_error == 1 ? "s" : "");
 -              if (applied_after_stripping)
 +              if (applied_after_fixing_ws)
                        fprintf(stderr, "warning: %d line%s applied after"
 -                              " stripping trailing whitespaces.\n",
 -                              applied_after_stripping,
 -                              applied_after_stripping == 1 ? "" : "s");
 +                              " fixing whitespace errors.\n",
 +                              applied_after_fixing_ws,
 +                              applied_after_fixing_ws == 1 ? "" : "s");
                else if (whitespace_error)
 -                      fprintf(stderr, "warning: %d line%s add%s trailing"
 -                              " whitespaces.\n",
 +                      fprintf(stderr, "warning: %d line%s add%s whitespace errors.\n",
                                whitespace_error,
                                whitespace_error == 1 ? "" : "s",
                                whitespace_error == 1 ? "s" : "");
diff --combined setup.c
index 4945eb3134c3e047f54e51db25cd0aa81d9c47d7,2b8e8c0e5e1e957615e986efaab289d77c8fc51c..b55b82c99e2f796700ee95abc8bb5a71e01235ab
+++ b/setup.c
@@@ -1,8 -1,4 +1,8 @@@
  #include "cache.h"
 +#include "dir.h"
 +
 +static int inside_git_dir = -1;
 +static int inside_work_tree = -1;
  
  const char *prefix_path(const char *prefix, int len, const char *path)
  {
@@@ -43,7 -39,7 +43,7 @@@
        if (len) {
                int speclen = strlen(path);
                char *n = xmalloc(speclen + len + 1);
 -      
 +
                memcpy(n, prefix, len);
                memcpy(n + len, path, speclen+1);
                path = n;
@@@ -51,7 -47,7 +51,7 @@@
        return path;
  }
  
 -/* 
 +/*
   * Unlike prefix_path, this should be used if the named file does
   * not have to interact with index entry; i.e. name of a random file
   * on the filesystem.
@@@ -99,7 -95,7 +99,7 @@@ void verify_non_filename(const char *pr
        const char *name;
        struct stat st;
  
 -      if (is_inside_git_dir())
 +      if (!is_inside_work_tree() || is_inside_git_dir())
                return;
        if (*arg == '-')
                return; /* flag */
        if (!lstat(name, &st))
                die("ambiguous argument '%s': both revision and filename\n"
                    "Use '--' to separate filenames from revisions", arg);
-       if (errno != ENOENT)
+       if (errno != ENOENT && errno != ENOTDIR)
                die("'%s': %s", arg, strerror(errno));
  }
  
@@@ -174,77 -170,30 +174,77 @@@ static int is_git_directory(const char 
        return 1;
  }
  
 -static int inside_git_dir = -1;
 -
  int is_inside_git_dir(void)
  {
 -      if (inside_git_dir < 0) {
 -              char buffer[1024];
 -
 -              if (is_bare_repository())
 -                      return (inside_git_dir = 1);
 -              if (getcwd(buffer, sizeof(buffer))) {
 -                      const char *git_dir = get_git_dir(), *cwd = buffer;
 -                      while (*git_dir && *git_dir == *cwd) {
 -                              git_dir++;
 -                              cwd++;
 -                      }
 -                      inside_git_dir = !*git_dir;
 -              } else
 -                      inside_git_dir = 0;
 -      }
 +      if (inside_git_dir < 0)
 +              inside_git_dir = is_inside_dir(get_git_dir());
        return inside_git_dir;
  }
  
 +int is_inside_work_tree(void)
 +{
 +      if (inside_work_tree < 0)
 +              inside_work_tree = is_inside_dir(get_git_work_tree());
 +      return inside_work_tree;
 +}
 +
 +/*
 + * If no worktree was given, and we are outside of a default work tree,
 + * now is the time to set it.
 + *
 + * In other words, if the user calls git with something like
 + *
 + *    git --git-dir=/some/where/else/.git bla
 + *
 + * default to /some/where/else as working directory; if the specified
 + * git-dir does not end in "/.git", the cwd is used as working directory.
 + */
 +const char *set_work_tree(const char *dir)
 +{
 +      char dir_buffer[PATH_MAX], *rel = NULL;
 +      static char buffer[PATH_MAX + 1];
 +      int len, suffix_len = strlen(DEFAULT_GIT_DIR_ENVIRONMENT) + 1;
 +
 +      /* strip the variable 'dir' of the postfix "/.git" if it has it */
 +      len = strlen(dir);
 +      if (len > suffix_len &&
 +          !strcmp(dir + len - suffix_len, "/" DEFAULT_GIT_DIR_ENVIRONMENT)) {
 +              if ((len - suffix_len) >= sizeof(dir_buffer))
 +                      die("directory name too long");
 +              memcpy(dir_buffer, dir, len - suffix_len);
 +              dir_buffer[len - suffix_len] = '\0';
 +
 +              /* are we inside the default work tree? */
 +              rel = get_relative_cwd(buffer, sizeof(buffer), dir_buffer);
 +      }
 +
 +      /* if rel is set, the cwd is _not_ the current working tree */
 +      if (rel && *rel) {
 +              if (!is_absolute_path(dir))
 +                      set_git_dir(make_absolute_path(dir));
 +              dir = dir_buffer;
 +              if (chdir(dir))
 +                      die("cannot chdir to %s: %s", dir, strerror(errno));
 +              else
 +                      strcat(rel, "/");
 +              inside_git_dir = 0;
 +      } else {
 +              rel = NULL;
 +              dir = getcwd(buffer, sizeof(buffer));
 +      }
 +      git_work_tree_cfg = xstrdup(dir);
 +      inside_work_tree = 1;
 +
 +      return rel;
 +}
 +
 +/*
 + * We cannot decide in this function whether we are in the work tree or
 + * not, since the config can only be read _after_ this function was called.
 + */
  const char *setup_git_directory_gently(int *nongit_ok)
  {
 +      const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT);
        static char cwd[PATH_MAX+1];
        const char *gitdirenv;
        int len, offset;
        if (gitdirenv) {
                if (PATH_MAX - 40 < strlen(gitdirenv))
                        die("'$%s' too big", GIT_DIR_ENVIRONMENT);
 -              if (is_git_directory(gitdirenv))
 +              if (is_git_directory(gitdirenv)) {
 +                      if (!work_tree_env)
 +                              return set_work_tree(gitdirenv);
                        return NULL;
 +              }
                if (nongit_ok) {
                        *nongit_ok = 1;
                        return NULL;
                die("Not a git repository: '%s'", gitdirenv);
        }
  
 -      if (!getcwd(cwd, sizeof(cwd)-1) || cwd[0] != '/')
 +      if (!getcwd(cwd, sizeof(cwd)-1))
                die("Unable to read current working directory");
  
 +      /*
 +       * Test in the following order (relative to the cwd):
 +       * - .git/
 +       * - ./ (bare)
 +       * - ../.git/
 +       * - ../ (bare)
 +       * - ../../.git/
 +       *   etc.
 +       */
        offset = len = strlen(cwd);
        for (;;) {
 -              if (is_git_directory(".git"))
 +              if (is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT))
                        break;
 +              if (is_git_directory(".")) {
 +                      inside_git_dir = 1;
 +                      if (!work_tree_env)
 +                              inside_work_tree = 0;
 +                      setenv(GIT_DIR_ENVIRONMENT, ".", 1);
 +                      return NULL;
 +              }
                chdir("..");
                do {
                        if (!offset) {
 -                              if (is_git_directory(cwd)) {
 -                                      if (chdir(cwd))
 -                                              die("Cannot come back to cwd");
 -                                      setenv(GIT_DIR_ENVIRONMENT, cwd, 1);
 -                                      inside_git_dir = 1;
 -                                      return NULL;
 -                              }
                                if (nongit_ok) {
                                        if (chdir(cwd))
                                                die("Cannot come back to cwd");
                } while (cwd[--offset] != '/');
        }
  
 +      inside_git_dir = 0;
 +      if (!work_tree_env)
 +              inside_work_tree = 1;
 +      git_work_tree_cfg = xstrndup(cwd, offset);
        if (offset == len)
                return NULL;
  
        offset++;
        cwd[len++] = '/';
        cwd[len] = 0;
 -      inside_git_dir = !prefixcmp(cwd + offset, ".git/");
        return cwd + offset;
  }
  
  int git_config_perm(const char *var, const char *value)
  {
        if (value) {
 +              int i;
                if (!strcmp(value, "umask"))
                        return PERM_UMASK;
                if (!strcmp(value, "group"))
                    !strcmp(value, "world") ||
                    !strcmp(value, "everybody"))
                        return PERM_EVERYBODY;
 +              i = atoi(value);
 +              if (i > 1)
 +                      return i;
        }
        return git_config_bool(var, value);
  }
  
  int check_repository_format_version(const char *var, const char *value)
  {
 -       if (strcmp(var, "core.repositoryformatversion") == 0)
 -               repository_format_version = git_config_int(var, value);
 +      if (strcmp(var, "core.repositoryformatversion") == 0)
 +              repository_format_version = git_config_int(var, value);
        else if (strcmp(var, "core.sharedrepository") == 0)
                shared_repository = git_config_perm(var, value);
 -       return 0;
 +      else if (strcmp(var, "core.bare") == 0) {
 +              is_bare_repository_cfg = git_config_bool(var, value);
 +              if (is_bare_repository_cfg == 1)
 +                      inside_work_tree = -1;
 +      } else if (strcmp(var, "core.worktree") == 0) {
 +              if (git_work_tree_cfg)
 +                      free(git_work_tree_cfg);
 +              git_work_tree_cfg = xstrdup(value);
 +              inside_work_tree = -1;
 +      }
 +      return 0;
  }
  
  int check_repository_format(void)
@@@ -372,16 -292,5 +372,16 @@@ const char *setup_git_directory(void
  {
        const char *retval = setup_git_directory_gently(NULL);
        check_repository_format();
 +
 +      /* If the work tree is not the default one, recompute prefix */
 +      if (inside_work_tree < 0) {
 +              static char buffer[PATH_MAX + 1];
 +              char *rel;
 +              if (retval && chdir(retval))
 +                      die ("Could not jump back into original cwd");
 +              rel = get_relative_cwd(buffer, PATH_MAX, get_git_work_tree());
 +              return rel && *rel ? strcat(rel, "/") : NULL;
 +      }
 +
        return retval;
  }