builtin/read-tree: convert to struct object_id
[gitweb.git] / builtin / grep.c
index 0393b0fdc47467ddf10acdd830b910b58a1accd7..3ffb5b4e8176bbcd1ecf2e4ae2dc84aee968cd22 100644 (file)
@@ -310,10 +310,7 @@ static int grep_oid(struct grep_opt *opt, const struct object_id *oid,
 {
        struct strbuf pathbuf = STRBUF_INIT;
 
-       if (opt->relative && opt->prefix_length) {
-               quote_path_relative(filename + tree_name_len, opt->prefix, &pathbuf);
-               strbuf_insert(&pathbuf, 0, filename, tree_name_len);
-       } else if (super_prefix) {
+       if (super_prefix) {
                strbuf_add(&pathbuf, filename, tree_name_len);
                strbuf_addstr(&pathbuf, super_prefix);
                strbuf_addstr(&pathbuf, filename + tree_name_len);
@@ -321,6 +318,13 @@ static int grep_oid(struct grep_opt *opt, const struct object_id *oid,
                strbuf_addstr(&pathbuf, filename);
        }
 
+       if (opt->relative && opt->prefix_length) {
+               char *name = strbuf_detach(&pathbuf, NULL);
+               quote_path_relative(name + tree_name_len, opt->prefix, &pathbuf);
+               strbuf_insert(&pathbuf, 0, name, tree_name_len);
+               free(name);
+       }
+
 #ifndef NO_PTHREADS
        if (num_threads) {
                add_work(opt, GREP_SOURCE_SHA1, pathbuf.buf, path, oid);
@@ -345,12 +349,14 @@ static int grep_file(struct grep_opt *opt, const char *filename)
 {
        struct strbuf buf = STRBUF_INIT;
 
+       if (super_prefix)
+               strbuf_addstr(&buf, super_prefix);
+       strbuf_addstr(&buf, filename);
+
        if (opt->relative && opt->prefix_length) {
-               quote_path_relative(filename, opt->prefix, &buf);
-       } else {
-               if (super_prefix)
-                       strbuf_addstr(&buf, super_prefix);
-               strbuf_addstr(&buf, filename);
+               char *name = strbuf_detach(&buf, NULL);
+               quote_path_relative(name, opt->prefix, &buf);
+               free(name);
        }
 
 #ifndef NO_PTHREADS
@@ -399,13 +405,12 @@ static void run_pager(struct grep_opt *opt, const char *prefix)
 }
 
 static void compile_submodule_options(const struct grep_opt *opt,
-                                     const struct pathspec *pathspec,
+                                     const char **argv,
                                      int cached, int untracked,
                                      int opt_exclude, int use_index,
                                      int pattern_type_arg)
 {
        struct grep_pat *pattern;
-       int i;
 
        if (recurse_submodules)
                argv_array_push(&submodule_options, "--recurse-submodules");
@@ -523,9 +528,8 @@ static void compile_submodule_options(const struct grep_opt *opt,
 
        /* Add Pathspecs */
        argv_array_push(&submodule_options, "--");
-       for (i = 0; i < pathspec->nr; i++)
-               argv_array_push(&submodule_options,
-                               pathspec->items[i].original);
+       for (; *argv; argv++)
+               argv_array_push(&submodule_options, *argv);
 }
 
 /*
@@ -538,7 +542,7 @@ static int grep_submodule_launch(struct grep_opt *opt,
        int status, i;
        const char *end_of_base;
        const char *name;
-       struct work_item *w = opt->output_priv;
+       struct strbuf child_output = STRBUF_INIT;
 
        end_of_base = strchr(gs->name, ':');
        if (gs->identifier && end_of_base)
@@ -549,6 +553,11 @@ static int grep_submodule_launch(struct grep_opt *opt,
        prepare_submodule_repo_env(&cp.env_array);
        argv_array_push(&cp.env_array, GIT_DIR_ENVIRONMENT);
 
+       if (opt->relative && opt->prefix_length)
+               argv_array_pushf(&cp.env_array, "%s=%s",
+                                GIT_TOPLEVEL_PREFIX_ENVIRONMENT,
+                                opt->prefix);
+
        /* Add super prefix */
        argv_array_pushf(&cp.args, "--super-prefix=%s%s/",
                         super_prefix ? super_prefix : "",
@@ -593,14 +602,16 @@ static int grep_submodule_launch(struct grep_opt *opt,
         * child process.  A '0' indicates a hit, a '1' indicates no hit and
         * anything else is an error.
         */
-       status = capture_command(&cp, &w->out, 0);
+       status = capture_command(&cp, &child_output, 0);
        if (status && (status != 1)) {
                /* flush the buffer */
-               write_or_die(1, w->out.buf, w->out.len);
+               write_or_die(1, child_output.buf, child_output.len);
                die("process for submodule '%s' failed with exit code: %d",
                    gs->name, status);
        }
 
+       opt->output(opt, child_output.buf, child_output.len);
+       strbuf_release(&child_output);
        /* invert the return code to make a hit equal to 1 */
        return !status;
 }
@@ -616,7 +627,7 @@ static int grep_submodule(struct grep_opt *opt, const unsigned char *sha1,
 {
        if (!is_submodule_initialized(path))
                return 0;
-       if (!is_submodule_populated(path)) {
+       if (!is_submodule_populated_gently(path, NULL)) {
                /*
                 * If searching history, check for the presense of the
                 * submodule's gitdir before skipping the submodule.
@@ -641,19 +652,14 @@ static int grep_submodule(struct grep_opt *opt, const unsigned char *sha1,
        } else
 #endif
        {
-               struct work_item w;
+               struct grep_source gs;
                int hit;
 
-               grep_source_init(&w.source, GREP_SOURCE_SUBMODULE,
+               grep_source_init(&gs, GREP_SOURCE_SUBMODULE,
                                 filename, path, sha1);
-               strbuf_init(&w.out, 0);
-               opt->output_priv = &w;
-               hit = grep_submodule_launch(opt, &w.source);
-
-               write_or_die(1, w.out.buf, w.out.len);
+               hit = grep_submodule_launch(opt, &gs);
 
-               grep_source_clear(&w.source);
-               strbuf_release(&w.out);
+               grep_source_clear(&gs);
                return hit;
        }
 }
@@ -967,6 +973,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
        int dummy;
        int use_index = 1;
        int pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED;
+       int allow_revs;
 
        struct option options[] = {
                OPT_BOOL(0, "cached", &cached,
@@ -978,7 +985,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                OPT_SET_INT(0, "exclude-standard", &opt_exclude,
                            N_("ignore files specified via '.gitignore'"), 1),
                OPT_BOOL(0, "recurse-submodules", &recurse_submodules,
-                        N_("recursivley search in each submodule")),
+                        N_("recursively search in each submodule")),
                OPT_STRING(0, "parent-basename", &parent_basename,
                           N_("basename"),
                           N_("prepend parent project's basename to output")),
@@ -1149,26 +1156,69 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 
        compile_grep_patterns(&opt);
 
-       /* Check revs and then paths */
+       /*
+        * We have to find "--" in a separate pass, because its presence
+        * influences how we will parse arguments that come before it.
+        */
+       for (i = 0; i < argc; i++) {
+               if (!strcmp(argv[i], "--")) {
+                       seen_dashdash = 1;
+                       break;
+               }
+       }
+
+       /*
+        * Resolve any rev arguments. If we have a dashdash, then everything up
+        * to it must resolve as a rev. If not, then we stop at the first
+        * non-rev and assume everything else is a path.
+        */
+       allow_revs = use_index && !untracked;
        for (i = 0; i < argc; i++) {
                const char *arg = argv[i];
                struct object_id oid;
                struct object_context oc;
-               /* Is it a rev? */
-               if (!get_sha1_with_context(arg, 0, oid.hash, &oc)) {
-                       struct object *object = parse_object_or_die(oid.hash, arg);
-                       if (!seen_dashdash)
-                               verify_non_filename(prefix, arg);
-                       add_object_array_with_path(object, arg, &list, oc.mode, oc.path);
-                       continue;
-               }
+               struct object *object;
+
                if (!strcmp(arg, "--")) {
                        i++;
-                       seen_dashdash = 1;
+                       break;
                }
-               break;
+
+               if (!allow_revs) {
+                       if (seen_dashdash)
+                               die(_("--no-index or --untracked cannot be used with revs"));
+                       break;
+               }
+
+               if (get_sha1_with_context(arg, 0, oid.hash, &oc)) {
+                       if (seen_dashdash)
+                               die(_("unable to resolve revision: %s"), arg);
+                       break;
+               }
+
+               object = parse_object_or_die(oid.hash, arg);
+               if (!seen_dashdash)
+                       verify_non_filename(prefix, arg);
+               add_object_array_with_path(object, arg, &list, oc.mode, oc.path);
+       }
+
+       /*
+        * Anything left over is presumed to be a path. But in the non-dashdash
+        * "do what I mean" case, we verify and complain when that isn't true.
+        */
+       if (!seen_dashdash) {
+               int j;
+               for (j = i; j < argc; j++)
+                       verify_filename(prefix, argv[j], j == i && allow_revs);
        }
 
+       parse_pathspec(&pathspec, 0,
+                      PATHSPEC_PREFER_CWD |
+                      (opt.max_depth != -1 ? PATHSPEC_MAXDEPTH_VALID : 0),
+                      prefix, argv + i);
+       pathspec.max_depth = opt.max_depth;
+       pathspec.recursive = 1;
+
 #ifndef NO_PTHREADS
        if (list.nr || cached || show_in_pager)
                num_threads = 0;
@@ -1190,23 +1240,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
        }
 #endif
 
-       /* The rest are paths */
-       if (!seen_dashdash) {
-               int j;
-               for (j = i; j < argc; j++)
-                       verify_filename(prefix, argv[j], j == i);
-       }
-
-       parse_pathspec(&pathspec, 0,
-                      PATHSPEC_PREFER_CWD |
-                      (opt.max_depth != -1 ? PATHSPEC_MAXDEPTH_VALID : 0),
-                      prefix, argv + i);
-       pathspec.max_depth = opt.max_depth;
-       pathspec.recursive = 1;
-
        if (recurse_submodules) {
                gitmodules_config();
-               compile_submodule_options(&opt, &pathspec, cached, untracked,
+               compile_submodule_options(&opt, argv + i, cached, untracked,
                                          opt_exclude, use_index,
                                          pattern_type_arg);
        }
@@ -1245,8 +1281,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
 
        if (!use_index || untracked) {
                int use_exclude = (opt_exclude < 0) ? use_index : !!opt_exclude;
-               if (list.nr)
-                       die(_("--no-index or --untracked cannot be used with revs."));
                hit = grep_directory(&opt, &pathspec, use_exclude, use_index);
        } else if (0 <= opt_exclude) {
                die(_("--[no-]exclude-standard cannot be used for tracked contents."));
@@ -1265,6 +1299,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                hit |= wait_all();
        if (hit && show_in_pager)
                run_pager(&opt, prefix);
+       clear_pathspec(&pathspec);
        free_grep_patterns(&opt);
        return !hit;
 }