summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2020-02-21 02:06:01 (GMT)
committerJunio C Hamano <gitster@pobox.com>2020-02-21 02:06:01 (GMT)
commit22d8ec25f062df9e4eef68edd44bfe3ad34a08a3 (patch)
treea2b8a7c09604cf72baa6c4357f4320f2dbd71001
parent8634bb497044cc6903d1869603bba9449adef19f (diff)
parent9c5fc392d22895a2d69c8382a83e611fd2a58947 (diff)
downloadgit-22d8ec25f062df9e4eef68edd44bfe3ad34a08a3.zip
git-22d8ec25f062df9e4eef68edd44bfe3ad34a08a3.tar.gz
git-22d8ec25f062df9e4eef68edd44bfe3ad34a08a3.tar.bz2
Merge branch 'hw/advise-ng' into pu
Revamping of the advise API to allow more systematic enumeration of advice knobs in the future. * hw/advise-ng: advice: extract vadvise() from advise() advice: revamp advise API
-rw-r--r--Makefile1
-rw-r--r--advice.c93
-rw-r--r--advice.h53
-rw-r--r--builtin/tag.c4
-rw-r--r--t/helper/test-advise.c16
-rw-r--r--t/helper/test-tool.c1
-rw-r--r--t/helper/test-tool.h1
-rwxr-xr-xt/t0018-advice.sh28
-rwxr-xr-xt/t7004-tag.sh1
9 files changed, 187 insertions, 11 deletions
diff --git a/Makefile b/Makefile
index 9804a07..a596111 100644
--- a/Makefile
+++ b/Makefile
@@ -695,6 +695,7 @@ X =
PROGRAMS += $(patsubst %.o,git-%$X,$(PROGRAM_OBJS))
+TEST_BUILTINS_OBJS += test-advise.o
TEST_BUILTINS_OBJS += test-chmtime.o
TEST_BUILTINS_OBJS += test-config.o
TEST_BUILTINS_OBJS += test-ctype.o
diff --git a/advice.c b/advice.c
index 97f3f98..dad8abe 100644
--- a/advice.c
+++ b/advice.c
@@ -29,7 +29,6 @@ int advice_ignored_hook = 1;
int advice_waiting_for_editor = 1;
int advice_graft_file_deprecated = 1;
int advice_checkout_ambiguous_remote_branch_name = 1;
-int advice_nested_tag = 1;
int advice_submodule_alternate_error_strategy_die = 1;
int advice_add_ignored_file = 1;
int advice_add_empty_pathspec = 1;
@@ -91,7 +90,6 @@ static struct {
{ "waitingForEditor", &advice_waiting_for_editor },
{ "graftFileDeprecated", &advice_graft_file_deprecated },
{ "checkoutAmbiguousRemoteBranchName", &advice_checkout_ambiguous_remote_branch_name },
- { "nestedTag", &advice_nested_tag },
{ "submoduleAlternateErrorStrategyDie", &advice_submodule_alternate_error_strategy_die },
{ "addIgnoredFile", &advice_add_ignored_file },
{ "addEmptyPathspec", &advice_add_empty_pathspec },
@@ -100,15 +98,54 @@ static struct {
{ "pushNonFastForward", &advice_push_update_rejected }
};
-void advise(const char *advice, ...)
+static const char *advice_config_keys[] = {
+ [FETCH_SHOW_FORCED_UPDATES] = "fetchShowForcedUpdates",
+ [PUSH_UPDATE_REJECTED] = "pushUpdateRejected",
+ /* make this an alias for backward compatibility */
+ [PUSH_UPDATE_REJECTED_ALIAS] = "pushNonFastForward",
+
+ [PUSH_NON_FF_CURRENT] = "pushNonFFCurrent",
+ [PUSH_NON_FF_MATCHING] = "pushNonFFMatching",
+ [PUSH_ALREADY_EXISTS] = "pushAlreadyExists",
+ [PUSH_FETCH_FIRST] = "pushFetchFirst",
+ [PUSH_NEEDS_FORCE] = "pushNeedsForce",
+ [PUSH_UNQUALIFIED_REF_NAME] = "pushUnqualifiedRefName",
+ [STATUS_HINTS] = "statusHints",
+ [STATUS_U_OPTION] = "statusUoption",
+ [STATUS_AHEAD_BEHIND_WARNING] = "statusAheadBehindWarning",
+ [COMMIT_BEFORE_MERGE] = "commitBeforeMerge",
+ [RESET_QUIET_WARNING] = "resetQuiet",
+ [RESOLVE_CONFLICT] = "resolveConflict",
+ [SEQUENCER_IN_USE] = "sequencerInUse",
+ [IMPLICIT_IDENTITY] = "implicitIdentity",
+ [DETACHED_HEAD] = "detachedHead",
+ [SET_UPSTREAM_FAILURE] = "setupStreamFailure",
+ [OBJECT_NAME_WARNING] = "objectNameWarning",
+ [AMWORKDIR] = "amWorkDir",
+ [RM_HINTS] = "rmHints",
+ [ADD_EMBEDDED_REPO] = "addEmbeddedRepo",
+ [IGNORED_HOOK] = "ignoredHook",
+ [WAITING_FOR_EDITOR] = "waitingForEditor",
+ [GRAFT_FILE_DEPRECATED] = "graftFileDeprecated",
+ [CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME] = "checkoutAmbiguousRemoteBranchName",
+ [NESTED_TAG] = "nestedTag",
+ [SUBMODULE_ALTERNATE_ERROR_STRATEGY_DIE] = "submoduleAlternateErrorStrategyDie"
+};
+
+static const char turn_off_instructions[] =
+N_("\n"
+ "Disable this message with \"git config %s false\"");
+
+static void vadvise(const char *advice, va_list params,
+ int display_instructions, char *key)
{
struct strbuf buf = STRBUF_INIT;
- va_list params;
const char *cp, *np;
- va_start(params, advice);
strbuf_vaddf(&buf, advice, params);
- va_end(params);
+
+ if(display_instructions)
+ strbuf_addf(&buf, turn_off_instructions, key);
for (cp = buf.buf; *cp; cp = np) {
np = strchrnul(cp, '\n');
@@ -122,6 +159,46 @@ void advise(const char *advice, ...)
strbuf_release(&buf);
}
+static int get_config_value(enum advice_type type)
+{
+ int value = 1;
+ char *key = xstrfmt("%s.%s", "advice", advice_config_keys[type]);
+ git_config_get_bool(key, &value);
+ return value;
+}
+
+int advice_enabled(enum advice_type type)
+{
+ switch(type) {
+ case PUSH_UPDATE_REJECTED:
+ return get_config_value(PUSH_UPDATE_REJECTED) &&
+ get_config_value(PUSH_UPDATE_REJECTED_ALIAS);
+ default:
+ return get_config_value(type);
+ }
+}
+
+void advise(const char *advice, ...)
+{
+ va_list params;
+ va_start(params, advice);
+ vadvise(advice, params, 0, "");
+ va_end(params);
+}
+
+void advise_if_enabled(enum advice_type type, const char *advice, ...)
+{
+ va_list params;
+ char *key = xstrfmt("%s.%s", "advice", advice_config_keys[type]);
+
+ if(!advice_enabled(type))
+ return;
+
+ va_start(params, advice);
+ vadvise(advice, params, 1, key);
+ va_end(params);
+}
+
int git_default_advice_config(const char *var, const char *value)
{
const char *k, *slot_name;
@@ -158,8 +235,8 @@ void list_config_advices(struct string_list *list, const char *prefix)
{
int i;
- for (i = 0; i < ARRAY_SIZE(advice_config); i++)
- list_config_item(list, prefix, advice_config[i].name);
+ for (i = 0; i < ARRAY_SIZE(advice_config_keys); i++)
+ list_config_item(list, prefix, advice_config_keys[i]);
}
int error_resolve_conflict(const char *me)
diff --git a/advice.h b/advice.h
index 0e6e58d..e0741cf 100644
--- a/advice.h
+++ b/advice.h
@@ -29,14 +29,65 @@ extern int advice_ignored_hook;
extern int advice_waiting_for_editor;
extern int advice_graft_file_deprecated;
extern int advice_checkout_ambiguous_remote_branch_name;
-extern int advice_nested_tag;
extern int advice_submodule_alternate_error_strategy_die;
extern int advice_add_ignored_file;
extern int advice_add_empty_pathspec;
+/**
+ To add a new advice, you need to:
+ - Define an advice_type.
+ - Add a new entry to advice_config_keys list.
+ - Add the new config variable to Documentation/config/advice.txt.
+ - Call advise_if_enabled to print your advice.
+ */
+enum advice_type {
+ FETCH_SHOW_FORCED_UPDATES = 0,
+ PUSH_UPDATE_REJECTED = 1,
+ PUSH_UPDATE_REJECTED_ALIAS = 2,
+ PUSH_NON_FF_CURRENT = 3,
+ PUSH_NON_FF_MATCHING = 4,
+ PUSH_ALREADY_EXISTS = 5,
+ PUSH_FETCH_FIRST = 6,
+ PUSH_NEEDS_FORCE = 7,
+ PUSH_UNQUALIFIED_REF_NAME = 8,
+ STATUS_HINTS = 9,
+ STATUS_U_OPTION = 10,
+ STATUS_AHEAD_BEHIND_WARNING = 11,
+ COMMIT_BEFORE_MERGE = 12,
+ RESET_QUIET_WARNING = 13,
+ RESOLVE_CONFLICT = 14,
+ SEQUENCER_IN_USE = 15,
+ IMPLICIT_IDENTITY = 16,
+ DETACHED_HEAD = 17,
+ SET_UPSTREAM_FAILURE = 18,
+ OBJECT_NAME_WARNING = 19,
+ AMWORKDIR = 20,
+ RM_HINTS = 21,
+ ADD_EMBEDDED_REPO = 22,
+ IGNORED_HOOK = 23,
+ WAITING_FOR_EDITOR = 24,
+ GRAFT_FILE_DEPRECATED = 25,
+ CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME = 26,
+ NESTED_TAG = 27,
+ SUBMODULE_ALTERNATE_ERROR_STRATEGY_DIE = 28,
+};
+
+
int git_default_advice_config(const char *var, const char *value);
__attribute__((format (printf, 1, 2)))
void advise(const char *advice, ...);
+
+/**
+ Checks if advice type is enabled (can be printed to the user).
+ Should be called before advise().
+ */
+int advice_enabled(enum advice_type type);
+
+/**
+ Checks the visibility of the advice before printing.
+ */
+void advise_if_enabled(enum advice_type type, const char *advice, ...);
+
int error_resolve_conflict(const char *me);
void NORETURN die_resolve_conflict(const char *me);
void NORETURN die_conclude_merge(void);
diff --git a/builtin/tag.c b/builtin/tag.c
index e0a4c25..247d907 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -231,8 +231,8 @@ static void create_tag(const struct object_id *object, const char *object_ref,
if (type <= OBJ_NONE)
die(_("bad object type."));
- if (type == OBJ_TAG && advice_nested_tag)
- advise(_(message_advice_nested_tag), tag, object_ref);
+ if (type == OBJ_TAG)
+ advise_if_enabled(NESTED_TAG, _(message_advice_nested_tag), tag, object_ref);
strbuf_addf(&header,
"object %s\n"
diff --git a/t/helper/test-advise.c b/t/helper/test-advise.c
new file mode 100644
index 0000000..6d28c9c
--- /dev/null
+++ b/t/helper/test-advise.c
@@ -0,0 +1,16 @@
+#include "test-tool.h"
+#include "cache.h"
+#include "advice.h"
+
+int cmd__advise_if_enabled(int argc, const char **argv)
+{
+ if (!argv[1])
+ die("usage: %s <advice>", argv[0]);
+
+ setup_git_directory();
+
+ //use any advice type for testing
+ advise_if_enabled(NESTED_TAG, argv[1]);
+
+ return 0;
+}
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index c9a232d..31eedcd 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -14,6 +14,7 @@ struct test_cmd {
};
static struct test_cmd cmds[] = {
+ { "advise", cmd__advise_if_enabled },
{ "chmtime", cmd__chmtime },
{ "config", cmd__config },
{ "ctype", cmd__ctype },
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
index c8549fd..4eb5e66 100644
--- a/t/helper/test-tool.h
+++ b/t/helper/test-tool.h
@@ -4,6 +4,7 @@
#define USE_THE_INDEX_COMPATIBILITY_MACROS
#include "git-compat-util.h"
+int cmd__advise_if_enabled(int argc, const char **argv);
int cmd__chmtime(int argc, const char **argv);
int cmd__config(int argc, const char **argv);
int cmd__ctype(int argc, const char **argv);
diff --git a/t/t0018-advice.sh b/t/t0018-advice.sh
new file mode 100755
index 0000000..f4cdb64
--- /dev/null
+++ b/t/t0018-advice.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+test_description='Test advise_if_enabled functionality'
+
+. ./test-lib.sh
+
+cat > expected <<EOF
+hint: This is a piece of advice
+hint: Disable this message with "git config advice.nestedTag false"
+EOF
+test_expect_success 'advise should be printed when config variable is unset' '
+ test-tool advise "This is a piece of advice" 2>actual &&
+ test_i18ncmp expected actual
+'
+
+test_expect_success 'advise should be printed when config variable is set to true' '
+ test_config advice.nestedTag true &&
+ test-tool advise "This is a piece of advice" 2>actual &&
+ test_i18ncmp expected actual
+'
+
+test_expect_success 'advise should not be printed when config variable is set to false' '
+ test_config advice.nestedTag false &&
+ test-tool advise "This is a piece of advice" 2>actual &&
+ test_must_be_empty actual
+'
+
+test_done
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index 6db92bd..74b637d 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -1726,6 +1726,7 @@ test_expect_success 'recursive tagging should give advice' '
hint: already a tag. If you meant to tag the object that it points to, use:
hint: |
hint: git tag -f nested annotated-v4.0^{}
+ hint: Disable this message with "git config advice.nestedTag false"
EOF
git tag -m nested nested annotated-v4.0 2>actual &&
test_i18ncmp expect actual