diff --git a/builtin/config.c b/builtin/config.c index de41ba50e9ca03d5348e407eaba44c2a93447938..5677c942b6936f3332b1b4ed12541f45c4228dfb 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -360,6 +360,9 @@ static int get_colorbool(int print) static void check_write(void) { + if (given_config_source.use_stdin) + die("writing to stdin is not supported"); + if (given_config_source.blob) die("writing config blobs is not supported"); } @@ -472,6 +475,12 @@ int cmd_config(int argc, const char **argv, const char *prefix) usage_with_options(builtin_config_usage, builtin_config_options); } + if (given_config_source.file && + !strcmp(given_config_source.file, "-")) { + given_config_source.file = NULL; + given_config_source.use_stdin = 1; + } + if (use_global_config) { char *user_config = NULL; char *xdg_config = NULL; @@ -558,6 +567,8 @@ int cmd_config(int argc, const char **argv, const char *prefix) check_argc(argc, 0, 0); if (!given_config_source.file && nongit) die("not in a git directory"); + if (given_config_source.use_stdin) + die("editing stdin is not supported"); if (given_config_source.blob) die("editing blobs is not supported"); git_config(git_default_config, NULL); diff --git a/cache.h b/cache.h index 9d94bd69f7db9dde851683e610a0ffe5da775646..4db19b537059fc23fde3b698b00c3e609c4e116a 100644 --- a/cache.h +++ b/cache.h @@ -1147,6 +1147,7 @@ extern int update_server_info(int); #define CONFIG_GENERIC_ERROR 7 struct git_config_source { + unsigned int use_stdin:1; const char *file; const char *blob; }; diff --git a/config.c b/config.c index a21b0ddadecc3d288ea50339e9b39765a1227aec..7b1febdf4af090a5a6c0620398266a5fcfdb7498 100644 --- a/config.c +++ b/config.c @@ -1031,24 +1031,35 @@ static int do_config_from(struct config_source *top, config_fn_t fn, void *data) return ret; } -int git_config_from_file(config_fn_t fn, const char *filename, void *data) +static int do_config_from_file(config_fn_t fn, + const char *name, const char *path, FILE *f, void *data) { - int ret; - FILE *f = fopen(filename, "r"); + struct config_source top; - ret = -1; - if (f) { - struct config_source top; + top.u.file = f; + top.name = name; + top.path = path; + top.die_on_error = 1; + top.do_fgetc = config_file_fgetc; + top.do_ungetc = config_file_ungetc; + top.do_ftell = config_file_ftell; - top.u.file = f; - top.name = top.path = filename; - top.die_on_error = 1; - top.do_fgetc = config_file_fgetc; - top.do_ungetc = config_file_ungetc; - top.do_ftell = config_file_ftell; + return do_config_from(&top, fn, data); +} - ret = do_config_from(&top, fn, data); +static int git_config_from_stdin(config_fn_t fn, void *data) +{ + return do_config_from_file(fn, "", NULL, stdin, data); +} + +int git_config_from_file(config_fn_t fn, const char *filename, void *data) +{ + int ret = -1; + FILE *f; + f = fopen(filename, "r"); + if (f) { + ret = do_config_from_file(fn, filename, filename, f, data); fclose(f); } return ret; @@ -1190,7 +1201,9 @@ int git_config_with_options(config_fn_t fn, void *data, * If we have a specific filename, use it. Otherwise, follow the * regular lookup sequence. */ - if (config_source && config_source->file) + if (config_source && config_source->use_stdin) + return git_config_from_stdin(fn, data); + else if (config_source && config_source->file) return git_config_from_file(fn, config_source->file, data); else if (config_source && config_source->blob) return git_config_from_blob_ref(fn, config_source->blob, data); diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 967359344dab8118dfd55816ef08f4809a9f33ad..c9c426c273e556302338f7a30fc46de64b856eb2 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -475,15 +475,28 @@ ein.bahn=strasse EOF test_expect_success 'alternative GIT_CONFIG' ' - GIT_CONFIG=other-config git config -l >output && + GIT_CONFIG=other-config git config --list >output && test_cmp expect output ' test_expect_success 'alternative GIT_CONFIG (--file)' ' - git config --file other-config -l > output && + git config --file other-config --list >output && test_cmp expect output ' +test_expect_success 'alternative GIT_CONFIG (--file=-)' ' + git config --file - --list output && + test_cmp expect output +' + +test_expect_success 'setting a value in stdin is an error' ' + test_must_fail git config --file - some.value foo +' + +test_expect_success 'editing stdin is an error' ' + test_must_fail git config --file - --edit +' + test_expect_success 'refer config from subdirectory' ' mkdir x && ( diff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh index 6edd38b39a0b758b8007c1d58b858c9e3b533928..9ba2ba11c3cac88154dbb2d522b43adf98a8dee7 100755 --- a/t/t1305-config-include.sh +++ b/t/t1305-config-include.sh @@ -113,7 +113,7 @@ test_expect_success 'missing include files are ignored' ' test_expect_success 'absolute includes from command line work' ' echo "[test]one = 1" >one && echo 1 >expect && - git -c include.path="$PWD/one" config test.one >actual && + git -c include.path="$(pwd)/one" config test.one >actual && test_cmp expect actual ' @@ -138,6 +138,20 @@ test_expect_success 'relative includes from blobs fail' ' test_must_fail git config --blob=$blob test.one ' +test_expect_success 'absolute includes from stdin work' ' + echo "[test]one = 1" >one && + echo 1 >expect && + echo "[include]path=\"$(pwd)/one\"" | + git config --file - test.one >actual && + test_cmp expect actual +' + +test_expect_success 'relative includes from stdin line fail' ' + echo "[test]one = 1" >one && + echo "[include]path=one" | + test_must_fail git config --file - test.one +' + test_expect_success 'include cycles are detected' ' cat >.gitconfig <<-\EOF && [test]value = gitconfig