Merge pull request #1143 from greut/fix-chown

unit tests on copy + chown
This commit is contained in:
Tejal Desai 2020-03-18 11:05:20 -07:00 committed by GitHub
commit b290502d0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 257 additions and 35 deletions

2
go.mod
View File

@ -46,7 +46,7 @@ require (
github.com/opentracing/opentracing-go v1.0.2 // indirect github.com/opentracing/opentracing-go v1.0.2 // indirect
github.com/otiai10/copy v1.0.2 github.com/otiai10/copy v1.0.2
github.com/pelletier/go-buffruneio v0.2.0 // indirect github.com/pelletier/go-buffruneio v0.2.0 // indirect
github.com/pkg/errors v0.8.1 github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v0.9.0-pre1.0.20180210140205-a40133b69fbd // indirect github.com/prometheus/client_golang v0.9.0-pre1.0.20180210140205-a40133b69fbd // indirect
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 // indirect github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 // indirect
github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1 // indirect github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1 // indirect

4
go.sum
View File

@ -287,10 +287,10 @@ github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtb
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

View File

@ -49,7 +49,7 @@ func (a *AddCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.Bui
uid, gid, err := util.GetUserGroup(a.cmd.Chown, replacementEnvs) uid, gid, err := util.GetUserGroup(a.cmd.Chown, replacementEnvs)
if err != nil { if err != nil {
return errors.Wrap(err, "getting user group from chowm") return errors.Wrap(err, "getting user group from chown")
} }
srcs, dest, err := util.ResolveEnvAndWildcards(a.cmd.SourcesAndDest, a.buildcontext, replacementEnvs) srcs, dest, err := util.ResolveEnvAndWildcards(a.cmd.SourcesAndDest, a.buildcontext, replacementEnvs)

View File

@ -32,6 +32,11 @@ import (
v1 "github.com/google/go-containerregistry/pkg/v1" v1 "github.com/google/go-containerregistry/pkg/v1"
) )
// for testing
var (
getUserGroup = util.GetUserGroup
)
type CopyCommand struct { type CopyCommand struct {
BaseCommand BaseCommand
cmd *instructions.CopyCommand cmd *instructions.CopyCommand
@ -46,9 +51,9 @@ func (c *CopyCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.Bu
} }
replacementEnvs := buildArgs.ReplacementEnvs(config.Env) replacementEnvs := buildArgs.ReplacementEnvs(config.Env)
uid, gid, err := util.GetUserGroup(c.cmd.Chown, replacementEnvs) uid, gid, err := getUserGroup(c.cmd.Chown, replacementEnvs)
if err != nil { if err != nil {
return errors.Wrap(err, "getting user group from chowm") return errors.Wrap(err, "getting user group from chown")
} }
srcs, dest, err := util.ResolveEnvAndWildcards(c.cmd.SourcesAndDest, c.buildcontext, replacementEnvs) srcs, dest, err := util.ResolveEnvAndWildcards(c.cmd.SourcesAndDest, c.buildcontext, replacementEnvs)

View File

@ -23,12 +23,14 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"syscall"
"testing" "testing"
"github.com/GoogleContainerTools/kaniko/pkg/dockerfile" "github.com/GoogleContainerTools/kaniko/pkg/dockerfile"
"github.com/GoogleContainerTools/kaniko/testutil" "github.com/GoogleContainerTools/kaniko/testutil"
v1 "github.com/google/go-containerregistry/pkg/v1" v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/moby/buildkit/frontend/dockerfile/instructions" "github.com/moby/buildkit/frontend/dockerfile/instructions"
"github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -539,6 +541,7 @@ func TestCopyCommand_ExecuteCommand_Extended(t *testing.T) {
testutil.CheckDeepEqual(t, files[0].Name(), "bam.txt") testutil.CheckDeepEqual(t, files[0].Name(), "bam.txt")
}) })
t.Run("copy symlink file to a dir", func(t *testing.T) { t.Run("copy symlink file to a dir", func(t *testing.T) {
testDir, srcDir := setupDirs(t) testDir, srcDir := setupDirs(t)
defer os.RemoveAll(testDir) defer os.RemoveAll(testDir)
@ -573,6 +576,7 @@ func TestCopyCommand_ExecuteCommand_Extended(t *testing.T) {
} }
testutil.CheckDeepEqual(t, linkName, "dam.txt") testutil.CheckDeepEqual(t, linkName, "dam.txt")
}) })
t.Run("copy deadlink symlink file to a dir", func(t *testing.T) { t.Run("copy deadlink symlink file to a dir", func(t *testing.T) {
testDir, srcDir := setupDirs(t) testDir, srcDir := setupDirs(t)
defer os.RemoveAll(testDir) defer os.RemoveAll(testDir)
@ -653,6 +657,7 @@ func TestCopyCommand_ExecuteCommand_Extended(t *testing.T) {
testutil.CheckDeepEqual(t, expected[i].Mode(), f.Mode()) testutil.CheckDeepEqual(t, expected[i].Mode(), f.Mode())
} }
}) })
t.Run("copy dir with a symlink to a file outside of current src dir", func(t *testing.T) { t.Run("copy dir with a symlink to a file outside of current src dir", func(t *testing.T) {
testDir, srcDir := setupDirs(t) testDir, srcDir := setupDirs(t)
defer os.RemoveAll(testDir) defer os.RemoveAll(testDir)
@ -705,6 +710,7 @@ func TestCopyCommand_ExecuteCommand_Extended(t *testing.T) {
} }
testutil.CheckDeepEqual(t, linkName, targetPath) testutil.CheckDeepEqual(t, linkName, targetPath)
}) })
t.Run("copy src symlink dir to a dir", func(t *testing.T) { t.Run("copy src symlink dir to a dir", func(t *testing.T) {
testDir, srcDir := setupDirs(t) testDir, srcDir := setupDirs(t)
defer os.RemoveAll(testDir) defer os.RemoveAll(testDir)
@ -741,6 +747,7 @@ func TestCopyCommand_ExecuteCommand_Extended(t *testing.T) {
testutil.CheckDeepEqual(t, expected[i].Mode(), f.Mode()) testutil.CheckDeepEqual(t, expected[i].Mode(), f.Mode())
} }
}) })
t.Run("copy src dir to a dest dir which is a symlink", func(t *testing.T) { t.Run("copy src dir to a dest dir which is a symlink", func(t *testing.T) {
testDir, srcDir := setupDirs(t) testDir, srcDir := setupDirs(t)
defer os.RemoveAll(testDir) defer os.RemoveAll(testDir)
@ -789,6 +796,7 @@ func TestCopyCommand_ExecuteCommand_Extended(t *testing.T) {
} }
testutil.CheckDeepEqual(t, linkName, dest) testutil.CheckDeepEqual(t, linkName, dest)
}) })
t.Run("copy src file to a dest dir which is a symlink", func(t *testing.T) { t.Run("copy src file to a dest dir which is a symlink", func(t *testing.T) {
testDir, srcDir := setupDirs(t) testDir, srcDir := setupDirs(t)
defer os.RemoveAll(testDir) defer os.RemoveAll(testDir)
@ -835,4 +843,83 @@ func TestCopyCommand_ExecuteCommand_Extended(t *testing.T) {
} }
testutil.CheckDeepEqual(t, linkName, dest) testutil.CheckDeepEqual(t, linkName, dest)
}) })
t.Run("copy src file to a dest dir with chown", func(t *testing.T) {
testDir, srcDir := setupDirs(t)
defer os.RemoveAll(testDir)
original := getUserGroup
defer func() { getUserGroup = original }()
uid := os.Getuid()
gid := os.Getgid()
getUserGroup = func(userStr string, _ []string) (int64, int64, error) {
return int64(uid), int64(gid), nil
}
cmd := CopyCommand{
cmd: &instructions.CopyCommand{
SourcesAndDest: []string{fmt.Sprintf("%s/bam.txt", srcDir), testDir},
Chown: "alice:group",
},
buildcontext: testDir,
}
cfg := &v1.Config{
Cmd: nil,
Env: []string{},
WorkingDir: testDir,
}
err := cmd.ExecuteCommand(cfg, dockerfile.NewBuildArgs([]string{}))
testutil.CheckNoError(t, err)
actual, err := ioutil.ReadDir(filepath.Join(testDir))
if err != nil {
t.Fatal(err)
}
testutil.CheckDeepEqual(t, "bam.txt", actual[0].Name())
if stat, ok := actual[0].Sys().(*syscall.Stat_t); ok {
if int(stat.Uid) != uid {
t.Errorf("uid don't match, got %d, expected %d", stat.Uid, uid)
}
if int(stat.Gid) != gid {
t.Errorf("gid don't match, got %d, expected %d", stat.Gid, gid)
}
}
})
t.Run("copy src file to a dest dir with chown and random user", func(t *testing.T) {
testDir, srcDir := setupDirs(t)
defer os.RemoveAll(testDir)
original := getUserGroup
defer func() { getUserGroup = original }()
getUserGroup = func(userStr string, _ []string) (int64, int64, error) {
return 12345, 12345, nil
}
cmd := CopyCommand{
cmd: &instructions.CopyCommand{
SourcesAndDest: []string{fmt.Sprintf("%s/bam.txt", srcDir), testDir},
Chown: "missing:missing",
},
buildcontext: testDir,
}
cfg := &v1.Config{
Cmd: nil,
Env: []string{},
WorkingDir: testDir,
}
err := cmd.ExecuteCommand(cfg, dockerfile.NewBuildArgs([]string{}))
if !errors.Is(err, os.ErrPermission) {
testutil.CheckNoError(t, err)
}
})
} }

