Merge branch 'bw/pathspec-cleanup'
authorJunio C Hamano <gitster@pobox.com>
Wed, 18 Jan 2017 23:12:14 +0000 (15:12 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 18 Jan 2017 23:12:15 +0000 (15:12 -0800)
Code clean-up in the pathspec API.

* bw/pathspec-cleanup:
pathspec: rename prefix_pathspec to init_pathspec_item
pathspec: small readability changes
pathspec: create strip submodule slash helpers
pathspec: create parse_element_magic helper
pathspec: create parse_long_magic function
pathspec: create parse_short_magic function
pathspec: factor global magic into its own function
pathspec: simpler logic to prefix original pathspec elements
pathspec: always show mnemonic and name in unsupported_magic
pathspec: remove unused variable from unsupported_magic
pathspec: copy and free owned memory
pathspec: remove the deprecated get_pathspec function
ls-tree: convert show_recursive to use the pathspec struct interface
dir: convert fill_directory to use the pathspec struct interface
dir: remove struct path_simplify
mv: remove use of deprecated 'get_pathspec()'

1  2 
builtin/mv.c
cache.h
dir.c
diff --combined builtin/mv.c
index 43adf92ba64426a2f312cd6133276a98b20855f1,4e86dc5234ee6258b2513b410365de94fa9f6272..61d20037add7cf56df721f8d69612b50412f94e9
@@@ -4,6 -4,7 +4,7 @@@
   * Copyright (C) 2006 Johannes Schindelin
   */
  #include "builtin.h"
+ #include "pathspec.h"
  #include "lockfile.h"
  #include "dir.h"
  #include "cache-tree.h"
@@@ -19,31 -20,42 +20,42 @@@ static const char * const builtin_mv_us
  #define DUP_BASENAME 1
  #define KEEP_TRAILING_SLASH 2
  
- static const char **internal_copy_pathspec(const char *prefix,
-                                          const char **pathspec,
-                                          int count, unsigned flags)
+ static const char **internal_prefix_pathspec(const char *prefix,
+                                            const char **pathspec,
+                                            int count, unsigned flags)
  {
        int i;
        const char **result;
+       int prefixlen = prefix ? strlen(prefix) : 0;
        ALLOC_ARRAY(result, count + 1);
-       COPY_ARRAY(result, pathspec, count);
-       result[count] = NULL;
+       /* Create an intermediate copy of the pathspec based on the flags */
        for (i = 0; i < count; i++) {
-               int length = strlen(result[i]);
+               int length = strlen(pathspec[i]);
                int to_copy = length;
+               char *it;
                while (!(flags & KEEP_TRAILING_SLASH) &&
-                      to_copy > 0 && is_dir_sep(result[i][to_copy - 1]))
+                      to_copy > 0 && is_dir_sep(pathspec[i][to_copy - 1]))
                        to_copy--;
-               if (to_copy != length || flags & DUP_BASENAME) {
-                       char *it = xmemdupz(result[i], to_copy);
-                       if (flags & DUP_BASENAME) {
-                               result[i] = xstrdup(basename(it));
-                               free(it);
-                       } else
-                               result[i] = it;
+               it = xmemdupz(pathspec[i], to_copy);
+               if (flags & DUP_BASENAME) {
+                       result[i] = xstrdup(basename(it));
+                       free(it);
+               } else {
+                       result[i] = it;
                }
        }
-       return get_pathspec(prefix, result);
+       result[count] = NULL;
+       /* Prefix the pathspec and free the old intermediate strings */
+       for (i = 0; i < count; i++) {
+               const char *match = prefix_path(prefix, prefixlen, result[i]);
+               free((char *) result[i]);
+               result[i] = match;
+       }
+       return result;
  }
  
  static const char *add_slash(const char *path)
@@@ -126,11 -138,11 +138,11 @@@ int cmd_mv(int argc, const char **argv
        if (--argc < 1)
                usage_with_options(builtin_mv_usage, builtin_mv_options);
  
 -      hold_locked_index(&lock_file, 1);
 +      hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
        if (read_cache() < 0)
                die(_("index file corrupt"));
  
-       source = internal_copy_pathspec(prefix, argv, argc, 0);
+       source = internal_prefix_pathspec(prefix, argv, argc, 0);
        modes = xcalloc(argc, sizeof(enum update_mode));
        /*
         * Keep trailing slash, needed to let
        flags = KEEP_TRAILING_SLASH;
        if (argc == 1 && is_directory(argv[0]) && !is_directory(argv[1]))
                flags = 0;
-       dest_path = internal_copy_pathspec(prefix, argv + argc, 1, flags);
+       dest_path = internal_prefix_pathspec(prefix, argv + argc, 1, flags);
        submodule_gitfile = xcalloc(argc, sizeof(char *));
  
        if (dest_path[0][0] == '\0')
                /* special case: "." was normalized to "" */
-               destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
+               destination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
        else if (!lstat(dest_path[0], &st) &&
                        S_ISDIR(st.st_mode)) {
                dest_path[0] = add_slash(dest_path[0]);
-               destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
+               destination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
        } else {
                if (argc != 1)
                        die(_("destination '%s' is not a directory"), dest_path[0]);
diff --combined cache.h
index c74df701276e92aaae71dee36da96197b2dc3316,0f80e01bde5751e3a131a5fd6b4b09779722311f..40f7ddd24710b8d16d34fd00c9a0841fc346ec5c
+++ b/cache.h
@@@ -514,7 -514,6 +514,6 @@@ extern void set_git_work_tree(const cha
  
  #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
  
- extern const char **get_pathspec(const char *prefix, const char **pathspec);
  extern void setup_work_tree(void);
  extern const char *setup_git_directory_gently(int *);
  extern const char *setup_git_directory(void);
@@@ -670,7 -669,7 +669,7 @@@ extern const char *git_attributes_file
  extern const char *git_hooks_path;
  extern int zlib_compression_level;
  extern int core_compression_level;
 -extern int core_compression_seen;
 +extern int pack_compression_level;
  extern size_t packed_git_window_size;
  extern size_t packed_git_limit;
  extern size_t delta_base_cache_limit;
@@@ -1064,11 -1063,8 +1063,11 @@@ static inline int is_absolute_path(cons
        return is_dir_sep(path[0]) || has_dos_drive_prefix(path);
  }
  int is_directory(const char *);
 +char *strbuf_realpath(struct strbuf *resolved, const char *path,
 +                    int die_on_error);
  const char *real_path(const char *path);
  const char *real_path_if_valid(const char *path);
 +char *real_pathdup(const char *path);
  const char *absolute_path(const char *path);
  const char *remove_leading_path(const char *in, const char *prefix);
  const char *relative_path(const char *in, const char *prefix, struct strbuf *sb);
@@@ -1128,8 -1124,7 +1127,8 @@@ extern int write_sha1_file(const void *
  extern int hash_sha1_file_literally(const void *buf, unsigned long len, const char *type, unsigned char *sha1, unsigned flags);
  extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
  extern int force_object_loose(const unsigned char *sha1, time_t mtime);
 -extern int git_open(const char *name);
 +extern int git_open_cloexec(const char *name, int flags);
 +#define git_open(name) git_open_cloexec(name, O_RDONLY)
  extern void *map_sha1_file(const unsigned char *sha1, unsigned long *size);
  extern int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz);
  extern int parse_sha1_header(const char *hdr, unsigned long *sizep);
@@@ -1694,8 -1689,6 +1693,8 @@@ extern int git_default_config(const cha
  extern int git_config_from_file(config_fn_t fn, const char *, void *);
  extern int git_config_from_mem(config_fn_t fn, const enum config_origin_type,
                                        const char *name, const char *buf, size_t len, void *data);
 +extern int git_config_from_blob_sha1(config_fn_t fn, const char *name,
 +                                   const unsigned char *sha1, void *data);
  extern void git_config_push_parameter(const char *text);
  extern int git_config_from_parameters(config_fn_t fn, void *data);
  extern void git_config(config_fn_t fn, void *);
diff --combined dir.c
index d872cc1570989bf22d8bd5d741d817372e76018f,bc5ff72167a8e1d0db4461a62dd8fe78c6a0f93f..4ac63bc940fa043fe82002dd6c282b0b5abcbad8
--- 1/dir.c
--- 2/dir.c
+++ b/dir.c
  #include "varint.h"
  #include "ewah/ewok.h"
  
- struct path_simplify {
-       int len;
-       const char *path;
- };
  /*
   * Tells read_directory_recursive how a file or directory should be treated.
   * Values are ordered by significance, e.g. if a directory contains both
@@@ -50,7 -45,7 +45,7 @@@ struct cached_dir 
  
  static enum path_treatment read_directory_recursive(struct dir_struct *dir,
        const char *path, int len, struct untracked_cache_dir *untracked,
-       int check_only, const struct path_simplify *simplify);
+       int check_only, const struct pathspec *pathspec);
  static int get_dtype(struct dirent *de, const char *path, int len);
  
  int fspathcmp(const char *a, const char *b)
@@@ -179,17 -174,21 +174,21 @@@ char *common_prefix(const struct pathsp
  
  int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)
  {
-       size_t len;
+       char *prefix;
+       size_t prefix_len;
  
        /*
         * Calculate common prefix for the pathspec, and
         * use that to optimize the directory walk
         */
-       len = common_prefix_len(pathspec);
+       prefix = common_prefix(pathspec);
+       prefix_len = prefix ? strlen(prefix) : 0;
  
        /* Read the directory and prune it */
-       read_directory(dir, pathspec->nr ? pathspec->_raw[0] : "", len, pathspec);
-       return len;
+       read_directory(dir, prefix, prefix_len, pathspec);
+       free(prefix);
+       return prefix_len;
  }
  
  int within_depth(const char *name, int namelen,
@@@ -1312,7 -1311,7 +1311,7 @@@ static enum exist_status directory_exis
  static enum path_treatment treat_directory(struct dir_struct *dir,
        struct untracked_cache_dir *untracked,
        const char *dirname, int len, int baselen, int exclude,
-       const struct path_simplify *simplify)
+       const struct pathspec *pathspec)
  {
        /* The "len-1" is to strip the final '/' */
        switch (directory_exists_in_index(dirname, len-1)) {
        untracked = lookup_untracked(dir->untracked, untracked,
                                     dirname + baselen, len - baselen);
        return read_directory_recursive(dir, dirname, len,
-                                       untracked, 1, simplify);
+                                       untracked, 1, pathspec);
  }
  
  /*
   * reading - if the path cannot possibly be in the pathspec,
   * return true, and we'll skip it early.
   */
- static int simplify_away(const char *path, int pathlen, const struct path_simplify *simplify)
+ static int simplify_away(const char *path, int pathlen,
+                        const struct pathspec *pathspec)
  {
-       if (simplify) {
-               for (;;) {
-                       const char *match = simplify->path;
-                       int len = simplify->len;
+       int i;
  
-                       if (!match)
-                               break;
-                       if (len > pathlen)
-                               len = pathlen;
-                       if (!memcmp(path, match, len))
-                               return 0;
-                       simplify++;
-               }
-               return 1;
+       if (!pathspec || !pathspec->nr)
+               return 0;
+       GUARD_PATHSPEC(pathspec,
+                      PATHSPEC_FROMTOP |
+                      PATHSPEC_MAXDEPTH |
+                      PATHSPEC_LITERAL |
+                      PATHSPEC_GLOB |
+                      PATHSPEC_ICASE |
+                      PATHSPEC_EXCLUDE);
+       for (i = 0; i < pathspec->nr; i++) {
+               const struct pathspec_item *item = &pathspec->items[i];
+               int len = item->nowildcard_len;
+               if (len > pathlen)
+                       len = pathlen;
+               if (!ps_strncmp(item, item->match, path, len))
+                       return 0;
        }
-       return 0;
+       return 1;
  }
  
  /*
   *   2. the path is a directory prefix of some element in the
   *      pathspec
   */
- static int exclude_matches_pathspec(const char *path, int len,
-               const struct path_simplify *simplify)
- {
-       if (simplify) {
-               for (; simplify->path; simplify++) {
-                       if (len == simplify->len
-                           && !memcmp(path, simplify->path, len))
-                               return 1;
-                       if (len < simplify->len
-                           && simplify->path[len] == '/'
-                           && !memcmp(path, simplify->path, len))
-                               return 1;
-               }
+ static int exclude_matches_pathspec(const char *path, int pathlen,
+                                   const struct pathspec *pathspec)
+ {
+       int i;
+       if (!pathspec || !pathspec->nr)
+               return 0;
+       GUARD_PATHSPEC(pathspec,
+                      PATHSPEC_FROMTOP |
+                      PATHSPEC_MAXDEPTH |
+                      PATHSPEC_LITERAL |
+                      PATHSPEC_GLOB |
+                      PATHSPEC_ICASE |
+                      PATHSPEC_EXCLUDE);
+       for (i = 0; i < pathspec->nr; i++) {
+               const struct pathspec_item *item = &pathspec->items[i];
+               int len = item->nowildcard_len;
+               if (len == pathlen &&
+                   !ps_strncmp(item, item->match, path, pathlen))
+                       return 1;
+               if (len > pathlen &&
+                   item->match[pathlen] == '/' &&
+                   !ps_strncmp(item, item->match, path, pathlen))
+                       return 1;
        }
        return 0;
  }
@@@ -1460,7 -1482,7 +1482,7 @@@ static enum path_treatment treat_one_pa
                                          struct untracked_cache_dir *untracked,
                                          struct strbuf *path,
                                          int baselen,
-                                         const struct path_simplify *simplify,
+                                         const struct pathspec *pathspec,
                                          int dtype, struct dirent *de)
  {
        int exclude;
        case DT_DIR:
                strbuf_addch(path, '/');
                return treat_directory(dir, untracked, path->buf, path->len,
-                                      baselen, exclude, simplify);
+                                      baselen, exclude, pathspec);
        case DT_REG:
        case DT_LNK:
                return exclude ? path_excluded : path_untracked;
@@@ -1524,7 -1546,7 +1546,7 @@@ static enum path_treatment treat_path_f
                                           struct cached_dir *cdir,
                                           struct strbuf *path,
                                           int baselen,
-                                          const struct path_simplify *simplify)
+                                          const struct pathspec *pathspec)
  {
        strbuf_setlen(path, baselen);
        if (!cdir->ucd) {
                 * with check_only set.
                 */
                return read_directory_recursive(dir, path->buf, path->len,
-                                               cdir->ucd, 1, simplify);
+                                               cdir->ucd, 1, pathspec);
        /*
         * We get path_recurse in the first run when
         * directory_exists_in_index() returns index_nonexistent. We
@@@ -1556,23 -1578,23 +1578,23 @@@ static enum path_treatment treat_path(s
                                      struct cached_dir *cdir,
                                      struct strbuf *path,
                                      int baselen,
-                                     const struct path_simplify *simplify)
+                                     const struct pathspec *pathspec)
  {
        int dtype;
        struct dirent *de = cdir->de;
  
        if (!de)
                return treat_path_fast(dir, untracked, cdir, path,
-                                      baselen, simplify);
+                                      baselen, pathspec);
        if (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, ".git"))
                return path_none;
        strbuf_setlen(path, baselen);
        strbuf_addstr(path, de->d_name);
-       if (simplify_away(path->buf, path->len, simplify))
+       if (simplify_away(path->buf, path->len, pathspec))
                return path_none;
  
        dtype = DTYPE(de);
-       return treat_one_path(dir, untracked, path, baselen, simplify, dtype, de);
+       return treat_one_path(dir, untracked, path, baselen, pathspec, dtype, de);
  }
  
  static void add_untracked(struct untracked_cache_dir *dir, const char *name)
@@@ -1703,7 -1725,7 +1725,7 @@@ static void close_cached_dir(struct cac
  static enum path_treatment read_directory_recursive(struct dir_struct *dir,
                                    const char *base, int baselen,
                                    struct untracked_cache_dir *untracked, int check_only,
-                                   const struct path_simplify *simplify)
+                                   const struct pathspec *pathspec)
  {
        struct cached_dir cdir;
        enum path_treatment state, subdir_state, dir_state = path_none;
  
        while (!read_cached_dir(&cdir)) {
                /* check how the file or directory should be treated */
-               state = treat_path(dir, untracked, &cdir, &path, baselen, simplify);
+               state = treat_path(dir, untracked, &cdir, &path,
+                                  baselen, pathspec);
  
                if (state > dir_state)
                        dir_state = state;
                                              path.buf + baselen,
                                              path.len - baselen);
                        subdir_state =
-                               read_directory_recursive(dir, path.buf, path.len,
-                                                        ud, check_only, simplify);
+                               read_directory_recursive(dir, path.buf,
+                                                        path.len, ud,
+                                                        check_only, pathspec);
                        if (subdir_state > dir_state)
                                dir_state = subdir_state;
                }
                        else if ((dir->flags & DIR_SHOW_IGNORED_TOO) ||
                                ((dir->flags & DIR_COLLECT_IGNORED) &&
                                exclude_matches_pathspec(path.buf, path.len,
-                                       simplify)))
+                                                        pathspec)))
                                dir_add_ignored(dir, path.buf, path.len);
                        break;
  
