type Shell … type shellShared … // NewShell returns a new Shell. // // Shell will internally serialize calls to the print function. // If print is nil, it defaults to printing to stderr. func NewShell(workDir string, print func(a ...any) (int, error)) *Shell { … } // Print emits a to this Shell's output stream, formatting it like fmt.Print. // It is safe to call concurrently. func (sh *Shell) Print(a ...any) { … } func (sh *Shell) printLocked(a ...any) { … } // WithAction returns a Shell identical to sh, but bound to Action a. func (sh *Shell) WithAction(a *Action) *Shell { … } // Shell returns a shell for running commands on behalf of Action a. func (b *Builder) Shell(a *Action) *Shell { … } // BackgroundShell returns a Builder-wide Shell that's not bound to any Action. // Try not to use this unless there's really no sensible Action available. func (b *Builder) BackgroundShell() *Shell { … } // moveOrCopyFile is like 'mv src dst' or 'cp src dst'. func (sh *Shell) moveOrCopyFile(dst, src string, perm fs.FileMode, force bool) error { … } // copyFile is like 'cp src dst'. func (sh *Shell) CopyFile(dst, src string, perm fs.FileMode, force bool) error { … } // mayberemovefile removes a file only if it is a regular file // When running as a user with sufficient privileges, we may delete // even device files, for example, which is not intended. func mayberemovefile(s string) { … } // writeFile writes the text to file. func (sh *Shell) writeFile(file string, text []byte) error { … } // Mkdir makes the named directory. func (sh *Shell) Mkdir(dir string) error { … } // RemoveAll is like 'rm -rf'. It attempts to remove all paths even if there's // an error, and returns the first error. func (sh *Shell) RemoveAll(paths ...string) error { … } // Symlink creates a symlink newname -> oldname. func (sh *Shell) Symlink(oldname, newname string) error { … } // fmtCmd formats a command in the manner of fmt.Sprintf but also: // // fmtCmd replaces the value of b.WorkDir with $WORK. func (sh *Shell) fmtCmd(dir string, format string, args ...any) string { … } // ShowCmd prints the given command to standard output // for the implementation of -n or -x. // // ShowCmd also replaces the name of the current script directory with dot (.) // but only when it is at the beginning of a space-separated token. // // If dir is not "" or "/" and not the current script directory, ShowCmd first // prints a "cd" command to switch to dir and updates the script directory. func (sh *Shell) ShowCmd(dir string, format string, args ...any) { … } // reportCmd reports the output and exit status of a command. The cmdOut and // cmdErr arguments are the output and exit error of the command, respectively. // // The exact reporting behavior is as follows: // // cmdOut cmdErr Result // "" nil print nothing, return nil // !="" nil print output, return nil // "" !=nil print nothing, return cmdErr (later printed) // !="" !=nil print nothing, ignore err, return output as error (later printed) // // reportCmd returns a non-nil error if and only if cmdErr != nil. It assumes // that the command output, if non-empty, is more detailed than the command // error (which is usually just an exit status), so prefers using the output as // the ultimate error. Typically, the caller should return this error from an // Action, which it will be printed by the Builder. // // reportCmd formats the output as "# desc" followed by the given output. The // output is expected to contain references to 'dir', usually the source // directory for the package that has failed to build. reportCmd rewrites // mentions of dir with a relative path to dir when the relative path is // shorter. This is usually more pleasant. For example, if fmt doesn't compile // and we are in src/html, the output is // // $ go build // # fmt // ../fmt/print.go:1090: undefined: asdf // $ // // instead of // // $ go build // # fmt // /usr/gopher/go/src/fmt/print.go:1090: undefined: asdf // $ // // reportCmd also replaces references to the work directory with $WORK, replaces // cgo file paths with the original file path, and replaces cgo-mangled names // with "C.name". // // desc is optional. If "", a.Package.Desc() is used. // // dir is optional. If "", a.Package.Dir is used. func (sh *Shell) reportCmd(desc, dir string, cmdOut []byte, cmdErr error) error { … } // replacePrefix is like strings.ReplaceAll, but only replaces instances of old // that are preceded by ' ', '\t', or appear at the beginning of a line. func replacePrefix(s, old, new string) string { … } type cmdError … func (e *cmdError) Error() string { … } func (e *cmdError) ImportPath() string { … } var cgoLine … var cgoTypeSigRe … // run runs the command given by cmdline in the directory dir. // If the command fails, run prints information about the failure // and returns a non-nil error. func (sh *Shell) run(dir string, desc string, env []string, cmdargs ...any) error { … } // runOut runs the command given by cmdline in the directory dir. // It returns the command output and any errors that occurred. // It accumulates execution time in a. func (sh *Shell) runOut(dir string, env []string, cmdargs ...any) ([]byte, error) { … } // joinUnambiguously prints the slice, quoting where necessary to make the // output unambiguous. // TODO: See issue 5279. The printing of commands needs a complete redo. func joinUnambiguously(a []string) string { … }