Merge branch 'hw/advise-ng'

Revamping of the advise API to allow more systematic enumeration of
advice knobs in the future.

* hw/advise-ng:
  tag: use new advice API to check visibility
  advice: revamp advise API
  advice: change "setupStreamFailure" to "setUpstreamFailure"
  advice: extract vadvise() from advise()
This commit is contained in:
Junio C Hamano 2020-03-25 13:57:41 -07:00
commit c4a09cc9cc
9 changed files with 200 additions and 12 deletions

View File

@ -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

View File

@ -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;
@ -82,7 +81,7 @@ static struct {
{ "sequencerInUse", &advice_sequencer_in_use },
{ "implicitIdentity", &advice_implicit_identity },
{ "detachedHead", &advice_detached_head },
{ "setupStreamFailure", &advice_set_upstream_failure },
{ "setUpstreamFailure", &advice_set_upstream_failure },
{ "objectNameWarning", &advice_object_name_warning },
{ "amWorkDir", &advice_amworkdir },
{ "rmHints", &advice_rm_hints },
@ -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,58 @@ static struct {
{ "pushNonFastForward", &advice_push_update_rejected }
};
void advise(const char *advice, ...)
static struct {
const char *key;
int enabled;
} advice_setting[] = {
[ADVICE_ADD_EMBEDDED_REPO] = { "addEmbeddedRepo", 1 },
[ADVICE_AM_WORK_DIR] = { "amWorkDir", 1 },
[ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME] = { "checkoutAmbiguousRemoteBranchName", 1 },
[ADVICE_COMMIT_BEFORE_MERGE] = { "commitBeforeMerge", 1 },
[ADVICE_DETACHED_HEAD] = { "detachedHead", 1 },
[ADVICE_FETCH_SHOW_FORCED_UPDATES] = { "fetchShowForcedUpdates", 1 },
[ADVICE_GRAFT_FILE_DEPRECATED] = { "graftFileDeprecated", 1 },
[ADVICE_IGNORED_HOOK] = { "ignoredHook", 1 },
[ADVICE_IMPLICIT_IDENTITY] = { "implicitIdentity", 1 },
[ADVICE_NESTED_TAG] = { "nestedTag", 1 },
[ADVICE_OBJECT_NAME_WARNING] = { "objectNameWarning", 1 },
[ADVICE_PUSH_ALREADY_EXISTS] = { "pushAlreadyExists", 1 },
[ADVICE_PUSH_FETCH_FIRST] = { "pushFetchFirst", 1 },
[ADVICE_PUSH_NEEDS_FORCE] = { "pushNeedsForce", 1 },
/* make this an alias for backward compatibility */
[ADVICE_PUSH_UPDATE_REJECTED_ALIAS] = { "pushNonFastForward", 1 },
[ADVICE_PUSH_NON_FF_CURRENT] = { "pushNonFFCurrent", 1 },
[ADVICE_PUSH_NON_FF_MATCHING] = { "pushNonFFMatching", 1 },
[ADVICE_PUSH_UNQUALIFIED_REF_NAME] = { "pushUnqualifiedRefName", 1 },
[ADVICE_PUSH_UPDATE_REJECTED] = { "pushUpdateRejected", 1 },
[ADVICE_RESET_QUIET_WARNING] = { "resetQuiet", 1 },
[ADVICE_RESOLVE_CONFLICT] = { "resolveConflict", 1 },
[ADVICE_RM_HINTS] = { "rmHints", 1 },
[ADVICE_SEQUENCER_IN_USE] = { "sequencerInUse", 1 },
[ADVICE_SET_UPSTREAM_FAILURE] = { "setUpstreamFailure", 1 },
[ADVICE_STATUS_AHEAD_BEHIND_WARNING] = { "statusAheadBehindWarning", 1 },
[ADVICE_STATUS_HINTS] = { "statusHints", 1 },
[ADVICE_STATUS_U_OPTION] = { "statusUoption", 1 },
[ADVICE_SUBMODULE_ALTERNATE_ERROR_STRATEGY_DIE] = { "submoduleAlternateErrorStrategyDie", 1 },
[ADVICE_WAITING_FOR_EDITOR] = { "waitingForEditor", 1 },
};
static const char turn_off_instructions[] =
N_("\n"
"Disable this message with \"git config advice.%s false\"");
static void vadvise(const char *advice, int display_instructions,
const char *key, va_list params)
{
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 +163,37 @@ void advise(const char *advice, ...)
strbuf_release(&buf);
}
void advise(const char *advice, ...)
{
va_list params;
va_start(params, advice);
vadvise(advice, 0, "", params);
va_end(params);
}
int advice_enabled(enum advice_type type)
{
switch(type) {
case ADVICE_PUSH_UPDATE_REJECTED:
return advice_setting[ADVICE_PUSH_UPDATE_REJECTED].enabled &&
advice_setting[ADVICE_PUSH_UPDATE_REJECTED_ALIAS].enabled;
default:
return advice_setting[type].enabled;
}
}
void advise_if_enabled(enum advice_type type, const char *advice, ...)
{
va_list params;
if (!advice_enabled(type))
return;
va_start(params, advice);
vadvise(advice, 1, advice_setting[type].key, params);
va_end(params);
}
int git_default_advice_config(const char *var, const char *value)
{
const char *k, *slot_name;
@ -148,6 +220,13 @@ int git_default_advice_config(const char *var, const char *value)
if (strcasecmp(k, advice_config[i].name))
continue;
*advice_config[i].preference = git_config_bool(var, value);
break;
}
for (i = 0; i < ARRAY_SIZE(advice_setting); i++) {
if (strcasecmp(k, advice_setting[i].key))
continue;
advice_setting[i].enabled = git_config_bool(var, value);
return 0;
}
@ -158,8 +237,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_setting); i++)
list_config_item(list, prefix, advice_setting[i].key);
}
int error_resolve_conflict(const char *me)

