diff options
author | Patrick Steinhardt <psteinhardt@gitlab.com> | 2022-06-16 14:35:50 +0300 |
---|---|---|
committer | Patrick Steinhardt <psteinhardt@gitlab.com> | 2022-06-23 09:13:31 +0300 |
commit | cb68cc07ab761febe0508aa45a7ec26ca352f20a (patch) | |
tree | 3f24f2187755452a753a1bd65b3de5d5e917c333 | |
parent | 7d2a056ecaebea9403a04abc6482a0a7d8cc277b (diff) |
command: Improve grouping of functions
Reorder the code so that all functions belonging to the `Command` type
are grouped together.
-rw-r--r-- | internal/command/command.go | 277 |
1 files changed, 140 insertions, 137 deletions
diff --git a/internal/command/command.go b/internal/command/command.go index 5602ee24e..024bdd333 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -73,40 +73,50 @@ var ( }, []string{"grpc_service", "grpc_method", "cmd"}, ) -) -// exportedEnvVars contains a list of environment variables -// that are always exported to child processes on spawn -var exportedEnvVars = []string{ - "HOME", - "PATH", - "LD_LIBRARY_PATH", - "TZ", - - // Export git tracing variables for easier debugging - "GIT_TRACE", - "GIT_TRACE_PACK_ACCESS", - "GIT_TRACE_PACKET", - "GIT_TRACE_PERFORMANCE", - "GIT_TRACE_SETUP", - - // GIT_EXEC_PATH tells Git where to find its binaries. This must be exported especially in - // the case where we use bundled Git executables given that we cannot rely on a complete Git - // installation in that case. - "GIT_EXEC_PATH", - - // Git HTTP proxy settings: https://git-scm.com/docs/git-config#git-config-httpproxy - "all_proxy", - "http_proxy", - "HTTP_PROXY", - "https_proxy", - "HTTPS_PROXY", - // libcurl settings: https://curl.haxx.se/libcurl/c/CURLOPT_NOPROXY.html - "no_proxy", - "NO_PROXY", -} + // exportedEnvVars contains a list of environment variables + // that are always exported to child processes on spawn + exportedEnvVars = []string{ + "HOME", + "PATH", + "LD_LIBRARY_PATH", + "TZ", + + // Export git tracing variables for easier debugging + "GIT_TRACE", + "GIT_TRACE_PACK_ACCESS", + "GIT_TRACE_PACKET", + "GIT_TRACE_PERFORMANCE", + "GIT_TRACE_SETUP", + + // GIT_EXEC_PATH tells Git where to find its binaries. This must be exported + // especially in the case where we use bundled Git executables given that we cannot + // rely on a complete Git installation in that case. + "GIT_EXEC_PATH", + + // Git HTTP proxy settings: + // https://git-scm.com/docs/git-config#git-config-httpproxy + "all_proxy", + "http_proxy", + "HTTP_PROXY", + "https_proxy", + "HTTPS_PROXY", + // libcurl settings: https://curl.haxx.se/libcurl/c/CURLOPT_NOPROXY.html + "no_proxy", + "NO_PROXY", + } -var envInjector = tracing.NewEnvInjector() + // envInjector is responsible for injecting environment variables required for tracing into + // the child process. + envInjector = tracing.NewEnvInjector() + + // SetupStdin instructs New() to configure the stdin pipe of the command it is creating. + // This allows you call Write() on the command as if it is an ordinary io.Writer, sending + // data directly to the stdin of the process. + // + // You should not call Read() on this value - it is strictly for configuration! + SetupStdin io.Reader = stdinSentinel{} +) const ( // maxStderrBytes is at most how many bytes will be written to stderr @@ -137,68 +147,6 @@ type Command struct { cgroupPath string } -type stdinSentinel struct{} - -func (stdinSentinel) Read([]byte) (int, error) { - return 0, errors.New("stdin sentinel should not be read from") -} - -// SetupStdin instructs New() to configure the stdin pipe of the command it is -// creating. This allows you call Write() on the command as if it is an ordinary -// io.Writer, sending data directly to the stdin of the process. -// -// You should not call Read() on this value - it is strictly for configuration! -var SetupStdin io.Reader = stdinSentinel{} - -// Read calls Read() on the stdout pipe of the command. -func (c *Command) Read(p []byte) (int, error) { - if c.reader == nil { - panic("command has no reader") - } - - return c.reader.Read(p) -} - -// Write calls Write() on the stdin pipe of the command. -func (c *Command) Write(p []byte) (int, error) { - if c.writer == nil { - panic("command has no writer") - } - - return c.writer.Write(p) -} - -// Wait calls Wait() on the exec.Cmd instance inside the command. This -// blocks until the command has finished and reports the command exit -// status via the error return value. Use ExitStatus to get the integer -// exit status from the error returned by Wait(). -func (c *Command) Wait() error { - c.waitOnce.Do(c.wait) - - return c.waitError -} - -// SetCgroupPath sets the cgroup path for logging -func (c *Command) SetCgroupPath(path string) { - c.cgroupPath = path -} - -// SetMetricsCmd overrides the "cmd" label used in metrics -func (c *Command) SetMetricsCmd(metricsCmd string) { - c.metricsCmd = metricsCmd -} - -// SetMetricsSubCmd sets the "subcmd" label used in metrics -func (c *Command) SetMetricsSubCmd(metricsSubCmd string) { - c.metricsSubCmd = metricsSubCmd -} - -type contextWithoutDonePanic string - -var getSpawnTokenAcquiringSeconds = func(t time.Time) float64 { - return time.Since(t).Seconds() -} - // New creates a Command from an exec.Cmd. On success, the Command // contains a running subprocess. When ctx is canceled the embedded // process will be terminated and reaped automatically. @@ -322,22 +270,47 @@ func New(ctx context.Context, cmd *exec.Cmd, stdin io.Reader, stdout, stderr io. return command, nil } -// AllowedEnvironment filters the given slice of environment variables and -// returns all variables which are allowed per the variables defined above. -// This is useful for constructing a base environment in which a command can be -// run. -func AllowedEnvironment(envs []string) []string { - var filtered []string +// Read calls Read() on the stdout pipe of the command. +func (c *Command) Read(p []byte) (int, error) { + if c.reader == nil { + panic("command has no reader") + } - for _, env := range envs { - for _, exportedEnv := range exportedEnvVars { - if strings.HasPrefix(env, exportedEnv+"=") { - filtered = append(filtered, env) - } - } + return c.reader.Read(p) +} + +// Write calls Write() on the stdin pipe of the command. +func (c *Command) Write(p []byte) (int, error) { + if c.writer == nil { + panic("command has no writer") } - return filtered + return c.writer.Write(p) +} + +// Wait calls Wait() on the exec.Cmd instance inside the command. This +// blocks until the command has finished and reports the command exit +// status via the error return value. Use ExitStatus to get the integer +// exit status from the error returned by Wait(). +func (c *Command) Wait() error { + c.waitOnce.Do(c.wait) + + return c.waitError +} + +// SetCgroupPath sets the cgroup path for logging +func (c *Command) SetCgroupPath(path string) { + c.cgroupPath = path +} + +// SetMetricsCmd overrides the "cmd" label used in metrics +func (c *Command) SetMetricsCmd(metricsCmd string) { + c.metricsCmd = metricsCmd +} + +// SetMetricsSubCmd sets the "subcmd" label used in metrics +func (c *Command) SetMetricsSubCmd(metricsSubCmd string) { + c.metricsSubCmd = metricsSubCmd } // This function should never be called directly, use Wait(). @@ -368,21 +341,6 @@ func (c *Command) wait() { commandcounter.Decrement() } -// ExitStatus will return the exit-code from an error returned by Wait(). -func ExitStatus(err error) (int, bool) { - exitError, ok := err.(*exec.ExitError) - if !ok { - return 0, false - } - - waitStatus, ok := exitError.Sys().(syscall.WaitStatus) - if !ok { - return 0, false - } - - return waitStatus.ExitStatus(), true -} - func (c *Command) logProcessComplete() { exitCode := 0 if c.waitError != nil { @@ -480,6 +438,66 @@ func (c *Command) logProcessComplete() { c.span.Finish() } +// Args is an accessor for the command arguments +func (c *Command) Args() []string { + return c.cmd.Args +} + +// Env is an accessor for the environment variables +func (c *Command) Env() []string { + return c.cmd.Env +} + +// Pid is an accessor for the pid +func (c *Command) Pid() int { + return c.cmd.Process.Pid +} + +type contextWithoutDonePanic string + +var getSpawnTokenAcquiringSeconds = func(t time.Time) float64 { + return time.Since(t).Seconds() +} + +type stdinSentinel struct{} + +func (stdinSentinel) Read([]byte) (int, error) { + return 0, errors.New("stdin sentinel should not be read from") +} + +// AllowedEnvironment filters the given slice of environment variables and +// returns all variables which are allowed per the variables defined above. +// This is useful for constructing a base environment in which a command can be +// run. +func AllowedEnvironment(envs []string) []string { + var filtered []string + + for _, env := range envs { + for _, exportedEnv := range exportedEnvVars { + if strings.HasPrefix(env, exportedEnv+"=") { + filtered = append(filtered, env) + } + } + } + + return filtered +} + +// ExitStatus will return the exit-code from an error returned by Wait(). +func ExitStatus(err error) (int, bool) { + exitError, ok := err.(*exec.ExitError) + if !ok { + return 0, false + } + + waitStatus, ok := exitError.Sys().(syscall.WaitStatus) + if !ok { + return 0, false + } + + return waitStatus.ExitStatus(), true +} + func methodFromContext(ctx context.Context) (service string, method string) { tags := grpcmwtags.Extract(ctx) ctxValue := tags.Values()["grpc.request.fullMethod"] @@ -514,18 +532,3 @@ func checkNullArgv(cmd *exec.Cmd) error { return nil } - -// Args is an accessor for the command arguments -func (c *Command) Args() []string { - return c.cmd.Args -} - -// Env is an accessor for the environment variables -func (c *Command) Env() []string { - return c.cmd.Env -} - -// Pid is an accessor for the pid -func (c *Command) Pid() int { - return c.cmd.Process.Pid -} |