mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-01 10:59:45 +00:00
243 lines
6.7 KiB
C
243 lines
6.7 KiB
C
/*
|
|
* Copyright (C) the libgit2 contributors. All rights reserved.
|
|
*
|
|
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
|
* a Linking Exception. For full terms see the included COPYING file.
|
|
*/
|
|
|
|
#include <git2.h>
|
|
|
|
#include "common.h"
|
|
#include "cmd.h"
|
|
|
|
#define COMMAND_NAME "config"
|
|
|
|
typedef enum {
|
|
ACTION_NONE = 0,
|
|
ACTION_GET,
|
|
ACTION_ADD,
|
|
ACTION_REPLACE_ALL,
|
|
ACTION_LIST
|
|
} action_t;
|
|
|
|
static action_t action = ACTION_NONE;
|
|
static int show_origin;
|
|
static int show_scope;
|
|
static int show_help;
|
|
static int null_separator;
|
|
static int config_level;
|
|
static char *config_filename;
|
|
static char *name, *value, *value_pattern;
|
|
|
|
static const cli_opt_spec opts[] = {
|
|
CLI_COMMON_OPT, \
|
|
|
|
{ CLI_OPT_TYPE_SWITCH, "null", 'z', &null_separator, 1,
|
|
0, NULL, "use NUL as a separator" },
|
|
|
|
{ CLI_OPT_TYPE_SWITCH, "system", 0, &config_level, GIT_CONFIG_LEVEL_SYSTEM,
|
|
0, NULL, "read/write to system configuration" },
|
|
{ CLI_OPT_TYPE_SWITCH, "global", 0, &config_level, GIT_CONFIG_LEVEL_GLOBAL,
|
|
CLI_OPT_USAGE_CHOICE, NULL, "read/write to global configuration" },
|
|
{ CLI_OPT_TYPE_SWITCH, "local", 0, &config_level, GIT_CONFIG_LEVEL_LOCAL,
|
|
CLI_OPT_USAGE_CHOICE, NULL, "read/write to local configuration" },
|
|
{ CLI_OPT_TYPE_VALUE, "file", 0, &config_filename, 0,
|
|
CLI_OPT_USAGE_CHOICE, "filename", "read/write to specified configuration file" },
|
|
|
|
{ CLI_OPT_TYPE_SWITCH, "get", 0, &action, ACTION_GET,
|
|
CLI_OPT_USAGE_REQUIRED, NULL, "get a configuration value" },
|
|
{ CLI_OPT_TYPE_SWITCH, "add", 0, &action, ACTION_ADD,
|
|
CLI_OPT_USAGE_CHOICE, NULL, "add a configuration value" },
|
|
{ CLI_OPT_TYPE_SWITCH, "replace-all", 0, &action, ACTION_REPLACE_ALL,
|
|
CLI_OPT_USAGE_CHOICE, NULL, "add a configuration value, replacing any old values" },
|
|
{ CLI_OPT_TYPE_SWITCH, "list", 'l', &action, ACTION_LIST,
|
|
CLI_OPT_USAGE_CHOICE | CLI_OPT_USAGE_SHOW_LONG,
|
|
NULL, "list all configuration entries" },
|
|
{ CLI_OPT_TYPE_SWITCH, "show-origin", 0, &show_origin, 1,
|
|
0, NULL, "show origin of configuration" },
|
|
{ CLI_OPT_TYPE_SWITCH, "show-scope", 0, &show_scope, 1,
|
|
0, NULL, "show scope of configuration" },
|
|
{ CLI_OPT_TYPE_ARG, "name", 0, &name, 0,
|
|
0, "name", "name of configuration entry" },
|
|
{ CLI_OPT_TYPE_ARG, "value", 0, &value, 0,
|
|
0, "value", "value of configuration entry" },
|
|
{ CLI_OPT_TYPE_ARG, "regexp", 0, &value_pattern, 0,
|
|
0, "regexp", "regular expression of values to replace" },
|
|
{ 0 },
|
|
};
|
|
|
|
static void print_help(void)
|
|
{
|
|
cli_opt_usage_fprint(stdout, PROGRAM_NAME, COMMAND_NAME, opts);
|
|
printf("\n");
|
|
|
|
printf("Query and set configuration options.\n");
|
|
printf("\n");
|
|
|
|
printf("Options:\n");
|
|
|
|
cli_opt_help_fprint(stdout, opts);
|
|
}
|
|
|
|
static int get_config(git_config *config)
|
|
{
|
|
git_buf value = GIT_BUF_INIT;
|
|
char sep = null_separator ? '\0' : '\n';
|
|
int error;
|
|
|
|
error = git_config_get_string_buf(&value, config, name);
|
|
|
|
if (error && error != GIT_ENOTFOUND)
|
|
return cli_error_git();
|
|
|
|
else if (error == GIT_ENOTFOUND)
|
|
return 1;
|
|
|
|
printf("%s%c", value.ptr, sep);
|
|
return 0;
|
|
}
|
|
|
|
static int add_config(git_config *config)
|
|
{
|
|
if (git_config_set_multivar(config, name, "$^", value) < 0)
|
|
return cli_error_git();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int replace_all_config(git_config *config)
|
|
{
|
|
if (git_config_set_multivar(config, name, value_pattern ? value_pattern : ".*", value) < 0)
|
|
return cli_error_git();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const char *level_name(git_config_level_t level)
|
|
{
|
|
switch (level) {
|
|
case GIT_CONFIG_LEVEL_PROGRAMDATA:
|
|
return "programdata";
|
|
case GIT_CONFIG_LEVEL_SYSTEM:
|
|
return "system";
|
|
case GIT_CONFIG_LEVEL_XDG:
|
|
return "global";
|
|
case GIT_CONFIG_LEVEL_GLOBAL:
|
|
return "global";
|
|
case GIT_CONFIG_LEVEL_LOCAL:
|
|
return "local";
|
|
case GIT_CONFIG_LEVEL_APP:
|
|
return "command";
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
static int list_config(git_config *config)
|
|
{
|
|
git_config_iterator *iterator;
|
|
git_config_entry *entry;
|
|
char data_separator = null_separator ? '\0' : '\t';
|
|
char kv_separator = null_separator ? '\n' : '=';
|
|
char entry_separator = null_separator ? '\0' : '\n';
|
|
int error;
|
|
|
|
if (git_config_iterator_new(&iterator, config) < 0)
|
|
return cli_error_git();
|
|
|
|
while ((error = git_config_next(&entry, iterator)) == 0) {
|
|
if (show_scope)
|
|
printf("%s%c",
|
|
level_name(entry->level),
|
|
data_separator);
|
|
|
|
if (show_origin)
|
|
printf("%s%s%s%c",
|
|
entry->backend_type ? entry->backend_type : "",
|
|
entry->backend_type && entry->origin_path ? ":" : "",
|
|
entry->origin_path ? entry->origin_path : "",
|
|
data_separator);
|
|
|
|
printf("%s%c%s%c", entry->name, kv_separator, entry->value,
|
|
entry_separator);
|
|
}
|
|
|
|
if (error != GIT_ITEROVER)
|
|
return cli_error_git();
|
|
|
|
git_config_iterator_free(iterator);
|
|
return 0;
|
|
}
|
|
|
|
int cmd_config(int argc, char **argv)
|
|
{
|
|
git_repository *repo = NULL;
|
|
git_config *config = NULL;
|
|
cli_repository_open_options open_opts = { argv + 1, argc - 1};
|
|
cli_opt invalid_opt;
|
|
int ret = 0;
|
|
|
|
if (cli_opt_parse(&invalid_opt, opts, argv + 1, argc - 1, CLI_OPT_PARSE_GNU))
|
|
return cli_opt_usage_error(COMMAND_NAME, opts, &invalid_opt);
|
|
|
|
if (show_help) {
|
|
print_help();
|
|
return 0;
|
|
}
|
|
|
|
if (config_filename) {
|
|
if (git_config_new(&config) < 0 ||
|
|
git_config_add_file_ondisk(config, config_filename,
|
|
GIT_CONFIG_LEVEL_APP, NULL, 0) < 0) {
|
|
ret = cli_error_git();
|
|
goto done;
|
|
}
|
|
} else {
|
|
if (cli_repository_open(&repo, &open_opts) < 0 ||
|
|
git_repository_config(&config, repo) < 0) {
|
|
ret = cli_error_git();
|
|
goto done;
|
|
}
|
|
|
|
if (config_level &&
|
|
git_config_open_level(&config, config, config_level) < 0) {
|
|
ret = cli_error_git();
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
switch (action) {
|
|
case ACTION_ADD:
|
|
if (!name || !value || value_pattern)
|
|
ret = cli_error_usage("%s --add requires two arguments", COMMAND_NAME);
|
|
else
|
|
ret = add_config(config);
|
|
break;
|
|
case ACTION_REPLACE_ALL:
|
|
if (!name || !value)
|
|
ret = cli_error_usage("%s --replace-all requires two or three arguments", COMMAND_NAME);
|
|
else
|
|
ret = replace_all_config(config);
|
|
break;
|
|
case ACTION_GET:
|
|
if (!name)
|
|
ret = cli_error_usage("%s --get requires an argument", COMMAND_NAME);
|
|
else
|
|
ret = get_config(config);
|
|
break;
|
|
case ACTION_LIST:
|
|
if (name)
|
|
ret = cli_error_usage("%s --list does not take an argument", COMMAND_NAME);
|
|
else
|
|
ret = list_config(config);
|
|
break;
|
|
default:
|
|
ret = cli_error_usage("unknown action");
|
|
}
|
|
|
|
done:
|
|
git_config_free(config);
|
|
git_repository_free(repo);
|
|
return ret;
|
|
}
|