#include "cache.h"
+#include "config.h"
#include "submodule-config.h"
#include "submodule.h"
#include "dir.h"
return ret;
}
+/*
+ * Dies if the provided 'prefix' corresponds to an unpopulated submodule
+ */
+void die_in_unpopulated_submodule(const struct index_state *istate,
+ const char *prefix)
+{
+ int i, prefixlen;
+
+ if (!prefix)
+ return;
+
+ prefixlen = strlen(prefix);
+
+ for (i = 0; i < istate->cache_nr; i++) {
+ struct cache_entry *ce = istate->cache[i];
+ int ce_len = ce_namelen(ce);
+
+ if (!S_ISGITLINK(ce->ce_mode))
+ continue;
+ if (prefixlen <= ce_len)
+ continue;
+ if (strncmp(ce->name, prefix, ce_len))
+ continue;
+ if (prefix[ce_len] != '/')
+ continue;
+
+ die(_("in unpopulated submodule '%s'"), ce->name);
+ }
+}
+
+/*
+ * Dies if any paths in the provided pathspec descends into a submodule
+ */
+void die_path_inside_submodule(const struct index_state *istate,
+ const struct pathspec *ps)
+{
+ int i, j;
+
+ for (i = 0; i < istate->cache_nr; i++) {
+ struct cache_entry *ce = istate->cache[i];
+ int ce_len = ce_namelen(ce);
+
+ if (!S_ISGITLINK(ce->ce_mode))
+ continue;
+
+ for (j = 0; j < ps->nr ; j++) {
+ const struct pathspec_item *item = &ps->items[j];
+
+ if (item->len <= ce_len)
+ continue;
+ if (item->match[ce_len] != '/')
+ continue;
+ if (strncmp(ce->name, item->match, ce_len))
+ continue;
+ if (item->len == ce_len + 1)
+ continue;
+
+ die(_("Pathspec '%s' is in submodule '%.*s'"),
+ item->original, ce_len, ce->name);
+ }
+ }
+}
+
int parse_submodule_update_strategy(const char *value,
struct submodule_update_strategy *dst)
{
return prepare_revision_walk(rev);
}
-static void print_submodule_summary(struct rev_info *rev, FILE *f,
- const char *line_prefix,
- const char *del, const char *add, const char *reset)
+static void print_submodule_summary(struct rev_info *rev, struct diff_options *o)
{
static const char format[] = " %m %s";
struct strbuf sb = STRBUF_INIT;
ctx.date_mode = rev->date_mode;
ctx.output_encoding = get_log_output_encoding();
strbuf_setlen(&sb, 0);
- strbuf_addstr(&sb, line_prefix);
- if (commit->object.flags & SYMMETRIC_LEFT) {
- if (del)
- strbuf_addstr(&sb, del);
- }
- else if (add)
- strbuf_addstr(&sb, add);
format_commit_message(commit, format, &sb, &ctx);
- if (reset)
- strbuf_addstr(&sb, reset);
strbuf_addch(&sb, '\n');
- fprintf(f, "%s", sb.buf);
+ if (commit->object.flags & SYMMETRIC_LEFT)
+ diff_emit_submodule_del(o, sb.buf);
+ else
+ diff_emit_submodule_add(o, sb.buf);
}
strbuf_release(&sb);
}
* attempt to lookup both the left and right commits and put them into the
* left and right pointers.
*/
-static void show_submodule_header(FILE *f, const char *path,
- const char *line_prefix,
+static void show_submodule_header(struct diff_options *o, const char *path,
struct object_id *one, struct object_id *two,
- unsigned dirty_submodule, const char *meta,
- const char *reset,
+ unsigned dirty_submodule,
struct commit **left, struct commit **right,
struct commit_list **merge_bases)
{
int fast_forward = 0, fast_backward = 0;
if (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)
- fprintf(f, "%sSubmodule %s contains untracked content\n",
- line_prefix, path);
+ diff_emit_submodule_untracked(o, path);
+
if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
- fprintf(f, "%sSubmodule %s contains modified content\n",
- line_prefix, path);
+ diff_emit_submodule_modified(o, path);
if (is_null_oid(one))
message = "(new submodule)";
* Attempt to lookup the commit references, and determine if this is
* a fast forward or fast backwards update.
*/
- *left = lookup_commit_reference(one->hash);
- *right = lookup_commit_reference(two->hash);
+ *left = lookup_commit_reference(one);
+ *right = lookup_commit_reference(two);
/*
* Warn about missing commits in the submodule project, but only if
}
output_header:
- strbuf_addf(&sb, "%s%sSubmodule %s ", line_prefix, meta, path);
+ strbuf_addf(&sb, "Submodule %s ", path);
strbuf_add_unique_abbrev(&sb, one->hash, DEFAULT_ABBREV);
strbuf_addstr(&sb, (fast_backward || fast_forward) ? ".." : "...");
strbuf_add_unique_abbrev(&sb, two->hash, DEFAULT_ABBREV);
if (message)
- strbuf_addf(&sb, " %s%s\n", message, reset);
+ strbuf_addf(&sb, " %s\n", message);
else
- strbuf_addf(&sb, "%s:%s\n", fast_backward ? " (rewind)" : "", reset);
- fwrite(sb.buf, sb.len, 1, f);
+ strbuf_addf(&sb, "%s:\n", fast_backward ? " (rewind)" : "");
+ diff_emit_submodule_header(o, sb.buf);
strbuf_release(&sb);
}
-void show_submodule_summary(FILE *f, const char *path,
- const char *line_prefix,
+void show_submodule_summary(struct diff_options *o, const char *path,
struct object_id *one, struct object_id *two,
- unsigned dirty_submodule, const char *meta,
- const char *del, const char *add, const char *reset)
+ unsigned dirty_submodule)
{
struct rev_info rev;
struct commit *left = NULL, *right = NULL;
struct commit_list *merge_bases = NULL;
- show_submodule_header(f, path, line_prefix, one, two, dirty_submodule,
- meta, reset, &left, &right, &merge_bases);
+ show_submodule_header(o, path, one, two, dirty_submodule,
+ &left, &right, &merge_bases);
/*
* If we don't have both a left and a right pointer, there is no
/* Treat revision walker failure the same as missing commits */
if (prepare_submodule_summary(&rev, path, left, right, merge_bases)) {
- fprintf(f, "%s(revision walker failed)\n", line_prefix);
+ diff_emit_submodule_error(o, "(revision walker failed)\n");
goto out;
}
- print_submodule_summary(&rev, f, line_prefix, del, add, reset);
+ print_submodule_summary(&rev, o);
out:
if (merge_bases)
clear_commit_marks(right, ~0);
}
-void show_submodule_inline_diff(FILE *f, const char *path,
- const char *line_prefix,
+void show_submodule_inline_diff(struct diff_options *o, const char *path,
struct object_id *one, struct object_id *two,
- unsigned dirty_submodule, const char *meta,
- const char *del, const char *add, const char *reset,
- const struct diff_options *o)
+ unsigned dirty_submodule)
{
const struct object_id *old = &empty_tree_oid, *new = &empty_tree_oid;
struct commit *left = NULL, *right = NULL;
struct commit_list *merge_bases = NULL;
- struct strbuf submodule_dir = STRBUF_INIT;
struct child_process cp = CHILD_PROCESS_INIT;
+ struct strbuf sb = STRBUF_INIT;
- show_submodule_header(f, path, line_prefix, one, two, dirty_submodule,
- meta, reset, &left, &right, &merge_bases);
+ show_submodule_header(o, path, one, two, dirty_submodule,
+ &left, &right, &merge_bases);
/* We need a valid left and right commit to display a difference */
if (!(left || is_null_oid(one)) ||
if (right)
new = two;
- fflush(f);
cp.git_cmd = 1;
cp.dir = path;
- cp.out = dup(fileno(f));
+ cp.out = -1;
cp.no_stdin = 1;
/* TODO: other options may need to be passed here. */
- argv_array_push(&cp.args, "diff");
- argv_array_pushf(&cp.args, "--line-prefix=%s", line_prefix);
+ argv_array_pushl(&cp.args, "diff", "--submodule=diff", NULL);
+ argv_array_pushf(&cp.args, "--color=%s", want_color(o->use_color) ?
+ "always" : "never");
+
if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
argv_array_pushf(&cp.args, "--src-prefix=%s%s/",
o->b_prefix, path);
argv_array_push(&cp.args, oid_to_hex(new));
prepare_submodule_repo_env(&cp.env_array);
- if (run_command(&cp))
- fprintf(f, "(diff failed)\n");
+ if (start_command(&cp))
+ diff_emit_submodule_error(o, "(diff failed)\n");
+
+ while (strbuf_getwholeline_fd(&sb, cp.out, '\n') != EOF)
+ diff_emit_submodule_pipethrough(o, sb.buf, sb.len);
+
+ if (finish_command(&cp))
+ diff_emit_submodule_error(o, "(diff failed)\n");
done:
- strbuf_release(&submodule_dir);
+ strbuf_release(&sb);
if (merge_bases)
free_commit_list(merge_bases);
if (left)
{
int *has_commit = data;
- if (!lookup_commit_reference(oid->hash))
+ if (!lookup_commit_reference(oid))
*has_commit = 0;
return 0;
{
struct child_process cp = CHILD_PROCESS_INIT;
- prepare_submodule_repo_env_no_git_dir(&cp.env_array);
+ prepare_submodule_repo_env(&cp.env_array);
cp.git_cmd = 1;
argv_array_pushl(&cp.args, "diff-index", "--quiet",
static void submodule_reset_index(const char *path)
{
struct child_process cp = CHILD_PROCESS_INIT;
- prepare_submodule_repo_env_no_git_dir(&cp.env_array);
+ prepare_submodule_repo_env(&cp.env_array);
cp.git_cmd = 1;
cp.no_stdin = 1;
}
}
- prepare_submodule_repo_env_no_git_dir(&cp.env_array);
+ prepare_submodule_repo_env(&cp.env_array);
cp.git_cmd = 1;
cp.no_stdin = 1;
argv_array_pushf(&cp.args, "--super-prefix=%s%s/",
get_super_prefix_or_empty(), path);
- argv_array_pushl(&cp.args, "read-tree", NULL);
+ argv_array_pushl(&cp.args, "read-tree", "--recurse-submodules", NULL);
if (flags & SUBMODULE_MOVE_HEAD_DRY_RUN)
argv_array_push(&cp.args, "-n");
if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) {
if (new) {
- struct child_process cp1 = CHILD_PROCESS_INIT;
+ child_process_init(&cp);
/* also set the HEAD accordingly */
- cp1.git_cmd = 1;
- cp1.no_stdin = 1;
- cp1.dir = path;
+ cp.git_cmd = 1;
+ cp.no_stdin = 1;
+ cp.dir = path;
- argv_array_pushl(&cp1.args, "update-ref", "HEAD", new, NULL);
+ prepare_submodule_repo_env(&cp.env_array);
+ argv_array_pushl(&cp.args, "update-ref", "HEAD", new, NULL);
- if (run_command(&cp1)) {
+ if (run_command(&cp)) {
ret = -1;
goto out;
}
#define MERGE_WARNING(path, msg) \
warning("Failed to merge submodule %s (%s)", path, msg);
-int merge_submodule(unsigned char result[20], const char *path,
- const unsigned char base[20], const unsigned char a[20],
- const unsigned char b[20], int search)
+int merge_submodule(struct object_id *result, const char *path,
+ const struct object_id *base, const struct object_id *a,
+ const struct object_id *b, int search)
{
struct commit *commit_base, *commit_a, *commit_b;
int parent_count;
int i;
/* store a in result in case we fail */
- hashcpy(result, a);
+ oidcpy(result, a);
/* we can not handle deletion conflicts */
- if (is_null_sha1(base))
+ if (is_null_oid(base))
return 0;
- if (is_null_sha1(a))
+ if (is_null_oid(a))
return 0;
- if (is_null_sha1(b))
+ if (is_null_oid(b))
return 0;
if (add_submodule_odb(path)) {
/* Case #1: a is contained in b or vice versa */
if (in_merge_bases(commit_a, commit_b)) {
- hashcpy(result, b);
+ oidcpy(result, b);
return 1;
}
if (in_merge_bases(commit_b, commit_a)) {
- hashcpy(result, a);
+ oidcpy(result, a);
return 1;
}