diff --git a/Dockerfile.in b/Dockerfile.in index 0384235b8..ada3640d6 100644 --- a/Dockerfile.in +++ b/Dockerfile.in @@ -103,7 +103,6 @@ RUN rm -rf \ /usr/lib/git-core/git-http-push \ /usr/lib/git-core/git-imap-send \ /usr/lib/git-core/git-instaweb \ - /usr/lib/git-core/git-sh-i18n--envsubst \ /usr/lib/git-core/scalar \ /usr/lib/openssh/ssh-keysign \ /usr/lib/openssh/ssh-pkcs11-helper \ diff --git a/README.md b/README.md index 5244314f7..99c04acfe 100644 --- a/README.md +++ b/README.md @@ -312,7 +312,28 @@ OPTIONS --git-config , $GITSYNC_GIT_CONFIG Additional git config options in a comma-separated 'key:val' format. The parsed keys and values are passed to 'git config' and - must be valid syntax for that command. + must be valid syntax for that command. This is similar to + --git-config-add, but uses a single comma-separated string. + + Both keys and values can be either quoted or unquoted strings. + Within quoted keys and all values (quoted or not), the following + escape sequences are supported: + '\n' => [newline] + '\t' => [tab] + '\"' => '"' + '\,' => ',' + '\\' => '\' + To include a colon within a key (e.g. a URL) the key must be + quoted. Within unquoted values commas must be escaped. Within + quoted values commas may be escaped, but are not required to be. + Any other escape sequence is an error. + + --git-config-add + Add one git config option. The parsed key and value are passed to + 'git config' and must be valid syntax for that command. This flag + can be specified more than once. This is similar to --git-config, + but allows multiple discrete uses of the flag instead of a single + comma-separated string. Both keys and values can be either quoted or unquoted strings. Within quoted keys and all values (quoted or not), the following diff --git a/main.go b/main.go index eb96be093..405144dff 100644 --- a/main.go +++ b/main.go @@ -41,6 +41,7 @@ import ( "syscall" "time" + "github.com/go-logr/logr/funcr" "github.com/golang-jwt/jwt/v4" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -313,9 +314,12 @@ func main() { flGitCmd := pflag.String("git", envString("git", "GITSYNC_GIT", "GIT_SYNC_GIT"), "the git command to run (subject to PATH search, mostly for testing)") - flGitConfig := pflag.String("git-config", + flGitConfigString := pflag.String("git-config", envString("", "GITSYNC_GIT_CONFIG", "GIT_SYNC_GIT_CONFIG"), "additional git config options in 'section.var1:val1,\"section.sub.var2\":\"val2\"' format") + flGitConfigList := pflag.StringArray("git-config-add", // Array vs. Slice to avoid CSV parsing + nil, + "add one additional git config option in 'section.var1:val1' format; can be repeated") flGitGC := pflag.String("git-gc", envString("always", "GITSYNC_GIT_GC", "GIT_SYNC_GIT_GC"), "git garbage collection behavior: one of 'auto', 'always', 'aggressive', or 'off'") @@ -810,13 +814,42 @@ func main() { } // This needs to be after all other git-related config flags. - if *flGitConfig != "" { - if err := git.SetupExtraGitConfigs(ctx, *flGitConfig); err != nil { - log.Error(err, "can't set additional git configs", "configs", *flGitConfig) + if *flGitConfigString != "" { + if err := git.SetupExtraGitConfigs(ctx, *flGitConfigString, "--git-config"); err != nil { + log.Error(err, "can't set additional git configs", "configs", *flGitConfigString) + os.Exit(1) + } + } + if len(*flGitConfigList) > 0 { + str := strings.Join(*flGitConfigList, ",") + if err := git.SetupExtraGitConfigs(ctx, str, "--git-config-add"); err != nil { + log.Error(err, "can't set additional git configs", "configs", str) os.Exit(1) } } + // Log configs for debug. The -z means to produce a list of NUL-delimted KV + // pairs, where the first newline is the key/value separator and any + // additional newlines are part of the value. + if stdout, stderr, err := cmdRunner.Run(ctx, "", nil, *flGitCmd, "config", "list", "-z"); err != nil { + log.Error(err, "can't list git config") + os.Exit(1) + } else if stderr != "" { + log.V(0).Info("unexpected stderr reading git config", "stdout", stdout, "stderr", stderr) + os.Exit(1) + } else { + cfgs := strings.Split(stdout, string(rune(0))) + kvs := funcr.PseudoStruct{} // like a map but ordered + for _, cfg := range cfgs { + if cfg == "" { + continue + } + parts := strings.SplitN(cfg, "\n", 2) // any additional newlines are part of the value + kvs = append(kvs, parts[0], parts[1]) + } + log.V(0).Info("git config", "configs", kvs) + } + // The scope of the initialization context ends here, so we call cancel to release resources associated with it. cancel() @@ -2259,10 +2292,6 @@ func (git *repoSync) SetupDefaultGitConfigs(ctx context.Context) error { // Never prompt for a password. key: "core.askPass", val: "true", - }, { - // Mark repos as safe (avoid a "dubious ownership" error). - key: "safe.directory", - val: "*", }} for _, kv := range configs { @@ -2275,10 +2304,10 @@ func (git *repoSync) SetupDefaultGitConfigs(ctx context.Context) error { // SetupExtraGitConfigs configures the global git environment with user-provided // override settings. -func (git *repoSync) SetupExtraGitConfigs(ctx context.Context, configsFlag string) error { +func (git *repoSync) SetupExtraGitConfigs(ctx context.Context, configsFlag string, flagName string) error { configs, err := parseGitConfigs(configsFlag) if err != nil { - return fmt.Errorf("can't parse --git-config flag: %w", err) + return fmt.Errorf("can't parse %s flag: %w", flagName, err) } git.log.V(1).Info("setting additional git configs", "configs", configs) for _, kv := range configs { @@ -2631,7 +2660,28 @@ OPTIONS --git-config , $GITSYNC_GIT_CONFIG Additional git config options in a comma-separated 'key:val' format. The parsed keys and values are passed to 'git config' and - must be valid syntax for that command. + must be valid syntax for that command. This is similar to + --git-config-add, but uses a single comma-separated string. + + Both keys and values can be either quoted or unquoted strings. + Within quoted keys and all values (quoted or not), the following + escape sequences are supported: + '\n' => [newline] + '\t' => [tab] + '\"' => '"' + '\,' => ',' + '\\' => '\' + To include a colon within a key (e.g. a URL) the key must be + quoted. Within unquoted values commas must be escaped. Within + quoted values commas may be escaped, but are not required to be. + Any other escape sequence is an error. + + --git-config-add + Add one git config option. The parsed key and value are passed to + 'git config' and must be valid syntax for that command. This flag + can be specified more than once. This is similar to --git-config, + but allows multiple discrete uses of the flag instead of a single + comma-separated string. Both keys and values can be either quoted or unquoted strings. Within quoted keys and all values (quoted or not), the following diff --git a/test_e2e.sh b/test_e2e.sh index 70ffde3a0..ed467a08a 100755 --- a/test_e2e.sh +++ b/test_e2e.sh @@ -368,7 +368,8 @@ function GIT_SYNC() { --add-user \ --group-write \ --touch-file="$INTERLOCK" \ - --git-config='protocol.file.allow:always' \ + --git-config-add='protocol.file.allow:always' \ + --git-config-add='safe.directory:*' \ --http-bind=":$HTTP_PORT" \ --http-metrics \ --http-pprof \ @@ -3573,7 +3574,10 @@ function e2e::additional_git_configs() { --repo="file://$REPO" \ --root="$ROOT" \ --link="link" \ - --git-config='http.postBuffer:10485760,sect.k1:"a val",sect.k2:another val' + --git-config='http.postBuffer:10485760,sect.k1:"a val",sect.k2:another val' \ + --git-config-add='sect.k3:a val' \ + --git-config-add='sect.k4:"a val with quotes"' \ + --git-config-add='"sect.k5":"quoted_all"' assert_link_exists "$ROOT/link" assert_file_exists "$ROOT/link/file" assert_file_eq "$ROOT/link/file" "${FUNCNAME[0]}"