Merge branch 'mv/parseopt-ls-files'
authorJunio C Hamano <gitster@pobox.com>
Fri, 20 Mar 2009 21:30:51 +0000 (14:30 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 20 Mar 2009 21:30:51 +0000 (14:30 -0700)
* mv/parseopt-ls-files:
ls-files: fix broken --no-empty-directory
t3000: use test_cmp instead of diff
parse-opt: migrate builtin-ls-files.
Turn the flags in struct dir_struct into a single variable

Conflicts:
builtin-ls-files.c
t/t3000-ls-files-others.sh

1  2 
builtin-add.c
builtin-checkout.c
builtin-ls-files.c
dir.c
wt-status.c
diff --combined builtin-add.c
index 7ddb65932dd6ae11589c5063335b857ecd3298d9,c986a3ada1ad09f653b734e770ee871a255c5086..cb67d2c17e4017e8deede61b30c0eb7c8c60ac1e
@@@ -15,7 -15,7 +15,7 @@@ static const char * const builtin_add_u
        "git add [options] [--] <filepattern>...",
        NULL
  };
 -static int patch_interactive = 0, add_interactive = 0;
 +static int patch_interactive, add_interactive;
  static int take_worktree_changes;
  
  static void fill_pathspec_matches(const char **pathspec, char *seen, int specs)