View File

@ -29,14 +29,64 @@ 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 a new advice_type.
* Add a new entry to advice_setting array.
* Add the new config variable to Documentation/config/advice.txt.
* Call advise_if_enabled to print your advice.
*/
enum advice_type {
ADVICE_ADD_EMBEDDED_REPO,
ADVICE_AM_WORK_DIR,
ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME,
ADVICE_COMMIT_BEFORE_MERGE,
ADVICE_DETACHED_HEAD,
ADVICE_FETCH_SHOW_FORCED_UPDATES,
ADVICE_GRAFT_FILE_DEPRECATED,
ADVICE_IGNORED_HOOK,
ADVICE_IMPLICIT_IDENTITY,
ADVICE_NESTED_TAG,
ADVICE_OBJECT_NAME_WARNING,
ADVICE_PUSH_ALREADY_EXISTS,
ADVICE_PUSH_FETCH_FIRST,
ADVICE_PUSH_NEEDS_FORCE,
ADVICE_PUSH_NON_FF_CURRENT,
ADVICE_PUSH_NON_FF_MATCHING,
ADVICE_PUSH_UNQUALIFIED_REF_NAME,
ADVICE_PUSH_UPDATE_REJECTED_ALIAS,
ADVICE_PUSH_UPDATE_REJECTED,
ADVICE_RESET_QUIET_WARNING,
ADVICE_RESOLVE_CONFLICT,
ADVICE_RM_HINTS,
ADVICE_SEQUENCER_IN_USE,
ADVICE_SET_UPSTREAM_FAILURE,
ADVICE_STATUS_AHEAD_BEHIND_WARNING,
ADVICE_STATUS_HINTS,
ADVICE_STATUS_U_OPTION,
ADVICE_SUBMODULE_ALTERNATE_ERROR_STRATEGY_DIE,
ADVICE_WAITING_FOR_EDITOR,
};
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);

View File

@ -231,8 +231,9 @@ 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(ADVICE_NESTED_TAG, _(message_advice_nested_tag),
tag, object_ref);
strbuf_addf(&header,
"object %s\n"

22
t/helper/test-advise.c Normal file
View File

@ -0,0 +1,22 @@
#include "test-tool.h"
#include "cache.h"
#include "advice.h"
#include "config.h"
int cmd__advise_if_enabled(int argc, const char **argv)
{
if (!argv[1])
die("usage: %s <advice>", argv[0]);
setup_git_directory();
git_config(git_default_config, NULL);
/*
* Any advice type can be used for testing, but NESTED_TAG was
* selected here and in t0018 where this command is being
* executed.
*/
advise_if_enabled(ADVICE_NESTED_TAG, argv[1]);
return 0;
}

View File

@ -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 },

View File

@ -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);

32
t/t0018-advice.sh Executable file
View File

@ -0,0 +1,32 @@
#!/bin/sh
test_description='Test advise_if_enabled functionality'
. ./test-lib.sh
test_expect_success 'advice should be printed when config variable is unset' '
cat >expect <<-\EOF &&
hint: This is a piece of advice
hint: Disable this message with "git config advice.nestedTag false"
EOF
test-tool advise "This is a piece of advice" 2>actual &&
test_i18ncmp expect actual
'
test_expect_success 'advice should be printed when config variable is set to true' '
cat >expect <<-\EOF &&
hint: This is a piece of advice
hint: Disable this message with "git config advice.nestedTag false"
EOF
test_config advice.nestedTag true &&
test-tool advise "This is a piece of advice" 2>actual &&
test_i18ncmp expect actual
'
test_expect_success 'advice 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

View File

@ -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