From: Junio C Hamano Date: Mon, 26 Sep 2016 23:09:14 +0000 (-0700) Subject: Merge branch 'rs/cocci' X-Git-Tag: v2.11.0-rc0~118 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/85f34a929dc0f8c82f7167fe100d5264d7374876?ds=inline;hp=-c Merge branch 'rs/cocci' Code cleanup. * rs/cocci: use strbuf_addstr() for adding constant strings to a strbuf, part 2 add coccicheck make target contrib/coccinelle: fix semantic patch for oid_to_hex_r() --- 85f34a929dc0f8c82f7167fe100d5264d7374876 diff --combined Makefile index df4f86bb30,4b5b1a953d..e8b060a235 --- a/Makefile +++ b/Makefile @@@ -296,11 -296,6 +296,11 @@@ all: # Define USE_NED_ALLOCATOR if you want to replace the platforms default # memory allocators with the nedmalloc allocator written by Niall Douglas. # +# Define OVERRIDE_STRDUP to override the libc version of strdup(3). +# This is necessary when using a custom allocator in order to avoid +# crashes due to allocation and free working on different 'heaps'. +# It's defined automatically if USE_NED_ALLOCATOR is set. +# # Define NO_REGEX if you have no or inferior regex support in your C library. # # Define HAVE_DEV_TTY if your system can open /dev/tty to interact with the @@@ -461,6 -456,7 +461,7 @@@ CURL_CONFIG = curl-confi PTHREAD_LIBS = -lpthread PTHREAD_CFLAGS = GCOV = gcov + SPATCH = spatch export TCL_PATH TCLTK_PATH @@@ -696,7 -692,6 +697,7 @@@ LIB_OBJS += abspath. LIB_OBJS += advice.o LIB_OBJS += alias.o LIB_OBJS += alloc.o +LIB_OBJS += apply.o LIB_OBJS += archive.o LIB_OBJS += archive-tar.o LIB_OBJS += archive-zip.o @@@ -1462,14 -1457,8 +1463,14 @@@ ifdef NATIVE_CRL endif ifdef USE_NED_ALLOCATOR - COMPAT_CFLAGS += -Icompat/nedmalloc - COMPAT_OBJS += compat/nedmalloc/nedmalloc.o + COMPAT_CFLAGS += -Icompat/nedmalloc + COMPAT_OBJS += compat/nedmalloc/nedmalloc.o + OVERRIDE_STRDUP = YesPlease +endif + +ifdef OVERRIDE_STRDUP + COMPAT_CFLAGS += -DOVERRIDE_STRDUP + COMPAT_OBJS += compat/strdup.o endif ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT @@@ -2041,7 -2030,7 +2042,7 @@@ endi ifdef USE_NED_ALLOCATOR compat/nedmalloc/nedmalloc.sp compat/nedmalloc/nedmalloc.o: EXTRA_CPPFLAGS = \ - -DNDEBUG -DOVERRIDE_STRDUP -DREPLACE_SYSTEM_ALLOCATOR + -DNDEBUG -DREPLACE_SYSTEM_ALLOCATOR compat/nedmalloc/nedmalloc.sp: SPARSE_FLAGS += -Wno-non-pointer-null endif @@@ -2308,6 -2297,18 +2309,18 @@@ check: common-cmds. exit 1; \ fi + C_SOURCES = $(patsubst %.o,%.c,$(C_OBJ)) + %.cocci.patch: %.cocci $(C_SOURCES) + @echo ' ' SPATCH $<; \ + for f in $(C_SOURCES); do \ + $(SPATCH) --sp-file $< $$f; \ + done >$@ 2>$@.log; \ + if test -s $@; \ + then \ + echo ' ' SPATCH result: $@; \ + fi + coccicheck: $(patsubst %.cocci,%.cocci.patch,$(wildcard contrib/coccinelle/*.cocci)) + ### Installation rules ifneq ($(filter /%,$(firstword $(template_dir))),) @@@ -2499,6 -2500,7 +2512,7 @@@ clean: profile-clean coverage-clea $(RM) -r $(GIT_TARNAME) .doc-tmp-dir $(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz $(RM) $(htmldocs).tar.gz $(manpages).tar.gz + $(RM) contrib/coccinelle/*.cocci.patch* $(MAKE) -C Documentation/ clean ifndef NO_PERL $(MAKE) -C gitweb clean diff --combined builtin/submodule--helper.c index 7b8ddfe6cf,8807539115..432794b130 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@@ -296,8 -296,7 +296,8 @@@ static int module_list(int argc, const if (ce_stage(ce)) printf("%06o %s U\t", ce->ce_mode, sha1_to_hex(null_sha1)); else - printf("%06o %s %d\t", ce->ce_mode, sha1_to_hex(ce->sha1), ce_stage(ce)); + printf("%06o %s %d\t", ce->ce_mode, + oid_to_hex(&ce->oid), ce_stage(ce)); utf8_fprintf(stdout, "%s\n", ce->name); } @@@ -443,7 -442,7 +443,7 @@@ static int module_name(int argc, const } static int clone_submodule(const char *path, const char *gitdir, const char *url, - const char *depth, const char *reference, int quiet) + const char *depth, struct string_list *reference, int quiet) { struct child_process cp = CHILD_PROCESS_INIT; @@@ -453,12 -452,8 +453,12 @@@ argv_array_push(&cp.args, "--quiet"); if (depth && *depth) argv_array_pushl(&cp.args, "--depth", depth, NULL); - if (reference && *reference) - argv_array_pushl(&cp.args, "--reference", reference, NULL); + if (reference->nr) { + struct string_list_item *item; + for_each_string_list_item(item, reference) + argv_array_pushl(&cp.args, "--reference", + item->string, NULL); + } if (gitdir && *gitdir) argv_array_pushl(&cp.args, "--separate-git-dir", gitdir, NULL); @@@ -472,114 -467,15 +472,114 @@@ return run_command(&cp); } +struct submodule_alternate_setup { + const char *submodule_name; + enum SUBMODULE_ALTERNATE_ERROR_MODE { + SUBMODULE_ALTERNATE_ERROR_DIE, + SUBMODULE_ALTERNATE_ERROR_INFO, + SUBMODULE_ALTERNATE_ERROR_IGNORE + } error_mode; + struct string_list *reference; +}; +#define SUBMODULE_ALTERNATE_SETUP_INIT { NULL, \ + SUBMODULE_ALTERNATE_ERROR_IGNORE, NULL } + +static int add_possible_reference_from_superproject( + struct alternate_object_database *alt, void *sas_cb) +{ + struct submodule_alternate_setup *sas = sas_cb; + + /* directory name, minus trailing slash */ + size_t namelen = alt->name - alt->base - 1; + struct strbuf name = STRBUF_INIT; + strbuf_add(&name, alt->base, namelen); + + /* + * If the alternate object store is another repository, try the + * standard layout with .git/modules//objects + */ + if (ends_with(name.buf, ".git/objects")) { + char *sm_alternate; + struct strbuf sb = STRBUF_INIT; + struct strbuf err = STRBUF_INIT; + strbuf_add(&sb, name.buf, name.len - strlen("objects")); + /* + * We need to end the new path with '/' to mark it as a dir, + * otherwise a submodule name containing '/' will be broken + * as the last part of a missing submodule reference would + * be taken as a file name. + */ + strbuf_addf(&sb, "modules/%s/", sas->submodule_name); + + sm_alternate = compute_alternate_path(sb.buf, &err); + if (sm_alternate) { + string_list_append(sas->reference, xstrdup(sb.buf)); + free(sm_alternate); + } else { + switch (sas->error_mode) { + case SUBMODULE_ALTERNATE_ERROR_DIE: + die(_("submodule '%s' cannot add alternate: %s"), + sas->submodule_name, err.buf); + case SUBMODULE_ALTERNATE_ERROR_INFO: + fprintf(stderr, _("submodule '%s' cannot add alternate: %s"), + sas->submodule_name, err.buf); + case SUBMODULE_ALTERNATE_ERROR_IGNORE: + ; /* nothing */ + } + } + strbuf_release(&sb); + } + + strbuf_release(&name); + return 0; +} + +static void prepare_possible_alternates(const char *sm_name, + struct string_list *reference) +{ + char *sm_alternate = NULL, *error_strategy = NULL; + struct submodule_alternate_setup sas = SUBMODULE_ALTERNATE_SETUP_INIT; + + git_config_get_string("submodule.alternateLocation", &sm_alternate); + if (!sm_alternate) + return; + + git_config_get_string("submodule.alternateErrorStrategy", &error_strategy); + + if (!error_strategy) + error_strategy = xstrdup("die"); + + sas.submodule_name = sm_name; + sas.reference = reference; + if (!strcmp(error_strategy, "die")) + sas.error_mode = SUBMODULE_ALTERNATE_ERROR_DIE; + else if (!strcmp(error_strategy, "info")) + sas.error_mode = SUBMODULE_ALTERNATE_ERROR_INFO; + else if (!strcmp(error_strategy, "ignore")) + sas.error_mode = SUBMODULE_ALTERNATE_ERROR_IGNORE; + else + die(_("Value '%s' for submodule.alternateErrorStrategy is not recognized"), error_strategy); + + if (!strcmp(sm_alternate, "superproject")) + foreach_alt_odb(add_possible_reference_from_superproject, &sas); + else if (!strcmp(sm_alternate, "no")) + ; /* do nothing */ + else + die(_("Value '%s' for submodule.alternateLocation is not recognized"), sm_alternate); + + free(sm_alternate); + free(error_strategy); +} + static int module_clone(int argc, const char **argv, const char *prefix) { - const char *name = NULL, *url = NULL; - const char *reference = NULL, *depth = NULL; + const char *name = NULL, *url = NULL, *depth = NULL; int quiet = 0; FILE *submodule_dot_git; char *p, *path = NULL, *sm_gitdir; struct strbuf rel_path = STRBUF_INIT; struct strbuf sb = STRBUF_INIT; + struct string_list reference = STRING_LIST_INIT_NODUP; struct option module_clone_options[] = { OPT_STRING(0, "prefix", &prefix, @@@ -594,8 -490,8 +594,8 @@@ OPT_STRING(0, "url", &url, N_("string"), N_("url where to clone the submodule from")), - OPT_STRING(0, "reference", &reference, - N_("string"), + OPT_STRING_LIST(0, "reference", &reference, + N_("repo"), N_("reference repository")), OPT_STRING(0, "depth", &depth, N_("string"), @@@ -631,10 -527,7 +631,10 @@@ if (!file_exists(sm_gitdir)) { if (safe_create_leading_directories_const(sm_gitdir) < 0) die(_("could not create directory '%s'"), sm_gitdir); - if (clone_submodule(path, sm_gitdir, url, depth, reference, quiet)) + + prepare_possible_alternates(name, &reference); + + if (clone_submodule(path, sm_gitdir, url, depth, &reference, quiet)) die(_("clone of '%s' into submodule path '%s' failed"), url, path); } else { @@@ -686,7 -579,7 +686,7 @@@ struct submodule_update_clone /* configuration parameters which are passed on to the children */ int quiet; int recommend_shallow; - const char *reference; + struct string_list references; const char *depth; const char *recursive_prefix; const char *prefix; @@@ -702,8 -595,7 +702,8 @@@ int failed_clones_nr, failed_clones_alloc; }; #define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \ - SUBMODULE_UPDATE_STRATEGY_INIT, 0, -1, NULL, NULL, NULL, NULL, \ + SUBMODULE_UPDATE_STRATEGY_INIT, 0, -1, STRING_LIST_INIT_DUP, \ + NULL, NULL, NULL, \ STRING_LIST_INIT_DUP, 0, NULL, 0, 0} @@@ -791,7 -683,7 +791,7 @@@ static int prepare_to_clone_next_submod strbuf_reset(&sb); strbuf_addf(&sb, "%06o %s %d %d\t%s\n", ce->ce_mode, - sha1_to_hex(ce->sha1), ce_stage(ce), + oid_to_hex(&ce->oid), ce_stage(ce), needs_cloning, ce->name); string_list_append(&suc->projectlines, sb.buf); @@@ -813,11 -705,8 +813,11 @@@ argv_array_pushl(&child->args, "--path", sub->path, NULL); argv_array_pushl(&child->args, "--name", sub->name, NULL); argv_array_pushl(&child->args, "--url", url, NULL); - if (suc->reference) - argv_array_push(&child->args, suc->reference); + if (suc->references.nr) { + struct string_list_item *item; + for_each_string_list_item(item, &suc->references) + argv_array_pushl(&child->args, "--reference", item->string, NULL); + } if (suc->depth) argv_array_push(&child->args, suc->depth); @@@ -860,8 -749,9 +860,9 @@@ static int update_clone_get_next_task(s ce = suc->failed_clones[index]; if (!prepare_to_clone_next_submodule(ce, child, suc, err)) { suc->current ++; - strbuf_addf(err, "BUG: submodule considered for cloning," - "doesn't need cloning any more?\n"); + strbuf_addstr(err, "BUG: submodule considered for " + "cloning, doesn't need cloning " + "any more?\n"); return 0; } p = xmalloc(sizeof(*p)); @@@ -940,7 -830,7 +941,7 @@@ static int update_clone(int argc, cons OPT_STRING(0, "update", &update, N_("string"), N_("rebase, merge, checkout or none")), - OPT_STRING(0, "reference", &suc.reference, N_("repo"), + OPT_STRING_LIST(0, "reference", &suc.references, N_("repo"), N_("reference repository")), OPT_STRING(0, "depth", &suc.depth, "", N_("Create a shallow clone truncated to the " diff --combined merge-recursive.c index 3750d2534f,d2b191b8c6..5200d5ccf8 --- a/merge-recursive.c +++ b/merge-recursive.c @@@ -206,7 -206,7 +206,7 @@@ static void output_commit_title(struct find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV)); if (parse_commit(commit) != 0) - strbuf_addf(&o->obuf, _("(bad commit)\n")); + strbuf_addstr(&o->obuf, _("(bad commit)\n")); else { const char *title; const char *msg = get_commit_buffer(commit, NULL); @@@ -382,7 -382,7 +382,7 @@@ static struct string_list *get_unmerged } e = item->util; e->stages[ce_stage(ce)].mode = ce->ce_mode; - hashcpy(e->stages[ce_stage(ce)].oid.hash, ce->sha1); + oidcpy(&e->stages[ce_stage(ce)].oid, &ce->oid); } return unmerged; @@@ -910,9 -910,9 +910,9 @@@ static int merge_3way(struct merge_opti name2 = mkpathdup("%s", branch2); } - read_mmblob(&orig, one->oid.hash); - read_mmblob(&src1, a->oid.hash); - read_mmblob(&src2, b->oid.hash); + read_mmblob(&orig, &one->oid); + read_mmblob(&src1, &a->oid); + read_mmblob(&src2, &b->oid); merge_status = ll_merge(result_buf, a->path, &orig, base_name, &src1, name1, &src2, name2, &ll_opts); diff --combined wt-status.c index 9a14658e7e,39470dadf0..9628c1d5d7 --- a/wt-status.c +++ b/wt-status.c @@@ -139,7 -139,7 +139,7 @@@ void wt_status_prepare(struct wt_statu s->display_comment_prefix = 0; } -static void wt_status_print_unmerged_header(struct wt_status *s) +static void wt_longstatus_print_unmerged_header(struct wt_status *s) { int i; int del_mod_conflict = 0; @@@ -191,7 -191,7 +191,7 @@@ status_printf_ln(s, c, "%s", ""); } -static void wt_status_print_cached_header(struct wt_status *s) +static void wt_longstatus_print_cached_header(struct wt_status *s) { const char *c = color(WT_STATUS_HEADER, s); @@@ -207,9 -207,9 +207,9 @@@ status_printf_ln(s, c, "%s", ""); } -static void wt_status_print_dirty_header(struct wt_status *s, - int has_deleted, - int has_dirty_submodules) +static void wt_longstatus_print_dirty_header(struct wt_status *s, + int has_deleted, + int has_dirty_submodules) { const char *c = color(WT_STATUS_HEADER, s); @@@ -226,9 -226,9 +226,9 @@@ status_printf_ln(s, c, "%s", ""); } -static void wt_status_print_other_header(struct wt_status *s, - const char *what, - const char *how) +static void wt_longstatus_print_other_header(struct wt_status *s, + const char *what, + const char *how) { const char *c = color(WT_STATUS_HEADER, s); status_printf_ln(s, c, "%s:", what); @@@ -238,7 -238,7 +238,7 @@@ status_printf_ln(s, c, "%s", ""); } -static void wt_status_print_trailer(struct wt_status *s) +static void wt_longstatus_print_trailer(struct wt_status *s) { status_printf_ln(s, color(WT_STATUS_HEADER, s), "%s", ""); } @@@ -304,8 -304,8 +304,8 @@@ static int maxwidth(const char *(*label return result; } -static void wt_status_print_unmerged_data(struct wt_status *s, - struct string_list_item *it) +static void wt_longstatus_print_unmerged_data(struct wt_status *s, + struct string_list_item *it) { const char *c = color(WT_STATUS_UNMERGED, s); struct wt_status_change_data *d = it->util; @@@ -331,9 -331,9 +331,9 @@@ strbuf_release(&onebuf); } -static void wt_status_print_change_data(struct wt_status *s, - int change_type, - struct string_list_item *it) +static void wt_longstatus_print_change_data(struct wt_status *s, + int change_type, + struct string_list_item *it) { struct wt_status_change_data *d = it->util; const char *c = color(change_type, s); @@@ -367,18 -367,18 +367,18 @@@ if (d->new_submodule_commits || d->dirty_submodule) { strbuf_addstr(&extra, " ("); if (d->new_submodule_commits) - strbuf_addf(&extra, _("new commits, ")); + strbuf_addstr(&extra, _("new commits, ")); if (d->dirty_submodule & DIRTY_SUBMODULE_MODIFIED) - strbuf_addf(&extra, _("modified content, ")); + strbuf_addstr(&extra, _("modified content, ")); if (d->dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) - strbuf_addf(&extra, _("untracked content, ")); + strbuf_addstr(&extra, _("untracked content, ")); strbuf_setlen(&extra, extra.len - 2); strbuf_addch(&extra, ')'); } status = d->worktree_status; break; default: - die("BUG: unhandled change_type %d in wt_status_print_change_data", + die("BUG: unhandled change_type %d in wt_longstatus_print_change_data", change_type); } @@@ -434,31 -434,6 +434,31 @@@ static void wt_status_collect_changed_c if (S_ISGITLINK(p->two->mode)) d->new_submodule_commits = !!oidcmp(&p->one->oid, &p->two->oid); + + switch (p->status) { + case DIFF_STATUS_ADDED: + die("BUG: worktree status add???"); + break; + + case DIFF_STATUS_DELETED: + d->mode_index = p->one->mode; + oidcpy(&d->oid_index, &p->one->oid); + /* mode_worktree is zero for a delete. */ + break; + + case DIFF_STATUS_MODIFIED: + case DIFF_STATUS_TYPE_CHANGED: + case DIFF_STATUS_UNMERGED: + d->mode_index = p->one->mode; + d->mode_worktree = p->two->mode; + oidcpy(&d->oid_index, &p->one->oid); + break; + + case DIFF_STATUS_UNKNOWN: + die("BUG: worktree status unknown???"); + break; + } + } } @@@ -504,36 -479,12 +504,36 @@@ static void wt_status_collect_updated_c if (!d->index_status) d->index_status = p->status; switch (p->status) { + case DIFF_STATUS_ADDED: + /* Leave {mode,oid}_head zero for an add. */ + d->mode_index = p->two->mode; + oidcpy(&d->oid_index, &p->two->oid); + break; + case DIFF_STATUS_DELETED: + d->mode_head = p->one->mode; + oidcpy(&d->oid_head, &p->one->oid); + /* Leave {mode,oid}_index zero for a delete. */ + break; + case DIFF_STATUS_COPIED: case DIFF_STATUS_RENAMED: d->head_path = xstrdup(p->one->path); + d->score = p->score * 100 / MAX_SCORE; + /* fallthru */ + case DIFF_STATUS_MODIFIED: + case DIFF_STATUS_TYPE_CHANGED: + d->mode_head = p->one->mode; + d->mode_index = p->two->mode; + oidcpy(&d->oid_head, &p->one->oid); + oidcpy(&d->oid_index, &p->two->oid); break; case DIFF_STATUS_UNMERGED: d->stagemask = unmerged_mask(p->two->path); + /* + * Don't bother setting {mode,oid}_{head,index} since the print + * code will output the stage values directly and not use the + * values in these fields. + */ break; } } @@@ -614,17 -565,9 +614,17 @@@ static void wt_status_collect_changes_i if (ce_stage(ce)) { d->index_status = DIFF_STATUS_UNMERGED; d->stagemask |= (1 << (ce_stage(ce) - 1)); - } - else + /* + * Don't bother setting {mode,oid}_{head,index} since the print + * code will output the stage values directly and not use the + * values in these fields. + */ + } else { d->index_status = DIFF_STATUS_ADDED; + /* Leave {mode,oid}_head zero for adds. */ + d->mode_index = ce->ce_mode; + hashcpy(d->oid_index.hash, ce->oid.hash); + } } } @@@ -684,7 -627,7 +684,7 @@@ void wt_status_collect(struct wt_statu wt_status_collect_untracked(s); } -static void wt_status_print_unmerged(struct wt_status *s) +static void wt_longstatus_print_unmerged(struct wt_status *s) { int shown_header = 0; int i; @@@ -697,17 -640,17 +697,17 @@@ if (!d->stagemask) continue; if (!shown_header) { - wt_status_print_unmerged_header(s); + wt_longstatus_print_unmerged_header(s); shown_header = 1; } - wt_status_print_unmerged_data(s, it); + wt_longstatus_print_unmerged_data(s, it); } if (shown_header) - wt_status_print_trailer(s); + wt_longstatus_print_trailer(s); } -static void wt_status_print_updated(struct wt_status *s) +static void wt_longstatus_print_updated(struct wt_status *s) { int shown_header = 0; int i; @@@ -721,14 -664,14 +721,14 @@@ d->index_status == DIFF_STATUS_UNMERGED) continue; if (!shown_header) { - wt_status_print_cached_header(s); + wt_longstatus_print_cached_header(s); s->commitable = 1; shown_header = 1; } - wt_status_print_change_data(s, WT_STATUS_UPDATED, it); + wt_longstatus_print_change_data(s, WT_STATUS_UPDATED, it); } if (shown_header) - wt_status_print_trailer(s); + wt_longstatus_print_trailer(s); } /* @@@ -760,7 -703,7 +760,7 @@@ static int wt_status_check_worktree_cha return changes; } -static void wt_status_print_changed(struct wt_status *s) +static void wt_longstatus_print_changed(struct wt_status *s) { int i, dirty_submodules; int worktree_changes = wt_status_check_worktree_changes(s, &dirty_submodules); @@@ -768,7 -711,7 +768,7 @@@ if (!worktree_changes) return; - wt_status_print_dirty_header(s, worktree_changes < 0, dirty_submodules); + wt_longstatus_print_dirty_header(s, worktree_changes < 0, dirty_submodules); for (i = 0; i < s->change.nr; i++) { struct wt_status_change_data *d; @@@ -778,12 -721,12 +778,12 @@@ if (!d->worktree_status || d->worktree_status == DIFF_STATUS_UNMERGED) continue; - wt_status_print_change_data(s, WT_STATUS_CHANGED, it); + wt_longstatus_print_change_data(s, WT_STATUS_CHANGED, it); } - wt_status_print_trailer(s); + wt_longstatus_print_trailer(s); } -static void wt_status_print_submodule_summary(struct wt_status *s, int uncommitted) +static void wt_longstatus_print_submodule_summary(struct wt_status *s, int uncommitted) { struct child_process sm_summary = CHILD_PROCESS_INIT; struct strbuf cmd_stdout = STRBUF_INIT; @@@ -829,10 -772,10 +829,10 @@@ strbuf_release(&summary); } -static void wt_status_print_other(struct wt_status *s, - struct string_list *l, - const char *what, - const char *how) +static void wt_longstatus_print_other(struct wt_status *s, + struct string_list *l, + const char *what, + const char *how) { int i; struct strbuf buf = STRBUF_INIT; @@@ -842,7 -785,7 +842,7 @@@ if (!l->nr) return; - wt_status_print_other_header(s, what, how); + wt_longstatus_print_other_header(s, what, how); for (i = 0; i < l->nr; i++) { struct string_list_item *it; @@@ -902,7 -845,7 +902,7 @@@ void wt_status_add_cut_line(FILE *fp strbuf_release(&buf); } -static void wt_status_print_verbose(struct wt_status *s) +static void wt_longstatus_print_verbose(struct wt_status *s) { struct rev_info rev; struct setup_revision_opt opt; @@@ -935,7 -878,7 +935,7 @@@ if (s->verbose > 1 && s->commitable) { /* print_updated() printed a header, so do we */ if (s->fp != stdout) - wt_status_print_trailer(s); + wt_longstatus_print_trailer(s); status_printf_ln(s, c, _("Changes to be committed:")); rev.diffopt.a_prefix = "c/"; rev.diffopt.b_prefix = "i/"; @@@ -953,7 -896,7 +953,7 @@@ } } -static void wt_status_print_tracking(struct wt_status *s) +static void wt_longstatus_print_tracking(struct wt_status *s) { struct strbuf sb = STRBUF_INIT; const char *cp, *ep, *branch_name; @@@ -1019,7 -962,7 +1019,7 @@@ static void show_merge_in_progress(stru status_printf_ln(s, color, _(" (use \"git commit\" to conclude merge)")); } - wt_status_print_trailer(s); + wt_longstatus_print_trailer(s); } static void show_am_in_progress(struct wt_status *s, @@@ -1040,7 -983,7 +1040,7 @@@ status_printf_ln(s, color, _(" (use \"git am --abort\" to restore the original branch)")); } - wt_status_print_trailer(s); + wt_longstatus_print_trailer(s); } static char *read_line_from_git_path(const char *filename) @@@ -1264,7 -1207,7 +1264,7 @@@ static void show_rebase_in_progress(str _(" (use \"git rebase --continue\" once you are satisfied with your changes)")); } } - wt_status_print_trailer(s); + wt_longstatus_print_trailer(s); } static void show_cherry_pick_in_progress(struct wt_status *s, @@@ -1283,7 -1226,7 +1283,7 @@@ status_printf_ln(s, color, _(" (use \"git cherry-pick --abort\" to cancel the cherry-pick operation)")); } - wt_status_print_trailer(s); + wt_longstatus_print_trailer(s); } static void show_revert_in_progress(struct wt_status *s, @@@ -1302,7 -1245,7 +1302,7 @@@ status_printf_ln(s, color, _(" (use \"git revert --abort\" to cancel the revert operation)")); } - wt_status_print_trailer(s); + wt_longstatus_print_trailer(s); } static void show_bisect_in_progress(struct wt_status *s, @@@ -1319,7 -1262,7 +1319,7 @@@ if (s->hints) status_printf_ln(s, color, _(" (use \"git bisect reset\" to get back to the original branch)")); - wt_status_print_trailer(s); + wt_longstatus_print_trailer(s); } /* @@@ -1489,8 -1432,8 +1489,8 @@@ void wt_status_get_state(struct wt_stat wt_status_get_detached_from(state); } -static void wt_status_print_state(struct wt_status *s, - struct wt_status_state *state) +static void wt_longstatus_print_state(struct wt_status *s, + struct wt_status_state *state) { const char *state_color = color(WT_STATUS_HEADER, s); if (state->merge_in_progress) @@@ -1507,7 -1450,7 +1507,7 @@@ show_bisect_in_progress(s, state, state_color); } -void wt_status_print(struct wt_status *s) +static void wt_longstatus_print(struct wt_status *s) { const char *branch_color = color(WT_STATUS_ONBRANCH, s); const char *branch_status_color = color(WT_STATUS_HEADER, s); @@@ -1544,10 -1487,10 +1544,10 @@@ status_printf_more(s, branch_status_color, "%s", on_what); status_printf_more(s, branch_color, "%s\n", branch_name); if (!s->is_initial) - wt_status_print_tracking(s); + wt_longstatus_print_tracking(s); } - wt_status_print_state(s, &state); + wt_longstatus_print_state(s, &state); free(state.branch); free(state.onto); free(state.detached_from); @@@ -1558,19 -1501,19 +1558,19 @@@ status_printf_ln(s, color(WT_STATUS_HEADER, s), "%s", ""); } - wt_status_print_updated(s); - wt_status_print_unmerged(s); - wt_status_print_changed(s); + wt_longstatus_print_updated(s); + wt_longstatus_print_unmerged(s); + wt_longstatus_print_changed(s); if (s->submodule_summary && (!s->ignore_submodule_arg || strcmp(s->ignore_submodule_arg, "all"))) { - wt_status_print_submodule_summary(s, 0); /* staged */ - wt_status_print_submodule_summary(s, 1); /* unstaged */ + wt_longstatus_print_submodule_summary(s, 0); /* staged */ + wt_longstatus_print_submodule_summary(s, 1); /* unstaged */ } if (s->show_untracked_files) { - wt_status_print_other(s, &s->untracked, _("Untracked files"), "add"); + wt_longstatus_print_other(s, &s->untracked, _("Untracked files"), "add"); if (s->show_ignored_files) - wt_status_print_other(s, &s->ignored, _("Ignored files"), "add -f"); + wt_longstatus_print_other(s, &s->ignored, _("Ignored files"), "add -f"); if (advice_status_u_option && 2000 < s->untracked_in_ms) { status_printf_ln(s, GIT_COLOR_NORMAL, "%s", ""); status_printf_ln(s, GIT_COLOR_NORMAL, @@@ -1585,7 -1528,7 +1585,7 @@@ ? _(" (use -u option to show untracked files)") : ""); if (s->verbose) - wt_status_print_verbose(s); + wt_longstatus_print_verbose(s); if (!s->commitable) { if (s->amend) status_printf_ln(s, GIT_COLOR_NORMAL, _("No changes")); @@@ -1774,7 -1717,7 +1774,7 @@@ static void wt_shortstatus_print_tracki fputc(s->null_termination ? '\0' : '\n', s->fp); } -void wt_shortstatus_print(struct wt_status *s) +static void wt_shortstatus_print(struct wt_status *s) { int i; @@@ -1806,7 -1749,7 +1806,7 @@@ } } -void wt_porcelain_print(struct wt_status *s) +static void wt_porcelain_print(struct wt_status *s) { s->use_color = 0; s->relative_paths = 0; @@@ -1814,398 -1757,3 +1814,398 @@@ s->no_gettext = 1; wt_shortstatus_print(s); } + +/* + * Print branch information for porcelain v2 output. These lines + * are printed when the '--branch' parameter is given. + * + * # branch.oid + * # branch.head + * [# branch.upstream + * [# branch.ab + -]] + * + * ::= the current commit hash or the the literal + * "(initial)" to indicate an initialized repo + * with no commits. + * + * ::= the current branch name or + * "(detached)" literal when detached head or + * "(unknown)" when something is wrong. + * + * ::= the upstream branch name, when set. + * + * ::= integer ahead value, when upstream set + * and the commit is present (not gone). + * + * ::= integer behind value, when upstream set + * and commit is present. + * + * + * The end-of-line is defined by the -z flag. + * + * ::= NUL when -z, + * LF when NOT -z. + * + */ +static void wt_porcelain_v2_print_tracking(struct wt_status *s) +{ + struct branch *branch; + const char *base; + const char *branch_name; + struct wt_status_state state; + int ab_info, nr_ahead, nr_behind; + char eol = s->null_termination ? '\0' : '\n'; + + memset(&state, 0, sizeof(state)); + wt_status_get_state(&state, s->branch && !strcmp(s->branch, "HEAD")); + + fprintf(s->fp, "# branch.oid %s%c", + (s->is_initial ? "(initial)" : sha1_to_hex(s->sha1_commit)), + eol); + + if (!s->branch) + fprintf(s->fp, "# branch.head %s%c", "(unknown)", eol); + else { + if (!strcmp(s->branch, "HEAD")) { + fprintf(s->fp, "# branch.head %s%c", "(detached)", eol); + + if (state.rebase_in_progress || state.rebase_interactive_in_progress) + branch_name = state.onto; + else if (state.detached_from) + branch_name = state.detached_from; + else + branch_name = ""; + } else { + branch_name = NULL; + skip_prefix(s->branch, "refs/heads/", &branch_name); + + fprintf(s->fp, "# branch.head %s%c", branch_name, eol); + } + + /* Lookup stats on the upstream tracking branch, if set. */ + branch = branch_get(branch_name); + base = NULL; + ab_info = (stat_tracking_info(branch, &nr_ahead, &nr_behind, &base) == 0); + if (base) { + base = shorten_unambiguous_ref(base, 0); + fprintf(s->fp, "# branch.upstream %s%c", base, eol); + free((char *)base); + + if (ab_info) + fprintf(s->fp, "# branch.ab +%d -%d%c", nr_ahead, nr_behind, eol); + } + } + + free(state.branch); + free(state.onto); + free(state.detached_from); +} + +/* + * Convert various submodule status values into a + * fixed-length string of characters in the buffer provided. + */ +static void wt_porcelain_v2_submodule_state( + struct wt_status_change_data *d, + char sub[5]) +{ + if (S_ISGITLINK(d->mode_head) || + S_ISGITLINK(d->mode_index) || + S_ISGITLINK(d->mode_worktree)) { + sub[0] = 'S'; + sub[1] = d->new_submodule_commits ? 'C' : '.'; + sub[2] = (d->dirty_submodule & DIRTY_SUBMODULE_MODIFIED) ? 'M' : '.'; + sub[3] = (d->dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) ? 'U' : '.'; + } else { + sub[0] = 'N'; + sub[1] = '.'; + sub[2] = '.'; + sub[3] = '.'; + } + sub[4] = 0; +} + +/* + * Fix-up changed entries before we print them. + */ +static void wt_porcelain_v2_fix_up_changed( + struct string_list_item *it, + struct wt_status *s) +{ + struct wt_status_change_data *d = it->util; + + if (!d->index_status) { + /* + * This entry is unchanged in the index (relative to the head). + * Therefore, the collect_updated_cb was never called for this + * entry (during the head-vs-index scan) and so the head column + * fields were never set. + * + * We must have data for the index column (from the + * index-vs-worktree scan (otherwise, this entry should not be + * in the list of changes)). + * + * Copy index column fields to the head column, so that our + * output looks complete. + */ + assert(d->mode_head == 0); + d->mode_head = d->mode_index; + oidcpy(&d->oid_head, &d->oid_index); + } + + if (!d->worktree_status) { + /* + * This entry is unchanged in the worktree (relative to the index). + * Therefore, the collect_changed_cb was never called for this entry + * (during the index-vs-worktree scan) and so the worktree column + * fields were never set. + * + * We must have data for the index column (from the head-vs-index + * scan). + * + * Copy the index column fields to the worktree column so that + * our output looks complete. + * + * Note that we only have a mode field in the worktree column + * because the scan code tries really hard to not have to compute it. + */ + assert(d->mode_worktree == 0); + d->mode_worktree = d->mode_index; + } +} + +/* + * Print porcelain v2 info for tracked entries with changes. + */ +static void wt_porcelain_v2_print_changed_entry( + struct string_list_item *it, + struct wt_status *s) +{ + struct wt_status_change_data *d = it->util; + struct strbuf buf_index = STRBUF_INIT; + struct strbuf buf_head = STRBUF_INIT; + const char *path_index = NULL; + const char *path_head = NULL; + char key[3]; + char submodule_token[5]; + char sep_char, eol_char; + + wt_porcelain_v2_fix_up_changed(it, s); + wt_porcelain_v2_submodule_state(d, submodule_token); + + key[0] = d->index_status ? d->index_status : '.'; + key[1] = d->worktree_status ? d->worktree_status : '.'; + key[2] = 0; + + if (s->null_termination) { + /* + * In -z mode, we DO NOT C-quote pathnames. Current path is ALWAYS first. + * A single NUL character separates them. + */ + sep_char = '\0'; + eol_char = '\0'; + path_index = it->string; + path_head = d->head_path; + } else { + /* + * Path(s) are C-quoted if necessary. Current path is ALWAYS first. + * The source path is only present when necessary. + * A single TAB separates them (because paths can contain spaces + * which are not escaped and C-quoting does escape TAB characters). + */ + sep_char = '\t'; + eol_char = '\n'; + path_index = quote_path(it->string, s->prefix, &buf_index); + if (d->head_path) + path_head = quote_path(d->head_path, s->prefix, &buf_head); + } + + if (path_head) + fprintf(s->fp, "2 %s %s %06o %06o %06o %s %s %c%d %s%c%s%c", + key, submodule_token, + d->mode_head, d->mode_index, d->mode_worktree, + oid_to_hex(&d->oid_head), oid_to_hex(&d->oid_index), + key[0], d->score, + path_index, sep_char, path_head, eol_char); + else + fprintf(s->fp, "1 %s %s %06o %06o %06o %s %s %s%c", + key, submodule_token, + d->mode_head, d->mode_index, d->mode_worktree, + oid_to_hex(&d->oid_head), oid_to_hex(&d->oid_index), + path_index, eol_char); + + strbuf_release(&buf_index); + strbuf_release(&buf_head); +} + +/* + * Print porcelain v2 status info for unmerged entries. + */ +static void wt_porcelain_v2_print_unmerged_entry( + struct string_list_item *it, + struct wt_status *s) +{ + struct wt_status_change_data *d = it->util; + const struct cache_entry *ce; + struct strbuf buf_index = STRBUF_INIT; + const char *path_index = NULL; + int pos, stage, sum; + struct { + int mode; + struct object_id oid; + } stages[3]; + char *key; + char submodule_token[5]; + char unmerged_prefix = 'u'; + char eol_char = s->null_termination ? '\0' : '\n'; + + wt_porcelain_v2_submodule_state(d, submodule_token); + + switch (d->stagemask) { + case 1: key = "DD"; break; /* both deleted */ + case 2: key = "AU"; break; /* added by us */ + case 3: key = "UD"; break; /* deleted by them */ + case 4: key = "UA"; break; /* added by them */ + case 5: key = "DU"; break; /* deleted by us */ + case 6: key = "AA"; break; /* both added */ + case 7: key = "UU"; break; /* both modified */ + default: + die("BUG: unhandled unmerged status %x", d->stagemask); + } + + /* + * Disregard d.aux.porcelain_v2 data that we accumulated + * for the head and index columns during the scans and + * replace with the actual stage data. + * + * Note that this is a last-one-wins for each the individual + * stage [123] columns in the event of multiple cache entries + * for same stage. + */ + memset(stages, 0, sizeof(stages)); + sum = 0; + pos = cache_name_pos(it->string, strlen(it->string)); + assert(pos < 0); + pos = -pos-1; + while (pos < active_nr) { + ce = active_cache[pos++]; + stage = ce_stage(ce); + if (strcmp(ce->name, it->string) || !stage) + break; + stages[stage - 1].mode = ce->ce_mode; + hashcpy(stages[stage - 1].oid.hash, ce->oid.hash); + sum |= (1 << (stage - 1)); + } + if (sum != d->stagemask) + die("BUG: observed stagemask 0x%x != expected stagemask 0x%x", sum, d->stagemask); + + if (s->null_termination) + path_index = it->string; + else + path_index = quote_path(it->string, s->prefix, &buf_index); + + fprintf(s->fp, "%c %s %s %06o %06o %06o %06o %s %s %s %s%c", + unmerged_prefix, key, submodule_token, + stages[0].mode, /* stage 1 */ + stages[1].mode, /* stage 2 */ + stages[2].mode, /* stage 3 */ + d->mode_worktree, + oid_to_hex(&stages[0].oid), /* stage 1 */ + oid_to_hex(&stages[1].oid), /* stage 2 */ + oid_to_hex(&stages[2].oid), /* stage 3 */ + path_index, + eol_char); + + strbuf_release(&buf_index); +} + +/* + * Print porcelain V2 status info for untracked and ignored entries. + */ +static void wt_porcelain_v2_print_other( + struct string_list_item *it, + struct wt_status *s, + char prefix) +{ + struct strbuf buf = STRBUF_INIT; + const char *path; + char eol_char; + + if (s->null_termination) { + path = it->string; + eol_char = '\0'; + } else { + path = quote_path(it->string, s->prefix, &buf); + eol_char = '\n'; + } + + fprintf(s->fp, "%c %s%c", prefix, path, eol_char); + + strbuf_release(&buf); +} + +/* + * Print porcelain V2 status. + * + * [] + * []* + * []* + * []* + * []* + * + */ +static void wt_porcelain_v2_print(struct wt_status *s) +{ + struct wt_status_change_data *d; + struct string_list_item *it; + int i; + + if (s->show_branch) + wt_porcelain_v2_print_tracking(s); + + for (i = 0; i < s->change.nr; i++) { + it = &(s->change.items[i]); + d = it->util; + if (!d->stagemask) + wt_porcelain_v2_print_changed_entry(it, s); + } + + for (i = 0; i < s->change.nr; i++) { + it = &(s->change.items[i]); + d = it->util; + if (d->stagemask) + wt_porcelain_v2_print_unmerged_entry(it, s); + } + + for (i = 0; i < s->untracked.nr; i++) { + it = &(s->untracked.items[i]); + wt_porcelain_v2_print_other(it, s, '?'); + } + + for (i = 0; i < s->ignored.nr; i++) { + it = &(s->ignored.items[i]); + wt_porcelain_v2_print_other(it, s, '!'); + } +} + +void wt_status_print(struct wt_status *s) +{ + switch (s->status_format) { + case STATUS_FORMAT_SHORT: + wt_shortstatus_print(s); + break; + case STATUS_FORMAT_PORCELAIN: + wt_porcelain_print(s); + break; + case STATUS_FORMAT_PORCELAIN_V2: + wt_porcelain_v2_print(s); + break; + case STATUS_FORMAT_UNSPECIFIED: + die("BUG: finalize_deferred_config() should have been called"); + break; + case STATUS_FORMAT_NONE: + case STATUS_FORMAT_LONG: + wt_longstatus_print(s); + break; + } +}