@@@ -104,7 -104,7 +104,7 @@@ static void fill_directory(struct dir_s
        /* Set up the default git porcelain excludes */
        memset(dir, 0, sizeof(*dir));
        if (!ignored_too) {
-               dir->collect_ignored = 1;
+               dir->flags |= DIR_COLLECT_IGNORED;
                setup_standard_excludes(dir);
        }
  
@@@ -148,7 -148,7 +148,7 @@@ static const char **validate_pathspec(i
        if (pathspec) {
                const char **p;
                for (p = pathspec; *p; p++) {
 -                      if (has_symlink_leading_path(strlen(*p), *p)) {
 +                      if (has_symlink_leading_path(*p, strlen(*p))) {
                                int len = prefix ? strlen(prefix) : 0;
                                die("'%s' is beyond a symbolic link", *p + len);
                        }
diff --combined builtin-checkout.c
index c315f63398bac5dd3fd465af881caa5f3b9c9184,5b4921d48c43359624c4232ba971f0167c439317..9fdfc58d1a198164727431352e083585d91f2d30
@@@ -295,8 -295,6 +295,8 @@@ static void show_local_changes(struct o
        init_revisions(&rev, NULL);
        rev.abbrev = 0;
        rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS;
 +      if (diff_setup_done(&rev.diffopt) < 0)
 +              die("diff_setup_done failed");
        add_pending_object(&rev, head, NULL);
        run_diff_index(&rev, 0);
  }
@@@ -407,7 -405,7 +407,7 @@@ static int merge_working_tree(struct ch
                topts.verbose_update = !opts->quiet;
                topts.fn = twoway_merge;
                topts.dir = xcalloc(1, sizeof(*topts.dir));
-               topts.dir->show_ignored = 1;
+               topts.dir->flags |= DIR_SHOW_IGNORED;
                topts.dir->exclude_per_dir = ".gitignore";
                tree = parse_tree_indirect(old->commit->object.sha1);
                init_tree_desc(&trees[0], tree->buffer, tree->size);
diff --combined builtin-ls-files.c
index ca6f33d0466572863db7dbd4c3079dcb06caa4e0,437c366c9e7875aa5003419f1eb03c600b1a1f6f..88e2697aebf11399baf9f9c8b5a63b06a0f83c1d
@@@ -10,6 -10,7 +10,7 @@@
  #include "dir.h"
  #include "builtin.h"
  #include "tree.h"
+ #include "parse-options.h"
  
  static int abbrev;
  static int show_deleted;
@@@ -28,6 -29,7 +29,7 @@@ static const char **pathspec
  static int error_unmatch;
  static char *ps_matched;
  static const char *with_tree;
+ static int exc_given;
  
  static const char *tag_cached = "";
  static const char *tag_unmerged = "";
@@@ -174,7 -176,8 +176,8 @@@ static void show_files(struct dir_struc
                for (i = 0; i < active_nr; i++) {
                        struct cache_entry *ce = active_cache[i];
                        int dtype = ce_to_dtype(ce);
-                       if (excluded(dir, ce->name, &dtype) != dir->show_ignored)
+                       if (excluded(dir, ce->name, &dtype) !=
+                                       !!(dir->flags & DIR_SHOW_IGNORED))
                                continue;
                        if (show_unmerged && !ce_stage(ce))
                                continue;
                        struct stat st;
                        int err;
                        int dtype = ce_to_dtype(ce);
-                       if (excluded(dir, ce->name, &dtype) != dir->show_ignored)
+                       if (excluded(dir, ce->name, &dtype) !=
+                                       !!(dir->flags & DIR_SHOW_IGNORED))
                                continue;
                        if (ce->ce_flags & CE_UPDATE)
                                continue;
@@@ -374,157 -378,139 +378,139 @@@ int report_path_error(const char *ps_ma
        return errors;
  }
  
- static const char ls_files_usage[] =
-       "git ls-files [-z] [-t] [-v] (--[cached|deleted|others|stage|unmerged|killed|modified])* "
-       "[ --ignored ] [--exclude=<pattern>] [--exclude-from=<file>] "
-       "[ --exclude-per-directory=<filename> ] [--exclude-standard] "
-       "[--full-name] [--abbrev] [--] [<file>]*";
+ static const char * const ls_files_usage[] = {
+       "git ls-files [options] [<file>]*",
+       NULL
+ };
+ static int option_parse_z(const struct option *opt,
+                         const char *arg, int unset)
+ {
+       line_terminator = unset ? '\n' : '\0';
+       return 0;
+ }
+ static int option_parse_exclude(const struct option *opt,
+                               const char *arg, int unset)
+ {
+       struct exclude_list *list = opt->value;
+       exc_given = 1;
+       add_exclude(arg, "", 0, list);
+       return 0;
+ }
+ static int option_parse_exclude_from(const struct option *opt,
+                                    const char *arg, int unset)
+ {
+       struct dir_struct *dir = opt->value;
+       exc_given = 1;
+       add_excludes_from_file(dir, arg);
+       return 0;
+ }
+ static int option_parse_exclude_standard(const struct option *opt,
+                                        const char *arg, int unset)
+ {
+       struct dir_struct *dir = opt->value;
+       exc_given = 1;
+       setup_standard_excludes(dir);
+       return 0;
+ }
  
  int cmd_ls_files(int argc, const char **argv, const char *prefix)
  {
-       int i;
-       int exc_given = 0, require_work_tree = 0;
+       int require_work_tree = 0, show_tag = 0;
        struct dir_struct dir;
+       struct option builtin_ls_files_options[] = {
+               { OPTION_CALLBACK, 'z', NULL, NULL, NULL,
+                       "paths are separated with NUL character",
+                       PARSE_OPT_NOARG, option_parse_z },
+               OPT_BOOLEAN('t', NULL, &show_tag,
+                       "identify the file status with tags"),
+               OPT_BOOLEAN('v', NULL, &show_valid_bit,
+                       "use lowercase letters for 'assume unchanged' files"),
+               OPT_BOOLEAN('c', "cached", &show_cached,
+                       "show cached files in the output (default)"),
+               OPT_BOOLEAN('d', "deleted", &show_deleted,
+                       "show deleted files in the output"),
+               OPT_BOOLEAN('m', "modified", &show_modified,
+                       "show modified files in the output"),
+               OPT_BOOLEAN('o', "others", &show_others,
+                       "show other files in the output"),
+               OPT_BIT('i', "ignored", &dir.flags,
+                       "show ignored files in the output",
+                       DIR_SHOW_IGNORED),
+               OPT_BOOLEAN('s', "stage", &show_stage,
+                       "show staged contents' object name in the output"),
+               OPT_BOOLEAN('k', "killed", &show_killed,
+                       "show files on the filesystem that need to be removed"),
+               OPT_BIT(0, "directory", &dir.flags,
+                       "show 'other' directories' name only",
+                       DIR_SHOW_OTHER_DIRECTORIES),
+               OPT_BIT(0, "no-empty-directory", &dir.flags,
+                       "don't show empty directories",
+                       DIR_HIDE_EMPTY_DIRECTORIES),
+               OPT_BOOLEAN('u', "unmerged", &show_unmerged,
+                       "show unmerged files in the output"),
+               { OPTION_CALLBACK, 'x', "exclude", &dir.exclude_list[EXC_CMDL], "pattern",
+                       "skip files matching pattern",
+                       0, option_parse_exclude },
+               { OPTION_CALLBACK, 'X', "exclude-from", &dir, "file",
+                       "exclude patterns are read from <file>",
+                       0, option_parse_exclude_from },
+               OPT_STRING(0, "exclude-per-directory", &dir.exclude_per_dir, "file",
+                       "read additional per-directory exclude patterns in <file>"),
+               { OPTION_CALLBACK, 0, "exclude-standard", &dir, NULL,
+                       "add the standard git exclusions",
+                       PARSE_OPT_NOARG, option_parse_exclude_standard },
+               { OPTION_SET_INT, 0, "full-name", &prefix_offset, NULL,
+                       "make the output relative to the project top directory",
+                       PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL },
+               OPT_BOOLEAN(0, "error-unmatch", &error_unmatch,
+                       "if any <file> is not in the index, treat this as an error"),
+               OPT_STRING(0, "with-tree", &with_tree, "tree-ish",
+                       "pretend that paths removed since <tree-ish> are still present"),
+               OPT__ABBREV(&abbrev),
+               OPT_END()
+       };
  
        memset(&dir, 0, sizeof(dir));
        if (prefix)
                prefix_offset = strlen(prefix);
        git_config(git_default_config, NULL);
  
-       for (i = 1; i < argc; i++) {
-               const char *arg = argv[i];
-               if (!strcmp(arg, "--")) {
-                       i++;
-                       break;
-               }
-               if (!strcmp(arg, "-z")) {
-                       line_terminator = 0;
-                       continue;
-               }
-               if (!strcmp(arg, "-t") || !strcmp(arg, "-v")) {
-                       tag_cached = "H ";
-                       tag_unmerged = "M ";
-                       tag_removed = "R ";
-                       tag_modified = "C ";
-                       tag_other = "? ";
-                       tag_killed = "K ";
-                       if (arg[1] == 'v')
-                               show_valid_bit = 1;
-                       continue;
-               }
-               if (!strcmp(arg, "-c") || !strcmp(arg, "--cached")) {
-                       show_cached = 1;
-                       continue;
-               }
-               if (!strcmp(arg, "-d") || !strcmp(arg, "--deleted")) {
-                       show_deleted = 1;
-                       require_work_tree = 1;
-                       continue;
-               }
-               if (!strcmp(arg, "-m") || !strcmp(arg, "--modified")) {
-                       show_modified = 1;
-                       require_work_tree = 1;
-                       continue;
-               }
-               if (!strcmp(arg, "-o") || !strcmp(arg, "--others")) {
-                       show_others = 1;
-                       require_work_tree = 1;
-                       continue;
-               }
-               if (!strcmp(arg, "-i") || !strcmp(arg, "--ignored")) {
-                       dir.show_ignored = 1;
-                       require_work_tree = 1;
-                       continue;
-               }
-               if (!strcmp(arg, "-s") || !strcmp(arg, "--stage")) {
-                       show_stage = 1;
-                       continue;
-               }
-               if (!strcmp(arg, "-k") || !strcmp(arg, "--killed")) {
-                       show_killed = 1;
-                       require_work_tree = 1;
-                       continue;
-               }
-               if (!strcmp(arg, "--directory")) {
-                       dir.show_other_directories = 1;
-                       continue;
-               }
-               if (!strcmp(arg, "--no-empty-directory")) {
-                       dir.hide_empty_directories = 1;
-                       continue;
-               }
-               if (!strcmp(arg, "-u") || !strcmp(arg, "--unmerged")) {
-                       /* There's no point in showing unmerged unless
-                        * you also show the stage information.
-                        */
-                       show_stage = 1;
-                       show_unmerged = 1;
-                       continue;
-               }
-               if (!strcmp(arg, "-x") && i+1 < argc) {
-                       exc_given = 1;
-                       add_exclude(argv[++i], "", 0, &dir.exclude_list[EXC_CMDL]);
-                       continue;
-               }
-               if (!prefixcmp(arg, "--exclude=")) {
-                       exc_given = 1;
-                       add_exclude(arg+10, "", 0, &dir.exclude_list[EXC_CMDL]);
-                       continue;
-               }
-               if (!strcmp(arg, "-X") && i+1 < argc) {
-                       exc_given = 1;
-                       add_excludes_from_file(&dir, argv[++i]);
-                       continue;
-               }
-               if (!prefixcmp(arg, "--exclude-from=")) {
-                       exc_given = 1;
-                       add_excludes_from_file(&dir, arg+15);
-                       continue;
-               }
-               if (!prefixcmp(arg, "--exclude-per-directory=")) {
-                       exc_given = 1;
-                       dir.exclude_per_dir = arg + 24;
-                       continue;
-               }
-               if (!strcmp(arg, "--exclude-standard")) {
-                       exc_given = 1;
-                       setup_standard_excludes(&dir);
-                       continue;
-               }
-               if (!strcmp(arg, "--full-name")) {
-                       prefix_offset = 0;
-                       continue;
-               }
-               if (!strcmp(arg, "--error-unmatch")) {
-                       error_unmatch = 1;
-                       continue;
-               }
-               if (!prefixcmp(arg, "--with-tree=")) {
-                       with_tree = arg + 12;
-                       continue;
-               }
-               if (!prefixcmp(arg, "--abbrev=")) {
-                       abbrev = strtoul(arg+9, NULL, 10);
-                       if (abbrev && abbrev < MINIMUM_ABBREV)
-                               abbrev = MINIMUM_ABBREV;
-                       else if (abbrev > 40)
-                               abbrev = 40;
-                       continue;
-               }
-               if (!strcmp(arg, "--abbrev")) {
-                       abbrev = DEFAULT_ABBREV;
-                       continue;
-               }
-               if (*arg == '-')
-                       usage(ls_files_usage);
-               break;
+       argc = parse_options(argc, argv, builtin_ls_files_options,
+                       ls_files_usage, 0);
+       if (show_tag || show_valid_bit) {
+               tag_cached = "H ";
+               tag_unmerged = "M ";
+               tag_removed = "R ";
+               tag_modified = "C ";
+               tag_other = "? ";
+               tag_killed = "K ";
        }
 -      if (show_modified || show_others || (dir.flags & DIR_SHOW_IGNORED) || show_killed)
++      if (show_modified || show_others || show_deleted || (dir.flags & DIR_SHOW_IGNORED) || show_killed)
+               require_work_tree = 1;
+       if (show_unmerged)
+               /*
+                * There's no point in showing unmerged unless
+                * you also show the stage information.
+                */
+               show_stage = 1;
+       if (dir.exclude_per_dir)
+               exc_given = 1;
  
        if (require_work_tree && !is_inside_work_tree())
                setup_work_tree();
  
-       pathspec = get_pathspec(prefix, argv + i);
+       pathspec = get_pathspec(prefix, argv);
  
        /* be nice with submodule patsh ending in a slash */
        read_cache();
                ps_matched = xcalloc(1, num);
        }
  
-       if (dir.show_ignored && !exc_given) {
+       if ((dir.flags & DIR_SHOW_IGNORED) && !exc_given) {
                fprintf(stderr, "%s: --ignored needs some exclude pattern\n",
                        argv[0]);
                exit(1);
diff --combined dir.c
index 371bcf7cfbc0b3ae7693fb129a6082924c84194d,5011cb4dd47a98bf5f91c3a5dc4682cfe1352601..c91ebfb46f929f926e1925c2db830c5847f3223b
--- 1/dir.c
--- 2/dir.c
+++ b/dir.c
@@@ -137,7 -137,7 +137,7 @@@ int match_pathspec(const char **pathspe
  
  static int no_wildcard(const char *string)
  {
 -      return string[strcspn(string, "*?[{")] == '\0';
 +      return string[strcspn(string, "*?[{\\")] == '\0';
  }
  
  void add_exclude(const char *string, const char *base,
@@@ -487,14 -487,14 +487,14 @@@ static enum directory_treatment treat_d
                return recurse_into_directory;
  
        case index_gitdir:
-               if (dir->show_other_directories)
+               if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES)
                        return ignore_directory;
                return show_directory;
  
        case index_nonexistent:
-               if (dir->show_other_directories)
+               if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES)
                        break;
-               if (!dir->no_gitlinks) {
+               if (!(dir->flags & DIR_NO_GITLINKS)) {
                        unsigned char sha1[20];
                        if (resolve_gitlink_ref(dirname, "HEAD", sha1) == 0)
                                return show_directory;
        }
  
        /* This is the "show_other_directories" case */
-       if (!dir->hide_empty_directories)
+       if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
                return show_directory;
        if (!read_directory_recursive(dir, dirname, dirname, len, 1, simplify))
                return ignore_directory;
@@@ -601,7 -601,7 +601,7 @@@ static int read_directory_recursive(str
  
                        dtype = DTYPE(de);
                        exclude = excluded(dir, fullname, &dtype);
-                       if (exclude && dir->collect_ignored
+                       if (exclude && (dir->flags & DIR_COLLECT_IGNORED)
                            && in_pathspec(fullname, baselen + len, simplify))
                                dir_add_ignored(dir, fullname, baselen + len);
  
                         * Excluded? If we don't explicitly want to show
                         * ignored files, ignore it
                         */
-                       if (exclude && !dir->show_ignored)
+                       if (exclude && !(dir->flags & DIR_SHOW_IGNORED))
                                continue;
  
                        if (dtype == DT_UNKNOWN)
                         * even if we don't ignore them, since the
                         * directory may contain files that we do..
                         */
-                       if (!exclude && dir->show_ignored) {
+                       if (!exclude && (dir->flags & DIR_SHOW_IGNORED)) {
                                if (dtype != DT_DIR)
                                        continue;
                        }
                                len++;
                                switch (treat_directory(dir, fullname, baselen + len, simplify)) {
                                case show_directory:
-                                       if (exclude != dir->show_ignored)
+                                       if (exclude != !!(dir->flags
+                                                       & DIR_SHOW_IGNORED))
                                                continue;
                                        break;
                                case recurse_into_directory:
@@@ -720,7 -721,7 +721,7 @@@ int read_directory(struct dir_struct *d
  {
        struct path_simplify *simplify;
  
 -      if (has_symlink_leading_path(strlen(path), path))
 +      if (has_symlink_leading_path(path, strlen(path)))
                return dir->nr;
  
        simplify = create_simplify(pathspec);
diff --combined wt-status.c
index dd87339ff7b0faeb60091b087e5839c3cce9898c,f2eae20d89b71f384f727e72a1c520a3f1330df6..929b00f59285c21a07df98700c23171505f5cddb
@@@ -15,11 -15,11 +15,11 @@@ int wt_status_relative_paths = 1
  int wt_status_use_color = -1;
  int wt_status_submodule_summary;
  static char wt_status_colors[][COLOR_MAXLEN] = {
 -      "",         /* WT_STATUS_HEADER: normal */
 -      "\033[32m", /* WT_STATUS_UPDATED: green */
 -      "\033[31m", /* WT_STATUS_CHANGED: red */
 -      "\033[31m", /* WT_STATUS_UNTRACKED: red */
 -      "\033[31m", /* WT_STATUS_NOBRANCH: red */
 +      GIT_COLOR_NORMAL, /* WT_STATUS_HEADER */
 +      GIT_COLOR_GREEN,  /* WT_STATUS_UPDATED */
 +      GIT_COLOR_RED,    /* WT_STATUS_CHANGED */
 +      GIT_COLOR_RED,    /* WT_STATUS_UNTRACKED */
 +      GIT_COLOR_RED,    /* WT_STATUS_NOBRANCH */
  };
  
  enum untracked_status_type show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES;
@@@ -250,10 -250,9 +250,9 @@@ static void wt_status_print_untracked(s
  
        memset(&dir, 0, sizeof(dir));
  
-       if (!s->untracked) {
-               dir.show_other_directories = 1;
-               dir.hide_empty_directories = 1;
-       }
+       if (!s->untracked)
+               dir.flags |=
+                       DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
        setup_standard_excludes(&dir);
  
        read_directory(&dir, ".", "", 0, NULL);