Merge branch 'cn/log-parse-opt'
authorJunio C Hamano <gitster@pobox.com>
Fri, 13 May 2011 17:59:57 +0000 (10:59 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 13 May 2011 17:59:57 +0000 (10:59 -0700)
* cn/log-parse-opt:
log: convert to parse-options

1  2 
builtin/log.c
diff --combined builtin/log.c
index d43ad3a6172b4e083a6c066ab15dfce5bdb0ad3c,ca353402a6984b6fc122c712173f4f061dd5bf20..f6219909a787ae355a43e39974140a36848ab1d6
@@@ -25,12 -25,15 +25,15 @@@ static const char *default_date_mode = 
  
  static int default_show_root = 1;
  static int decoration_style;
+ static int decoration_given;
  static const char *fmt_patch_subject_prefix = "PATCH";
  static const char *fmt_pretty;
  
- static const char * const builtin_log_usage =
+ static const char * const builtin_log_usage[] = {
        "git log [<options>] [<since>..<until>] [[--] <path>...]\n"
-       "   or: git show [options] <object>...";
+       "   or: git show [options] <object>...",
+       NULL
+ };
  
  static int parse_decoration_style(const char *var, const char *value)
  {
        return -1;
  }
  
 -static void cmd_log_init(int argc, const char **argv, const char *prefix,
+ static int decorate_callback(const struct option *opt, const char *arg, int unset)
+ {
+       if (unset)
+               decoration_style = 0;
+       else if (arg)
+               decoration_style = parse_decoration_style("command line", arg);
+       else
+               decoration_style = DECORATE_SHORT_REFS;
+       if (decoration_style < 0)
+               die("invalid --decorate option: %s", arg);
+       decoration_given = 1;
+       return 0;
+ }
 +static void cmd_log_init_defaults(struct rev_info *rev)
 +{
 +      rev->abbrev = DEFAULT_ABBREV;
 +      rev->commit_format = CMIT_FMT_DEFAULT;
 +      if (fmt_pretty)
 +              get_commit_format(fmt_pretty, rev);
 +      rev->verbose_header = 1;
 +      DIFF_OPT_SET(&rev->diffopt, RECURSIVE);
 +      rev->show_root_diff = default_show_root;
 +      rev->subject_prefix = fmt_patch_subject_prefix;
 +      DIFF_OPT_SET(&rev->diffopt, ALLOW_TEXTCONV);
 +
 +      if (default_date_mode)
 +              rev->date_mode = parse_date_format(default_date_mode);
 +}
 +
 +static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
                         struct rev_info *rev, struct setup_revision_opt *opt)
  {
-       int i;
-       int decoration_given = 0;
        struct userformat_want w;
-       /*
-        * Check for -h before setup_revisions(), or "git log -h" will
-        * fail when run without a git directory.
-        */
-       if (argc == 2 && !strcmp(argv[1], "-h"))
-               usage(builtin_log_usage);
+       int quiet = 0, source = 0;
+       const struct option builtin_log_options[] = {
+               OPT_BOOLEAN(0, "quiet", &quiet, "supress diff output"),
+               OPT_BOOLEAN(0, "source", &source, "show source"),
+               { OPTION_CALLBACK, 0, "decorate", NULL, NULL, "decorate options",
+                 PARSE_OPT_OPTARG, decorate_callback},
+               OPT_END()
+       };
+       argc = parse_options(argc, argv, prefix,
+                            builtin_log_options, builtin_log_usage,
+                            PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |
+                            PARSE_OPT_KEEP_DASHDASH);
 -      rev->abbrev = DEFAULT_ABBREV;
 -      rev->commit_format = CMIT_FMT_DEFAULT;
 -      if (fmt_pretty)
 -              get_commit_format(fmt_pretty, rev);
 -      rev->verbose_header = 1;
 -      DIFF_OPT_SET(&rev->diffopt, RECURSIVE);
 -      rev->show_root_diff = default_show_root;
 -      rev->subject_prefix = fmt_patch_subject_prefix;
 -      DIFF_OPT_SET(&rev->diffopt, ALLOW_TEXTCONV);
 -
 -      if (default_date_mode)
 -              rev->date_mode = parse_date_format(default_date_mode);
 -
        argc = setup_revisions(argc, argv, rev, opt);
  
+       /* Any arguments at this point are not recognized */
+       if (argc > 1)
+               die("unrecognized argument: %s", argv[1]);
        memset(&w, 0, sizeof(w));
        userformat_find_requirements(NULL, &w);
  
                rev->always_show_header = 0;
        if (DIFF_OPT_TST(&rev->diffopt, FOLLOW_RENAMES)) {
                rev->always_show_header = 0;
 -              if (rev->diffopt.nr_paths != 1)
 +              if (rev->diffopt.pathspec.nr != 1)
                        usage("git logs can only follow renames on one pathname at a time");
        }
-       for (i = 1; i < argc; i++) {
-               const char *arg = argv[i];
-               if (!strcmp(arg, "--decorate")) {
-                       decoration_style = DECORATE_SHORT_REFS;
-                       decoration_given = 1;
-               } else if (!prefixcmp(arg, "--decorate=")) {
-                       const char *v = skip_prefix(arg, "--decorate=");
-                       decoration_style = parse_decoration_style(arg, v);
-                       if (decoration_style < 0)
-                               die(_("invalid --decorate option: %s"), arg);
-                       decoration_given = 1;
-               } else if (!strcmp(arg, "--no-decorate")) {
-                       decoration_style = 0;
-               } else if (!strcmp(arg, "--source")) {
-                       rev->show_source = 1;
-               } else if (!strcmp(arg, "-h")) {
-                       usage(builtin_log_usage);
-               } else
-                       die(_("unrecognized argument: %s"), arg);
-       }
+       if (source)
+               rev->show_source = 1;
  
        /*
         * defeat log.decorate configuration interacting with --pretty=raw
        setup_pager();
  }
  
 +static void cmd_log_init(int argc, const char **argv, const char *prefix,
 +                       struct rev_info *rev, struct setup_revision_opt *opt)
 +{
 +      cmd_log_init_defaults(rev);
 +      cmd_log_init_finish(argc, argv, prefix, rev, opt);
 +}
 +
  /*
   * This gives a rough estimate for how many commits we
   * will print out in the list.
@@@ -162,7 -166,7 +176,7 @@@ static void show_early_header(struct re
                if (rev->commit_format != CMIT_FMT_ONELINE)
                        putchar(rev->diffopt.line_termination);
        }
 -      printf("Final output: %d %s\n", nr, stage);
 +      printf(_("Final output: %d %s\n"), nr, stage);
  }
  
  static struct itimerval early_output_timer;
@@@ -256,14 -260,12 +270,14 @@@ static void finish_early_output(struct 
  static int cmd_log_walk(struct rev_info *rev)
  {
        struct commit *commit;
 +      int saved_nrl = 0;
 +      int saved_dcctc = 0;
  
        if (rev->early_output)
                setup_early_output(rev);
  
        if (prepare_revision_walk(rev))
 -              die("revision walk setup failed");
 +              die(_("revision walk setup failed"));
  
        if (rev->early_output)
                finish_early_output(rev);
                }
                free_commit_list(commit->parents);
                commit->parents = NULL;
 +              if (saved_nrl < rev->diffopt.needed_rename_limit)
 +                      saved_nrl = rev->diffopt.needed_rename_limit;
 +              if (rev->diffopt.degraded_cc_to_c)
 +                      saved_dcctc = 1;
        }
 +      rev->diffopt.degraded_cc_to_c = saved_dcctc;
 +      rev->diffopt.needed_rename_limit = saved_nrl;
 +
        if (rev->diffopt.output_format & DIFF_FORMAT_CHECKDIFF &&
            DIFF_OPT_TST(&rev->diffopt, CHECK_FAILED)) {
                return 02;
@@@ -367,7 -362,7 +381,7 @@@ static int show_object(const unsigned c
        int offset = 0;
  
        if (!buf)
 -              return error("Could not read object %s", sha1_to_hex(sha1));
 +              return error(_("Could not read object %s"), sha1_to_hex(sha1));
  
        if (show_tag_object)
                while (offset < size && buf[offset] != '\n') {
@@@ -414,7 -409,6 +428,7 @@@ int cmd_show(int argc, const char **arg
        struct rev_info rev;
        struct object_array_entry *objects;
        struct setup_revision_opt opt;
 +      struct pathspec match_all;
        int i, count, ret = 0;
  
        git_config(git_log_config, NULL);
        if (diff_use_color_default == -1)
                diff_use_color_default = git_use_color_default;
  
 +      init_pathspec(&match_all, NULL);
        init_revisions(&rev, prefix);
        rev.diff = 1;
        rev.always_show_header = 1;
                                break;
                        o = parse_object(t->tagged->sha1);
                        if (!o)
 -                              ret = error("Could not read object %s",
 +                              ret = error(_("Could not read object %s"),
                                            sha1_to_hex(t->tagged->sha1));
                        objects[i].item = o;
                        i--;
                                        diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
                                        name,
                                        diff_get_color_opt(&rev.diffopt, DIFF_RESET));
 -                      read_tree_recursive((struct tree *)o, "", 0, 0, NULL,
 +                      read_tree_recursive((struct tree *)o, "", 0, 0, &match_all,
                                        show_tree_object, NULL);
                        rev.shown_one = 1;
                        break;
                        ret = cmd_log_walk(&rev);
                        break;
                default:
 -                      ret = error("Unknown type: %d", o->type);
 +                      ret = error(_("Unknown type: %d"), o->type);
                }
        }
        free(objects);
@@@ -506,11 -499,16 +520,11 @@@ int cmd_log_reflog(int argc, const cha
        rev.verbose_header = 1;
        memset(&opt, 0, sizeof(opt));
        opt.def = "HEAD";
 -      cmd_log_init(argc, argv, prefix, &rev, &opt);
 -
 -      /*
 -       * This means that we override whatever commit format the user gave
 -       * on the cmd line.  Sad, but cmd_log_init() currently doesn't
 -       * allow us to set a different default.
 -       */
 +      cmd_log_init_defaults(&rev);
        rev.commit_format = CMIT_FMT_ONELINE;
        rev.use_terminator = 1;
        rev.always_show_header = 1;
 +      cmd_log_init_finish(argc, argv, prefix, &rev, &opt);
  
        return cmd_log_walk(&rev);
  }
@@@ -575,7 -573,7 +589,7 @@@ static int git_format_config(const cha
  {
        if (!strcmp(var, "format.headers")) {
                if (!value)
 -                      die("format.headers without value");
 +                      die(_("format.headers without value"));
                add_header(value);
                return 0;
        }
@@@ -638,7 -636,7 +652,7 @@@ static FILE *realstdout = NULL
  static const char *output_directory = NULL;
  static int outdir_offset;
  
 -static int reopen_stdout(struct commit *commit, struct rev_info *rev)
 +static int reopen_stdout(struct commit *commit, struct rev_info *rev, int quiet)
  {
        struct strbuf filename = STRBUF_INIT;
        int suffix_len = strlen(fmt_patch_suffix) + 1;
                strbuf_addstr(&filename, output_directory);
                if (filename.len >=
                    PATH_MAX - FORMAT_PATCH_NAME_MAX - suffix_len)
 -                      return error("name of output directory is too long");
 +                      return error(_("name of output directory is too long"));
                if (filename.buf[filename.len - 1] != '/')
                        strbuf_addch(&filename, '/');
        }
  
        get_patch_filename(commit, rev->nr, fmt_patch_suffix, &filename);
  
 -      if (!DIFF_OPT_TST(&rev->diffopt, QUICK))
 +      if (!quiet)
                fprintf(realstdout, "%s\n", filename.buf + outdir_offset);
  
        if (freopen(filename.buf, "w", stdout) == NULL)
 -              return error("Cannot open patch file %s", filename.buf);
 +              return error(_("Cannot open patch file %s"), filename.buf);
  
        strbuf_release(&filename);
        return 0;
@@@ -672,7 -670,7 +686,7 @@@ static void get_patch_ids(struct rev_in
        unsigned flags1, flags2;
  
        if (rev->pending.nr != 2)
 -              die("Need exactly one range.");
 +              die(_("Need exactly one range."));
  
        o1 = rev->pending.objects[0].item;
        flags1 = o1->flags;
        flags2 = o2->flags;
  
        if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING))
 -              die("Not a range.");
 +              die(_("Not a range."));
  
        init_patch_ids(ids);
  
        add_pending_object(&check_rev, o1, "o1");
        add_pending_object(&check_rev, o2, "o2");
        if (prepare_revision_walk(&check_rev))
 -              die("revision walk setup failed");
 +              die(_("revision walk setup failed"));
  
        while ((commit = get_revision(&check_rev)) != NULL) {
                /* ignore merges */
@@@ -717,7 -715,7 +731,7 @@@ static void gen_message_id(struct rev_i
        const char *email_end = strrchr(committer, '>');
        struct strbuf buf = STRBUF_INIT;
        if (!email_start || !email_end || email_start > email_end - 1)
 -              die("Could not extract email from committer identity.");
 +              die(_("Could not extract email from committer identity."));
        strbuf_addf(&buf, "%s.%lu.git.%.*s", base,
                    (unsigned long) time(NULL),
                    (int)(email_end - email_start - 1), email_start + 1);
@@@ -733,8 -731,7 +747,8 @@@ static void print_signature(void
  static void make_cover_letter(struct rev_info *rev, int use_stdout,
                              int numbered, int numbered_files,
                              struct commit *origin,
 -                            int nr, struct commit **list, struct commit *head)
 +                            int nr, struct commit **list, struct commit *head,
 +                            int quiet)
  {
        const char *committer;
        const char *subject_start = NULL;
        struct commit *commit = NULL;
  
        if (rev->commit_format != CMIT_FMT_EMAIL)
 -              die("Cover letter needs email format");
 +              die(_("Cover letter needs email format"));
  
        committer = git_committer_info(0);
  
                        sha1_to_hex(head->object.sha1), committer, committer);
        }
  
 -      if (!use_stdout && reopen_stdout(commit, rev))
 +      if (!use_stdout && reopen_stdout(commit, rev, quiet))
                return;
  
        if (commit) {
@@@ -843,7 -840,7 +857,7 @@@ static const char *clean_message_id(con
                m++;
        }
        if (!z)
 -              die("insane in-reply-to: %s", msg_id);
 +              die(_("insane in-reply-to: %s"), msg_id);
        if (++z == m)
                return a;
        return xmemdupz(a, z - a);
@@@ -916,7 -913,7 +930,7 @@@ static int output_directory_callback(co
  {
        const char **dir = (const char **)opt->value;
        if (*dir)
 -              die("Two output directories?");
 +              die(_("Two output directories?"));
        *dir = arg;
        return 0;
  }
@@@ -1011,7 -1008,6 +1025,7 @@@ int cmd_format_patch(int argc, const ch
        char *add_signoff = NULL;
        struct strbuf buf = STRBUF_INIT;
        int use_patch_format = 0;
 +      int quiet = 0;
        const struct option builtin_format_patch_options[] = {
                { OPTION_CALLBACK, 'n', "numbered", &numbered, NULL,
                            "use [PATCH n/m] even with a single patch",
                            PARSE_OPT_OPTARG, thread_callback },
                OPT_STRING(0, "signature", &signature, "signature",
                            "add a signature"),
 +              OPT_BOOLEAN(0, "quiet", &quiet,
 +                          "don't print the patch filenames"),
                OPT_END()
        };
  
        rev.commit_format = CMIT_FMT_EMAIL;
        rev.verbose_header = 1;
        rev.diff = 1;
 -      rev.no_merges = 1;
 +      rev.max_parents = 1;
        DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
        rev.subject_prefix = fmt_patch_subject_prefix;
        memset(&s_r_opt, 0, sizeof(s_r_opt));
                committer = git_committer_info(IDENT_ERROR_ON_NO_NAME);
                endpos = strchr(committer, '>');
                if (!endpos)
 -                      die("bogus committer info %s", committer);
 +                      die(_("bogus committer info %s"), committer);
                add_signoff = xmemdupz(committer, endpos - committer + 1);
        }
  
                numbered = 0;
  
        if (numbered && keep_subject)
 -              die ("-n and -k are mutually exclusive.");
 +              die (_("-n and -k are mutually exclusive."));
        if (keep_subject && subject_prefix)
 -              die ("--subject-prefix and -k are mutually exclusive.");
 +              die (_("--subject-prefix and -k are mutually exclusive."));
  
        argc = setup_revisions(argc, argv, &rev, &s_r_opt);
        if (argc > 1)
 -              die ("unrecognized argument: %s", argv[1]);
 +              die (_("unrecognized argument: %s"), argv[1]);
  
        if (rev.diffopt.output_format & DIFF_FORMAT_NAME)
 -              die("--name-only does not make sense");
 +              die(_("--name-only does not make sense"));
        if (rev.diffopt.output_format & DIFF_FORMAT_NAME_STATUS)
 -              die("--name-status does not make sense");
 +              die(_("--name-status does not make sense"));
        if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF)
 -              die("--check does not make sense");
 +              die(_("--check does not make sense"));
  
        if (!use_patch_format &&
                (!rev.diffopt.output_format ||
  
        if (output_directory) {
                if (use_stdout)
 -                      die("standard output, or directory, which one?");
 +                      die(_("standard output, or directory, which one?"));
                if (mkdir(output_directory, 0777) < 0 && errno != EEXIST)
 -                      die_errno("Could not create directory '%s'",
 +                      die_errno(_("Could not create directory '%s'"),
                                  output_directory);
        }
  
                realstdout = xfdopen(xdup(1), "w");
  
        if (prepare_revision_walk(&rev))
 -              die("revision walk setup failed");
 +              die(_("revision walk setup failed"));
        rev.boundary = 1;
        while ((commit = get_revision(&rev)) != NULL) {
                if (commit->object.flags & BOUNDARY) {
                if (thread)
                        gen_message_id(&rev, "cover");
                make_cover_letter(&rev, use_stdout, numbered, numbered_files,
 -                                origin, nr, list, head);
 +                                origin, nr, list, head, quiet);
                total++;
                start_number--;
        }
                }
  
                if (!use_stdout && reopen_stdout(numbered_files ? NULL : commit,
 -                                               &rev))
 -                      die("Failed to create output files");
 +                                               &rev, quiet))
 +                      die(_("Failed to create output files"));
                shown = log_tree_commit(&rev, commit);
                free(commit->buffer);
                commit->buffer = NULL;
@@@ -1429,9 -1423,9 +1443,9 @@@ int cmd_cherry(int argc, const char **a
                if (!current_branch || !current_branch->merge
                                        || !current_branch->merge[0]
                                        || !current_branch->merge[0]->dst) {
 -                      fprintf(stderr, "Could not find a tracked"
 +                      fprintf(stderr, _("Could not find a tracked"
                                        " remote branch, please"
 -                                      " specify <upstream> manually.\n");
 +                                      " specify <upstream> manually.\n"));
                        usage_with_options(cherry_usage, options);
                }
  
        DIFF_OPT_SET(&revs.diffopt, RECURSIVE);
  
        if (add_pending_commit(head, &revs, 0))
 -              die("Unknown commit %s", head);
 +              die(_("Unknown commit %s"), head);
        if (add_pending_commit(upstream, &revs, UNINTERESTING))
 -              die("Unknown commit %s", upstream);
 +              die(_("Unknown commit %s"), upstream);
  
        /* Don't say anything if head and upstream are the same. */
        if (revs.pending.nr == 2) {
        get_patch_ids(&revs, &ids, prefix);
  
        if (limit && add_pending_commit(limit, &revs, UNINTERESTING))
 -              die("Unknown commit %s", limit);
 +              die(_("Unknown commit %s"), limit);
  
        /* reverse the list of commits */
        if (prepare_revision_walk(&revs))
 -              die("revision walk setup failed");
 +              die(_("revision walk setup failed"));
        while ((commit = get_revision(&revs)) != NULL) {
                /* ignore merges */
                if (commit->parents && commit->parents->next)