@@@ -1787,36 -1811,9 +1811,9 @@@ static int cmp_name(const void *p1, con
        return name_compare(e1->name, e1->len, e2->name, e2->len);
  }
  
- static struct path_simplify *create_simplify(const char **pathspec)
- {
-       int nr, alloc = 0;
-       struct path_simplify *simplify = NULL;
-       if (!pathspec)
-               return NULL;
-       for (nr = 0 ; ; nr++) {
-               const char *match;
-               ALLOC_GROW(simplify, nr + 1, alloc);
-               match = *pathspec++;
-               if (!match)
-                       break;
-               simplify[nr].path = match;
-               simplify[nr].len = simple_length(match);
-       }
-       simplify[nr].path = NULL;
-       simplify[nr].len = 0;
-       return simplify;
- }
- static void free_simplify(struct path_simplify *simplify)
- {
-       free(simplify);
- }
  static int treat_leading_path(struct dir_struct *dir,
                              const char *path, int len,
-                             const struct path_simplify *simplify)
+                             const struct pathspec *pathspec)
  {
        struct strbuf sb = STRBUF_INIT;
        int baselen, rc = 0;
                strbuf_add(&sb, path, baselen);
                if (!is_directory(sb.buf))
                        break;
-               if (simplify_away(sb.buf, sb.len, simplify))
+               if (simplify_away(sb.buf, sb.len, pathspec))
                        break;
-               if (treat_one_path(dir, NULL, &sb, baselen, simplify,
+               if (treat_one_path(dir, NULL, &sb, baselen, pathspec,
                                   DT_DIR, NULL) == path_none)
                        break; /* do not recurse into it */
                if (len <= baselen) {
@@@ -2010,33 -2007,14 +2007,14 @@@ static struct untracked_cache_dir *vali
        return root;
  }
  
- int read_directory(struct dir_struct *dir, const char *path, int len, const struct pathspec *pathspec)
+ int read_directory(struct dir_struct *dir, const char *path,
+                  int len, const struct pathspec *pathspec)
  {
-       struct path_simplify *simplify;
        struct untracked_cache_dir *untracked;
  
-       /*
-        * Check out create_simplify()
-        */
-       if (pathspec)
-               GUARD_PATHSPEC(pathspec,
-                              PATHSPEC_FROMTOP |
-                              PATHSPEC_MAXDEPTH |
-                              PATHSPEC_LITERAL |
-                              PATHSPEC_GLOB |
-                              PATHSPEC_ICASE |
-                              PATHSPEC_EXCLUDE);
        if (has_symlink_leading_path(path, len))
                return dir->nr;
  
-       /*
-        * exclude patterns are treated like positive ones in
-        * create_simplify. Usually exclude patterns should be a
-        * subset of positive ones, which has no impacts on
-        * create_simplify().
-        */
-       simplify = create_simplify(pathspec ? pathspec->_raw : NULL);
        untracked = validate_untracked_cache(dir, len, pathspec);
        if (!untracked)
                /*
                 * e.g. prep_exclude()
                 */
                dir->untracked = NULL;
-       if (!len || treat_leading_path(dir, path, len, simplify))
-               read_directory_recursive(dir, path, len, untracked, 0, simplify);
-       free_simplify(simplify);
+       if (!len || treat_leading_path(dir, path, len, pathspec))
+               read_directory_recursive(dir, path, len, untracked, 0, pathspec);
        QSORT(dir->entries, dir->nr, cmp_name);
        QSORT(dir->ignored, dir->ignored_nr, cmp_name);
        if (dir->untracked) {
@@@ -2748,40 -2725,3 +2725,40 @@@ void untracked_cache_add_to_index(struc
  {
        untracked_cache_invalidate_path(istate, path);
  }
 +
 +/* Update gitfile and core.worktree setting to connect work tree and git dir */
 +void connect_work_tree_and_git_dir(const char *work_tree_, const char *git_dir_)
 +{
 +      struct strbuf file_name = STRBUF_INIT;
 +      struct strbuf rel_path = STRBUF_INIT;
 +      char *git_dir = xstrdup(real_path(git_dir_));
 +      char *work_tree = xstrdup(real_path(work_tree_));
 +
 +      /* Update gitfile */
 +      strbuf_addf(&file_name, "%s/.git", work_tree);
 +      write_file(file_name.buf, "gitdir: %s",
 +                 relative_path(git_dir, work_tree, &rel_path));
 +
 +      /* Update core.worktree setting */
 +      strbuf_reset(&file_name);
 +      strbuf_addf(&file_name, "%s/config", git_dir);
 +      git_config_set_in_file(file_name.buf, "core.worktree",
 +                             relative_path(work_tree, git_dir, &rel_path));
 +
 +      strbuf_release(&file_name);
 +      strbuf_release(&rel_path);
 +      free(work_tree);
 +      free(git_dir);
 +}
 +
 +/*
 + * Migrate the git directory of the given path from old_git_dir to new_git_dir.
 + */
 +void relocate_gitdir(const char *path, const char *old_git_dir, const char *new_git_dir)
 +{
 +      if (rename(old_git_dir, new_git_dir) < 0)
 +              die_errno(_("could not migrate git directory from '%s' to '%s'"),
 +                      old_git_dir, new_git_dir);
 +
 +      connect_work_tree_and_git_dir(path, new_git_dir);
 +}