View File

@ -344,14 +344,17 @@ func GetUserGroup(chownStr string, env []string) (int64, int64, error) {
if chownStr == "" { if chownStr == "" {
return DoNotChangeUID, DoNotChangeGID, nil return DoNotChangeUID, DoNotChangeGID, nil
} }
chown, err := ResolveEnvironmentReplacement(chownStr, env, false) chown, err := ResolveEnvironmentReplacement(chownStr, env, false)
if err != nil { if err != nil {
return -1, -1, err return -1, -1, err
} }
uid32, gid32, err := getUIDAndGID(chown, true) uid32, gid32, err := getUIDAndGID(chown, true)
if err != nil { if err != nil {
return -1, -1, err return -1, -1, err
} }
return int64(uid32), int64(gid32), nil return int64(uid32), int64(gid32), nil
} }
@ -370,15 +373,18 @@ func GetUIDAndGIDFromString(userGroupString string, fallbackToUID bool) (uint32,
if err != nil { if err != nil {
return 0, 0, err return 0, 0, err
} }
// uid and gid need to be fit into uint32 // uid and gid need to be fit into uint32
uid64, err := strconv.ParseUint(uidStr, 10, 32) uid64, err := strconv.ParseUint(uidStr, 10, 32)
if err != nil { if err != nil {
return 0, 0, err return 0, 0, err
} }
gid64, err := strconv.ParseUint(gidStr, 10, 32) gid64, err := strconv.ParseUint(gidStr, 10, 32)
if err != nil { if err != nil {
return 0, 0, err return 0, 0, err
} }
return uint32(uid64), uint32(gid64), nil return uint32(uid64), uint32(gid64), nil
} }
@ -422,11 +428,15 @@ func Lookup(userStr string) (*user.User, error) {
if _, ok := err.(user.UnknownUserError); !ok { if _, ok := err.(user.UnknownUserError); !ok {
return nil, err return nil, err
} }
// Lookup by id // Lookup by id
userObj, err = user.LookupId(userStr) u, e := user.LookupId(userStr)
if err != nil { if e != nil {
return nil, err return nil, err
} }
userObj = u
} }
return userObj, nil return userObj, nil
} }

View File

@ -70,7 +70,7 @@ func CheckError(t *testing.T, shouldErr bool, err error) {
func CheckNoError(t *testing.T, err error) { func CheckNoError(t *testing.T, err error) {
if err != nil { if err != nil {
t.Error(err) t.Errorf("%+v", err)
} }
} }

View File

@ -1,15 +1,10 @@
language: go language: go
go_import_path: github.com/pkg/errors go_import_path: github.com/pkg/errors
go: go:
- 1.4.x
- 1.5.x
- 1.6.x
- 1.7.x
- 1.8.x
- 1.9.x
- 1.10.x
- 1.11.x - 1.11.x
- 1.12.x
- 1.13.x
- tip - tip
script: script:
- go test -v ./... - make check

44
vendor/github.com/pkg/errors/Makefile generated vendored Normal file
View File

@ -0,0 +1,44 @@
PKGS := github.com/pkg/errors
SRCDIRS := $(shell go list -f '{{.Dir}}' $(PKGS))
GO := go
check: test vet gofmt misspell unconvert staticcheck ineffassign unparam
test:
$(GO) test $(PKGS)
vet: | test
$(GO) vet $(PKGS)
staticcheck:
$(GO) get honnef.co/go/tools/cmd/staticcheck
staticcheck -checks all $(PKGS)
misspell:
$(GO) get github.com/client9/misspell/cmd/misspell
misspell \
-locale GB \
-error \
*.md *.go
unconvert:
$(GO) get github.com/mdempsky/unconvert
unconvert -v $(PKGS)
ineffassign:
$(GO) get github.com/gordonklaus/ineffassign
find $(SRCDIRS) -name '*.go' | xargs ineffassign
pedantic: check errcheck
unparam:
$(GO) get mvdan.cc/unparam
unparam ./...
errcheck:
$(GO) get github.com/kisielk/errcheck
errcheck $(PKGS)
gofmt:
@echo Checking code is gofmted
@test -z "$(shell gofmt -s -l -d -e $(SRCDIRS) | tee /dev/stderr)"

View File

@ -41,11 +41,18 @@ default:
[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors). [Read the package documentation for more information](https://godoc.org/github.com/pkg/errors).
## Roadmap
With the upcoming [Go2 error proposals](https://go.googlesource.com/proposal/+/master/design/go2draft.md) this package is moving into maintenance mode. The roadmap for a 1.0 release is as follows:
- 0.9. Remove pre Go 1.9 and Go 1.10 support, address outstanding pull requests (if possible)
- 1.0. Final release.
## Contributing ## Contributing
We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high. Because of the Go2 errors changes, this package is not accepting proposals for new functionality. With that said, we welcome pull requests, bug fixes and issue reports.
Before proposing a change, please discuss your change by raising an issue. Before sending a PR, please discuss your change by raising an issue.
## License ## License

View File

@ -82,7 +82,7 @@
// //
// if err, ok := err.(stackTracer); ok { // if err, ok := err.(stackTracer); ok {
// for _, f := range err.StackTrace() { // for _, f := range err.StackTrace() {
// fmt.Printf("%+s:%d", f) // fmt.Printf("%+s:%d\n", f, f)
// } // }
// } // }
// //
@ -159,6 +159,9 @@ type withStack struct {
func (w *withStack) Cause() error { return w.error } func (w *withStack) Cause() error { return w.error }
// Unwrap provides compatibility for Go 1.13 error chains.
func (w *withStack) Unwrap() error { return w.error }
func (w *withStack) Format(s fmt.State, verb rune) { func (w *withStack) Format(s fmt.State, verb rune) {
switch verb { switch verb {
case 'v': case 'v':
@ -241,6 +244,9 @@ type withMessage struct {
func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() } func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
func (w *withMessage) Cause() error { return w.cause } func (w *withMessage) Cause() error { return w.cause }
// Unwrap provides compatibility for Go 1.13 error chains.
func (w *withMessage) Unwrap() error { return w.cause }
func (w *withMessage) Format(s fmt.State, verb rune) { func (w *withMessage) Format(s fmt.State, verb rune) {
switch verb { switch verb {
case 'v': case 'v':

38
vendor/github.com/pkg/errors/go113.go generated vendored Normal file
View File

@ -0,0 +1,38 @@
// +build go1.13
package errors
import (
stderrors "errors"
)
// Is reports whether any error in err's chain matches target.
//
// The chain consists of err itself followed by the sequence of errors obtained by
// repeatedly calling Unwrap.
//
// An error is considered to match a target if it is equal to that target or if
// it implements a method Is(error) bool such that Is(target) returns true.
func Is(err, target error) bool { return stderrors.Is(err, target) }
// As finds the first error in err's chain that matches target, and if so, sets
// target to that error value and returns true.
//
// The chain consists of err itself followed by the sequence of errors obtained by
// repeatedly calling Unwrap.
//
// An error matches target if the error's concrete value is assignable to the value
// pointed to by target, or if the error has a method As(interface{}) bool such that
// As(target) returns true. In the latter case, the As method is responsible for
// setting target.
//
// As will panic if target is not a non-nil pointer to either a type that implements
// error, or to any interface type. As returns false if err is nil.
func As(err error, target interface{}) bool { return stderrors.As(err, target) }
// Unwrap returns the result of calling the Unwrap method on err, if err's
// type contains an Unwrap method returning error.
// Otherwise, Unwrap returns nil.
func Unwrap(err error) error {
return stderrors.Unwrap(err)
}

View File

@ -5,10 +5,13 @@ import (
"io" "io"
"path" "path"
"runtime" "runtime"
"strconv"
"strings" "strings"
) )
// Frame represents a program counter inside a stack frame. // Frame represents a program counter inside a stack frame.
// For historical reasons if Frame is interpreted as a uintptr
// its value represents the program counter + 1.
type Frame uintptr type Frame uintptr
// pc returns the program counter for this frame; // pc returns the program counter for this frame;
@ -37,6 +40,15 @@ func (f Frame) line() int {
return line return line
} }
// name returns the name of this function, if known.
func (f Frame) name() string {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return "unknown"
}
return fn.Name()
}
// Format formats the frame according to the fmt.Formatter interface. // Format formats the frame according to the fmt.Formatter interface.
// //
// %s source file // %s source file
@ -54,22 +66,16 @@ func (f Frame) Format(s fmt.State, verb rune) {
case 's': case 's':
switch { switch {
case s.Flag('+'): case s.Flag('+'):
pc := f.pc() io.WriteString(s, f.name())
fn := runtime.FuncForPC(pc) io.WriteString(s, "\n\t")
if fn == nil { io.WriteString(s, f.file())
io.WriteString(s, "unknown")
} else {
file, _ := fn.FileLine(pc)
fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file)
}
default: default:
io.WriteString(s, path.Base(f.file())) io.WriteString(s, path.Base(f.file()))
} }
case 'd': case 'd':
fmt.Fprintf(s, "%d", f.line()) io.WriteString(s, strconv.Itoa(f.line()))
case 'n': case 'n':
name := runtime.FuncForPC(f.pc()).Name() io.WriteString(s, funcname(f.name()))
io.WriteString(s, funcname(name))
case 'v': case 'v':
f.Format(s, 's') f.Format(s, 's')
io.WriteString(s, ":") io.WriteString(s, ":")
@ -77,6 +83,16 @@ func (f Frame) Format(s fmt.State, verb rune) {
} }
} }
// MarshalText formats a stacktrace Frame as a text string. The output is the
// same as that of fmt.Sprintf("%+v", f), but without newlines or tabs.
func (f Frame) MarshalText() ([]byte, error) {
name := f.name()
if name == "unknown" {
return []byte(name), nil
}
return []byte(fmt.Sprintf("%s %s:%d", name, f.file(), f.line())), nil
}
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest). // StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
type StackTrace []Frame type StackTrace []Frame
@ -94,18 +110,32 @@ func (st StackTrace) Format(s fmt.State, verb rune) {
switch { switch {
case s.Flag('+'): case s.Flag('+'):
for _, f := range st { for _, f := range st {
fmt.Fprintf(s, "\n%+v", f) io.WriteString(s, "\n")
f.Format(s, verb)
} }
case s.Flag('#'): case s.Flag('#'):
fmt.Fprintf(s, "%#v", []Frame(st)) fmt.Fprintf(s, "%#v", []Frame(st))
default: default:
fmt.Fprintf(s, "%v", []Frame(st)) st.formatSlice(s, verb)
} }
case 's': case 's':
fmt.Fprintf(s, "%s", []Frame(st)) st.formatSlice(s, verb)
} }
} }
// formatSlice will format this StackTrace into the given buffer as a slice of
// Frame, only valid when called with '%s' or '%v'.
func (st StackTrace) formatSlice(s fmt.State, verb rune) {
io.WriteString(s, "[")
for i, f := range st {
if i > 0 {
io.WriteString(s, " ")
}
f.Format(s, verb)
}
io.WriteString(s, "]")
}
// stack represents a stack of program counters. // stack represents a stack of program counters.
type stack []uintptr type stack []uintptr

2
vendor/modules.txt vendored
View File

@ -396,7 +396,7 @@ github.com/otiai10/copy
github.com/pelletier/go-buffruneio github.com/pelletier/go-buffruneio
# github.com/peterbourgon/diskv v2.0.1+incompatible # github.com/peterbourgon/diskv v2.0.1+incompatible
github.com/peterbourgon/diskv github.com/peterbourgon/diskv
# github.com/pkg/errors v0.8.1 # github.com/pkg/errors v0.9.1
## explicit ## explicit
github.com/pkg/errors github.com/pkg/errors
# github.com/prometheus/client_golang v0.9.0-pre1.0.20180210140205-a40133b69fbd # github.com/prometheus/client_golang v0.9.0-pre1.0.20180210140205-a40133b69fbd