aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com')
-rw-r--r--vendor/github.com/containers/common/pkg/seccomp/conversion.go204
-rw-r--r--vendor/github.com/containers/common/pkg/seccomp/filter.go237
-rw-r--r--vendor/github.com/containers/common/pkg/seccomp/seccomp_linux.go4
-rw-r--r--vendor/github.com/containers/common/pkg/seccomp/validate.go29
-rw-r--r--vendor/github.com/containers/common/version/version.go2
-rw-r--r--vendor/github.com/containers/image/v5/copy/copy.go4
-rw-r--r--vendor/github.com/containers/image/v5/docker/archive/dest.go50
-rw-r--r--vendor/github.com/containers/image/v5/docker/archive/reader.go120
-rw-r--r--vendor/github.com/containers/image/v5/docker/archive/src.go22
-rw-r--r--vendor/github.com/containers/image/v5/docker/archive/transport.go95
-rw-r--r--vendor/github.com/containers/image/v5/docker/archive/writer.go82
-rw-r--r--vendor/github.com/containers/image/v5/docker/daemon/daemon_dest.go9
-rw-r--r--vendor/github.com/containers/image/v5/docker/daemon/daemon_src.go5
-rw-r--r--vendor/github.com/containers/image/v5/docker/docker_image_dest.go15
-rw-r--r--vendor/github.com/containers/image/v5/docker/docker_image_src.go6
-rw-r--r--vendor/github.com/containers/image/v5/docker/errors.go14
-rw-r--r--vendor/github.com/containers/image/v5/docker/internal/tarfile/dest.go217
-rw-r--r--vendor/github.com/containers/image/v5/docker/internal/tarfile/reader.go269
-rw-r--r--vendor/github.com/containers/image/v5/docker/internal/tarfile/src.go331
-rw-r--r--vendor/github.com/containers/image/v5/docker/internal/tarfile/types.go28
-rw-r--r--vendor/github.com/containers/image/v5/docker/internal/tarfile/writer.go381
-rw-r--r--vendor/github.com/containers/image/v5/docker/lookaside.go21
-rw-r--r--vendor/github.com/containers/image/v5/docker/tarfile/dest.go343
-rw-r--r--vendor/github.com/containers/image/v5/docker/tarfile/src.go442
-rw-r--r--vendor/github.com/containers/image/v5/docker/tarfile/types.go24
-rw-r--r--vendor/github.com/containers/image/v5/oci/layout/oci_src.go4
-rw-r--r--vendor/github.com/containers/image/v5/pkg/docker/config/config.go4
-rw-r--r--vendor/github.com/containers/image/v5/pkg/sysregistriesv2/system_registries_v2.go167
-rw-r--r--vendor/github.com/containers/image/v5/version/version.go2
-rw-r--r--vendor/github.com/containers/storage/VERSION2
-rw-r--r--vendor/github.com/containers/storage/go.mod5
-rw-r--r--vendor/github.com/containers/storage/go.sum8
-rw-r--r--vendor/github.com/containers/storage/layers.go2
-rw-r--r--vendor/github.com/containers/storage/pkg/mount/mount.go29
-rw-r--r--vendor/github.com/containers/storage/pkg/mount/mountinfo.go49
-rw-r--r--vendor/github.com/containers/storage/pkg/mount/mountinfo_linux.go119
-rw-r--r--vendor/github.com/containers/storage/pkg/mount/mountinfo_unsupported.go12
-rw-r--r--vendor/github.com/containers/storage/utils.go16
-rw-r--r--vendor/github.com/imdario/mergo/README.md69
-rw-r--r--vendor/github.com/imdario/mergo/doc.go141
-rw-r--r--vendor/github.com/imdario/mergo/go.mod5
-rw-r--r--vendor/github.com/imdario/mergo/go.sum4
-rw-r--r--vendor/github.com/imdario/mergo/map.go10
-rw-r--r--vendor/github.com/imdario/mergo/merge.go269
-rw-r--r--vendor/github.com/imdario/mergo/mergo.go21
-rw-r--r--vendor/github.com/klauspost/compress/flate/fast_encoder.go10
-rw-r--r--vendor/github.com/klauspost/compress/flate/gen_inflate.go32
-rw-r--r--vendor/github.com/klauspost/compress/flate/huffman_bit_writer.go8
-rw-r--r--vendor/github.com/klauspost/compress/flate/inflate.go38
-rw-r--r--vendor/github.com/klauspost/compress/flate/inflate_gen.go128
-rw-r--r--vendor/github.com/klauspost/compress/flate/regmask_amd64.go37
-rw-r--r--vendor/github.com/klauspost/compress/flate/regmask_other.go39
-rw-r--r--vendor/github.com/klauspost/compress/huff0/huff0.go10
-rw-r--r--vendor/github.com/klauspost/compress/zstd/README.md51
-rw-r--r--vendor/github.com/klauspost/compress/zstd/blockdec.go2
-rw-r--r--vendor/github.com/klauspost/compress/zstd/blockenc.go67
-rw-r--r--vendor/github.com/klauspost/compress/zstd/decoder.go8
-rw-r--r--vendor/github.com/klauspost/compress/zstd/dict.go26
-rw-r--r--vendor/github.com/klauspost/compress/zstd/enc_base.go155
-rw-r--r--vendor/github.com/klauspost/compress/zstd/enc_better.go81
-rw-r--r--vendor/github.com/klauspost/compress/zstd/enc_dfast.go39
-rw-r--r--vendor/github.com/klauspost/compress/zstd/enc_fast.go170
-rw-r--r--vendor/github.com/klauspost/compress/zstd/enc_params.go157
-rw-r--r--vendor/github.com/klauspost/compress/zstd/encoder.go39
-rw-r--r--vendor/github.com/klauspost/compress/zstd/encoder_options.go14
-rw-r--r--vendor/github.com/klauspost/compress/zstd/frameenc.go26
-rw-r--r--vendor/github.com/klauspost/compress/zstd/history.go4
-rw-r--r--vendor/github.com/klauspost/compress/zstd/seqdec.go8
-rw-r--r--vendor/github.com/klauspost/compress/zstd/snappy.go8
-rw-r--r--vendor/github.com/klauspost/pgzip/.travis.yml17
-rw-r--r--vendor/github.com/klauspost/pgzip/gunzip.go11
-rw-r--r--vendor/github.com/mattn/go-isatty/.travis.yml14
-rw-r--r--vendor/github.com/mattn/go-isatty/LICENSE9
-rw-r--r--vendor/github.com/mattn/go-isatty/README.md50
-rw-r--r--vendor/github.com/mattn/go-isatty/doc.go2
-rw-r--r--vendor/github.com/mattn/go-isatty/go.mod5
-rw-r--r--vendor/github.com/mattn/go-isatty/go.sum2
-rw-r--r--vendor/github.com/mattn/go-isatty/go.test.sh12
-rw-r--r--vendor/github.com/mattn/go-isatty/isatty_bsd.go18
-rw-r--r--vendor/github.com/mattn/go-isatty/isatty_others.go15
-rw-r--r--vendor/github.com/mattn/go-isatty/isatty_plan9.go22
-rw-r--r--vendor/github.com/mattn/go-isatty/isatty_solaris.go22
-rw-r--r--vendor/github.com/mattn/go-isatty/isatty_tcgets.go18
-rw-r--r--vendor/github.com/mattn/go-isatty/isatty_windows.go125
-rw-r--r--vendor/github.com/mattn/go-isatty/renovate.json8
-rw-r--r--vendor/github.com/moby/sys/mountinfo/LICENSE202
-rw-r--r--vendor/github.com/moby/sys/mountinfo/go.mod3
-rw-r--r--vendor/github.com/moby/sys/mountinfo/mountinfo.go67
-rw-r--r--vendor/github.com/moby/sys/mountinfo/mountinfo_filters.go58
-rw-r--r--vendor/github.com/moby/sys/mountinfo/mountinfo_freebsd.go (renamed from vendor/github.com/containers/storage/pkg/mount/mountinfo_freebsd.go)22
-rw-r--r--vendor/github.com/moby/sys/mountinfo/mountinfo_linux.go152
-rw-r--r--vendor/github.com/moby/sys/mountinfo/mountinfo_unsupported.go17
-rw-r--r--vendor/github.com/moby/sys/mountinfo/mountinfo_windows.go12
-rw-r--r--vendor/github.com/onsi/ginkgo/CHANGELOG.md5
-rw-r--r--vendor/github.com/onsi/ginkgo/README.md5
-rw-r--r--vendor/github.com/onsi/ginkgo/config/config.go2
-rw-r--r--vendor/github.com/onsi/ginkgo/ginkgo/nodot/nodot.go4
-rw-r--r--vendor/github.com/onsi/gomega/CHANGELOG.md5
-rw-r--r--vendor/github.com/onsi/gomega/gomega_dsl.go35
-rw-r--r--vendor/github.com/ulikunitz/xz/TODO.md5
-rw-r--r--vendor/github.com/ulikunitz/xz/bits.go7
-rw-r--r--vendor/github.com/vbauerster/mpb/v5/bar.go28
-rw-r--r--vendor/github.com/vbauerster/mpb/v5/cwriter/util_bsd.go7
-rw-r--r--vendor/github.com/vbauerster/mpb/v5/cwriter/util_linux.go7
-rw-r--r--vendor/github.com/vbauerster/mpb/v5/cwriter/util_solaris.go7
-rw-r--r--vendor/github.com/vbauerster/mpb/v5/cwriter/writer.go28
-rw-r--r--vendor/github.com/vbauerster/mpb/v5/cwriter/writer_posix.go16
-rw-r--r--vendor/github.com/vbauerster/mpb/v5/cwriter/writer_windows.go86
-rw-r--r--vendor/github.com/vbauerster/mpb/v5/decor/counters.go206
-rw-r--r--vendor/github.com/vbauerster/mpb/v5/go.mod3
-rw-r--r--vendor/github.com/vbauerster/mpb/v5/go.sum7
111 files changed, 4139 insertions, 2256 deletions
diff --git a/vendor/github.com/containers/common/pkg/seccomp/conversion.go b/vendor/github.com/containers/common/pkg/seccomp/conversion.go
index 79a893ba3..dfab381a5 100644
--- a/vendor/github.com/containers/common/pkg/seccomp/conversion.go
+++ b/vendor/github.com/containers/common/pkg/seccomp/conversion.go
@@ -1,25 +1,92 @@
+// NOTE: this package has originally been copied from
+// github.com/opencontainers/runc and modified to work for other use cases
+
package seccomp
-import "fmt"
-
-var goArchToSeccompArchMap = map[string]Arch{
- "386": ArchX86,
- "amd64": ArchX86_64,
- "amd64p32": ArchX32,
- "arm": ArchARM,
- "arm64": ArchAARCH64,
- "mips": ArchMIPS,
- "mips64": ArchMIPS64,
- "mips64le": ArchMIPSEL64,
- "mips64p32": ArchMIPS64N32,
- "mips64p32le": ArchMIPSEL64N32,
- "mipsle": ArchMIPSEL,
- "ppc": ArchPPC,
- "ppc64": ArchPPC64,
- "ppc64le": ArchPPC64LE,
- "s390": ArchS390,
- "s390x": ArchS390X,
-}
+import (
+ "fmt"
+
+ "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/pkg/errors"
+)
+
+var (
+ goArchToSeccompArchMap = map[string]Arch{
+ "386": ArchX86,
+ "amd64": ArchX86_64,
+ "amd64p32": ArchX32,
+ "arm": ArchARM,
+ "arm64": ArchAARCH64,
+ "mips": ArchMIPS,
+ "mips64": ArchMIPS64,
+ "mips64le": ArchMIPSEL64,
+ "mips64p32": ArchMIPS64N32,
+ "mips64p32le": ArchMIPSEL64N32,
+ "mipsle": ArchMIPSEL,
+ "ppc": ArchPPC,
+ "ppc64": ArchPPC64,
+ "ppc64le": ArchPPC64LE,
+ "s390": ArchS390,
+ "s390x": ArchS390X,
+ }
+ specArchToLibseccompArchMap = map[specs.Arch]string{
+ specs.ArchX86: "x86",
+ specs.ArchX86_64: "amd64",
+ specs.ArchX32: "x32",
+ specs.ArchARM: "arm",
+ specs.ArchAARCH64: "arm64",
+ specs.ArchMIPS: "mips",
+ specs.ArchMIPS64: "mips64",
+ specs.ArchMIPS64N32: "mips64n32",
+ specs.ArchMIPSEL: "mipsel",
+ specs.ArchMIPSEL64: "mipsel64",
+ specs.ArchMIPSEL64N32: "mipsel64n32",
+ specs.ArchPPC: "ppc",
+ specs.ArchPPC64: "ppc64",
+ specs.ArchPPC64LE: "ppc64le",
+ specs.ArchS390: "s390",
+ specs.ArchS390X: "s390x",
+ }
+ specArchToSeccompArchMap = map[specs.Arch]Arch{
+ specs.ArchX86: ArchX86,
+ specs.ArchX86_64: ArchX86_64,
+ specs.ArchX32: ArchX32,
+ specs.ArchARM: ArchARM,
+ specs.ArchAARCH64: ArchAARCH64,
+ specs.ArchMIPS: ArchMIPS,
+ specs.ArchMIPS64: ArchMIPS64,
+ specs.ArchMIPS64N32: ArchMIPS64N32,
+ specs.ArchMIPSEL: ArchMIPSEL,
+ specs.ArchMIPSEL64: ArchMIPSEL64,
+ specs.ArchMIPSEL64N32: ArchMIPSEL64N32,
+ specs.ArchPPC: ArchPPC,
+ specs.ArchPPC64: ArchPPC64,
+ specs.ArchPPC64LE: ArchPPC64LE,
+ specs.ArchS390: ArchS390,
+ specs.ArchS390X: ArchS390X,
+ }
+ specActionToSeccompActionMap = map[specs.LinuxSeccompAction]Action{
+ specs.ActKill: ActKill,
+ // TODO: wait for this PR to get merged:
+ // https://github.com/opencontainers/runtime-spec/pull/1064
+ // specs.ActKillProcess ActKillProcess,
+ // specs.ActKillThread ActKillThread,
+ specs.ActErrno: ActErrno,
+ specs.ActTrap: ActTrap,
+ specs.ActAllow: ActAllow,
+ specs.ActTrace: ActTrace,
+ specs.ActLog: ActLog,
+ }
+ specOperatorToSeccompOperatorMap = map[specs.LinuxSeccompOperator]Operator{
+ specs.OpNotEqual: OpNotEqual,
+ specs.OpLessThan: OpLessThan,
+ specs.OpLessEqual: OpLessEqual,
+ specs.OpEqualTo: OpEqualTo,
+ specs.OpGreaterEqual: OpGreaterEqual,
+ specs.OpGreaterThan: OpGreaterThan,
+ specs.OpMaskedEqual: OpMaskedEqual,
+ }
+)
// GoArchToSeccompArch converts a runtime.GOARCH to a seccomp `Arch`. The
// function returns an error if the architecture conversion is not supported.
@@ -30,3 +97,100 @@ func GoArchToSeccompArch(goArch string) (Arch, error) {
}
return arch, nil
}
+
+// specToSeccomp converts a `LinuxSeccomp` spec into a `Seccomp` struct.
+func specToSeccomp(spec *specs.LinuxSeccomp) (*Seccomp, error) {
+ res := &Seccomp{
+ Syscalls: []*Syscall{},
+ }
+
+ for _, arch := range spec.Architectures {
+ newArch, err := specArchToSeccompArch(arch)
+ if err != nil {
+ return nil, errors.Wrap(err, "convert spec arch")
+ }
+ res.Architectures = append(res.Architectures, newArch)
+ }
+
+ // Convert default action
+ newDefaultAction, err := specActionToSeccompAction(spec.DefaultAction)
+ if err != nil {
+ return nil, errors.Wrap(err, "convert default action")
+ }
+ res.DefaultAction = newDefaultAction
+
+ // Loop through all syscall blocks and convert them to the internal format
+ for _, call := range spec.Syscalls {
+ newAction, err := specActionToSeccompAction(call.Action)
+ if err != nil {
+ return nil, errors.Wrap(err, "convert action")
+ }
+
+ for _, name := range call.Names {
+ newCall := Syscall{
+ Name: name,
+ Action: newAction,
+ ErrnoRet: call.ErrnoRet,
+ Args: []*Arg{},
+ }
+
+ // Loop through all the arguments of the syscall and convert them
+ for _, arg := range call.Args {
+ newOp, err := specOperatorToSeccompOperator(arg.Op)
+ if err != nil {
+ return nil, errors.Wrap(err, "convert operator")
+ }
+
+ newArg := Arg{
+ Index: arg.Index,
+ Value: arg.Value,
+ ValueTwo: arg.ValueTwo,
+ Op: newOp,
+ }
+
+ newCall.Args = append(newCall.Args, &newArg)
+ }
+ res.Syscalls = append(res.Syscalls, &newCall)
+ }
+ }
+
+ return res, nil
+}
+
+// specArchToLibseccompArch converts a spec arch into a libseccomp one.
+func specArchToLibseccompArch(arch specs.Arch) (string, error) {
+ if res, ok := specArchToLibseccompArchMap[arch]; ok {
+ return res, nil
+ }
+ return "", errors.Errorf(
+ "architecture %q is not valid for libseccomp", arch,
+ )
+}
+
+// specArchToSeccompArch converts a spec arch into an internal one.
+func specArchToSeccompArch(arch specs.Arch) (Arch, error) {
+ if res, ok := specArchToSeccompArchMap[arch]; ok {
+ return res, nil
+ }
+ return "", errors.Errorf("architecture %q is not valid", arch)
+}
+
+// specActionToSeccompAction converts a spec action into a seccomp one.
+func specActionToSeccompAction(action specs.LinuxSeccompAction) (Action, error) {
+ if res, ok := specActionToSeccompActionMap[action]; ok {
+ return res, nil
+ }
+ return "", errors.Errorf(
+ "spec action %q is not valid internal action", action,
+ )
+}
+
+// specOperatorToSeccompOperator converts a spec operator into a seccomp one.
+func specOperatorToSeccompOperator(operator specs.LinuxSeccompOperator) (Operator, error) {
+ if op, ok := specOperatorToSeccompOperatorMap[operator]; ok {
+ return op, nil
+ }
+ return "", errors.Errorf(
+ "spec operator %q is not a valid internal operator", operator,
+ )
+}
diff --git a/vendor/github.com/containers/common/pkg/seccomp/filter.go b/vendor/github.com/containers/common/pkg/seccomp/filter.go
new file mode 100644
index 000000000..ac9b2698f
--- /dev/null
+++ b/vendor/github.com/containers/common/pkg/seccomp/filter.go
@@ -0,0 +1,237 @@
+// +build seccomp
+
+// NOTE: this package has originally been copied from
+// github.com/opencontainers/runc and modified to work for other use cases
+
+package seccomp
+
+import (
+ specs "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/pkg/errors"
+ libseccomp "github.com/seccomp/libseccomp-golang"
+ "golang.org/x/sys/unix"
+)
+
+// NOTE: this package has originally been copied from
+// github.com/opencontainers/runc and modified to work for other use cases
+
+var (
+ // ErrSpecNil is a possible return error from BuildFilter() and occurs if
+ // the provided spec is nil.
+ ErrSpecNil = errors.New("spec is nil")
+
+ // ErrSpecEmpty is a possible return error from BuildFilter() and occurs if
+ // the provided spec has neither a DefaultAction nor any syscalls.
+ ErrSpecEmpty = errors.New("spec contains neither a default action nor any syscalls")
+)
+
+// BuildFilter does a basic validation for the provided seccomp profile
+// string and returns a filter for it.
+func BuildFilter(spec *specs.LinuxSeccomp) (*libseccomp.ScmpFilter, error) {
+ // Sanity checking to allow consumers to act accordingly
+ if spec == nil {
+ return nil, ErrSpecNil
+ }
+ if spec.DefaultAction == "" && len(spec.Syscalls) == 0 {
+ return nil, ErrSpecEmpty
+ }
+
+ profile, err := specToSeccomp(spec)
+ if err != nil {
+ return nil, errors.Wrap(err, "convert spec to seccomp profile")
+ }
+
+ defaultAction, err := toAction(profile.DefaultAction, nil)
+ if err != nil {
+ return nil, errors.Wrapf(err, "convert default action %s", profile.DefaultAction)
+ }
+
+ filter, err := libseccomp.NewFilter(defaultAction)
+ if err != nil {
+ return nil, errors.Wrapf(err, "create filter for default action %s", defaultAction)
+ }
+
+ // Add extra architectures
+ for _, arch := range spec.Architectures {
+ libseccompArch, err := specArchToLibseccompArch(arch)
+ if err != nil {
+ return nil, errors.Wrap(err, "convert spec arch")
+ }
+
+ scmpArch, err := libseccomp.GetArchFromString(libseccompArch)
+ if err != nil {
+ return nil, errors.Wrapf(err, "validate Seccomp architecture %s", arch)
+ }
+
+ if err := filter.AddArch(scmpArch); err != nil {
+ return nil, errors.Wrap(err, "add architecture to seccomp filter")
+ }
+ }
+
+ // Unset no new privs bit
+ if err := filter.SetNoNewPrivsBit(false); err != nil {
+ return nil, errors.Wrap(err, "set no new privileges flag")
+ }
+
+ // Add a rule for each syscall
+ for _, call := range profile.Syscalls {
+ if call == nil {
+ return nil, errors.New("encountered nil syscall while initializing seccomp")
+ }
+
+ if err = matchSyscall(filter, call); err != nil {
+ return nil, errors.Wrap(err, "filter matches syscall")
+ }
+ }
+
+ return filter, nil
+}
+
+func matchSyscall(filter *libseccomp.ScmpFilter, call *Syscall) error {
+ if call == nil || filter == nil {
+ return errors.New("cannot use nil as syscall to block")
+ }
+
+ if call.Name == "" {
+ return errors.New("empty string is not a valid syscall")
+ }
+
+ // If we can't resolve the syscall, assume it's not supported on this kernel
+ // Ignore it, don't error out
+ callNum, err := libseccomp.GetSyscallFromName(call.Name)
+ if err != nil {
+ return nil
+ }
+
+ // Convert the call's action to the libseccomp equivalent
+ callAct, err := toAction(call.Action, call.ErrnoRet)
+ if err != nil {
+ return errors.Wrapf(err, "convert action %s", call.Action)
+ }
+
+ // Unconditional match - just add the rule
+ if len(call.Args) == 0 {
+ if err = filter.AddRule(callNum, callAct); err != nil {
+ return errors.Wrapf(err, "add seccomp filter rule for syscall %s", call.Name)
+ }
+ } else {
+ // Linux system calls can have at most 6 arguments
+ const syscallMaxArguments int = 6
+
+ // If two or more arguments have the same condition,
+ // Revert to old behavior, adding each condition as a separate rule
+ argCounts := make([]uint, syscallMaxArguments)
+ conditions := []libseccomp.ScmpCondition{}
+
+ for _, cond := range call.Args {
+ newCond, err := toCondition(cond)
+ if err != nil {
+ return errors.Wrapf(err, "create seccomp syscall condition for syscall %s", call.Name)
+ }
+
+ argCounts[cond.Index] += 1
+
+ conditions = append(conditions, newCond)
+ }
+
+ hasMultipleArgs := false
+ for _, count := range argCounts {
+ if count > 1 {
+ hasMultipleArgs = true
+ break
+ }
+ }
+
+ if hasMultipleArgs {
+ // Revert to old behavior
+ // Add each condition attached to a separate rule
+ for _, cond := range conditions {
+ condArr := []libseccomp.ScmpCondition{cond}
+
+ if err = filter.AddRuleConditional(callNum, callAct, condArr); err != nil {
+ return errors.Wrapf(err, "add seccomp rule for syscall %s", call.Name)
+ }
+ }
+ } else if err = filter.AddRuleConditional(callNum, callAct, conditions); err != nil {
+ // No conditions share same argument
+ // Use new, proper behavior
+ return errors.Wrapf(err, "add seccomp rule for syscall %s", call.Name)
+ }
+ }
+
+ return nil
+}
+
+// toAction converts an internal `Action` type to a `libseccomp.ScmpAction`
+// type.
+func toAction(act Action, errnoRet *uint) (libseccomp.ScmpAction, error) {
+ switch act {
+ case ActKill:
+ return libseccomp.ActKill, nil
+ case ActKillProcess:
+ return libseccomp.ActKillProcess, nil
+ case ActErrno:
+ if errnoRet != nil {
+ return libseccomp.ActErrno.SetReturnCode(int16(*errnoRet)), nil
+ }
+ return libseccomp.ActErrno.SetReturnCode(int16(unix.EPERM)), nil
+ case ActTrap:
+ return libseccomp.ActTrap, nil
+ case ActAllow:
+ return libseccomp.ActAllow, nil
+ case ActTrace:
+ if errnoRet != nil {
+ return libseccomp.ActTrace.SetReturnCode(int16(*errnoRet)), nil
+ }
+ return libseccomp.ActTrace.SetReturnCode(int16(unix.EPERM)), nil
+ case ActLog:
+ return libseccomp.ActLog, nil
+ default:
+ return libseccomp.ActInvalid, errors.Errorf("invalid action %s", act)
+ }
+}
+
+// toCondition converts an internal `Arg` type to a `libseccomp.ScmpCondition`
+// type.
+func toCondition(arg *Arg) (cond libseccomp.ScmpCondition, err error) {
+ if arg == nil {
+ return cond, errors.New("cannot convert nil to syscall condition")
+ }
+
+ op, err := toCompareOp(arg.Op)
+ if err != nil {
+ return cond, errors.Wrap(err, "convert compare operator")
+ }
+
+ condition, err := libseccomp.MakeCondition(
+ arg.Index, op, arg.Value, arg.ValueTwo,
+ )
+ if err != nil {
+ return cond, errors.Wrap(err, "make condition")
+ }
+
+ return condition, nil
+}
+
+// toCompareOp converts an internal `Operator` type to a
+// `libseccomp.ScmpCompareOp`.
+func toCompareOp(op Operator) (libseccomp.ScmpCompareOp, error) {
+ switch op {
+ case OpEqualTo:
+ return libseccomp.CompareEqual, nil
+ case OpNotEqual:
+ return libseccomp.CompareNotEqual, nil
+ case OpGreaterThan:
+ return libseccomp.CompareGreater, nil
+ case OpGreaterEqual:
+ return libseccomp.CompareGreaterEqual, nil
+ case OpLessThan:
+ return libseccomp.CompareLess, nil
+ case OpLessEqual:
+ return libseccomp.CompareLessOrEqual, nil
+ case OpMaskedEqual:
+ return libseccomp.CompareMaskedEqual, nil
+ default:
+ return libseccomp.CompareInvalid, errors.Errorf("invalid operator %s", op)
+ }
+}
diff --git a/vendor/github.com/containers/common/pkg/seccomp/seccomp_linux.go b/vendor/github.com/containers/common/pkg/seccomp/seccomp_linux.go
index 5655a7572..19500cc97 100644
--- a/vendor/github.com/containers/common/pkg/seccomp/seccomp_linux.go
+++ b/vendor/github.com/containers/common/pkg/seccomp/seccomp_linux.go
@@ -122,7 +122,7 @@ Loop:
}
if len(call.Excludes.Caps) > 0 {
for _, c := range call.Excludes.Caps {
- if inSlice(rs.Process.Capabilities.Bounding, c) {
+ if rs != nil && rs.Process != nil && rs.Process.Capabilities != nil && inSlice(rs.Process.Capabilities.Bounding, c) {
continue Loop
}
}
@@ -134,7 +134,7 @@ Loop:
}
if len(call.Includes.Caps) > 0 {
for _, c := range call.Includes.Caps {
- if !inSlice(rs.Process.Capabilities.Bounding, c) {
+ if rs != nil && rs.Process != nil && rs.Process.Capabilities != nil && !inSlice(rs.Process.Capabilities.Bounding, c) {
continue Loop
}
}
diff --git a/vendor/github.com/containers/common/pkg/seccomp/validate.go b/vendor/github.com/containers/common/pkg/seccomp/validate.go
new file mode 100644
index 000000000..1c5c4edc6
--- /dev/null
+++ b/vendor/github.com/containers/common/pkg/seccomp/validate.go
@@ -0,0 +1,29 @@
+// +build seccomp
+
+package seccomp
+
+import (
+ "encoding/json"
+
+ "github.com/pkg/errors"
+)
+
+// ValidateProfile does a basic validation for the provided seccomp profile
+// string.
+func ValidateProfile(content string) error {
+ profile := &Seccomp{}
+ if err := json.Unmarshal([]byte(content), &profile); err != nil {
+ return errors.Wrap(err, "decoding seccomp profile")
+ }
+
+ spec, err := setupSeccomp(profile, nil)
+ if err != nil {
+ return errors.Wrap(err, "create seccomp spec")
+ }
+
+ if _, err := BuildFilter(spec); err != nil {
+ return errors.Wrap(err, "build seccomp filter")
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/containers/common/version/version.go b/vendor/github.com/containers/common/version/version.go
index ef9a947f0..1f05ea3d9 100644
--- a/vendor/github.com/containers/common/version/version.go
+++ b/vendor/github.com/containers/common/version/version.go
@@ -1,4 +1,4 @@
package version
// Version is the version of the build.
-const Version = "0.20.4-dev"
+const Version = "0.21.0"
diff --git a/vendor/github.com/containers/image/v5/copy/copy.go b/vendor/github.com/containers/image/v5/copy/copy.go
index 7482fb458..873bdc67f 100644
--- a/vendor/github.com/containers/image/v5/copy/copy.go
+++ b/vendor/github.com/containers/image/v5/copy/copy.go
@@ -377,7 +377,7 @@ func (c *copier) copyMultipleImages(ctx context.Context, policyContext *signatur
if len(sigs) != 0 {
c.Printf("Checking if image list destination supports signatures\n")
if err := c.dest.SupportsSignatures(ctx); err != nil {
- return nil, "", errors.Wrap(err, "Can not copy signatures")
+ return nil, "", errors.Wrapf(err, "Can not copy signatures to %s", transports.ImageName(c.dest.Reference()))
}
}
canModifyManifestList := (len(sigs) == 0)
@@ -595,7 +595,7 @@ func (c *copier) copyOneImage(ctx context.Context, policyContext *signature.Poli
if len(sigs) != 0 {
c.Printf("Checking if image destination supports signatures\n")
if err := c.dest.SupportsSignatures(ctx); err != nil {
- return nil, "", "", errors.Wrap(err, "Can not copy signatures")
+ return nil, "", "", errors.Wrapf(err, "Can not copy signatures to %s", transports.ImageName(c.dest.Reference()))
}
}
diff --git a/vendor/github.com/containers/image/v5/docker/archive/dest.go b/vendor/github.com/containers/image/v5/docker/archive/dest.go
index 1cf197429..e874e02e0 100644
--- a/vendor/github.com/containers/image/v5/docker/archive/dest.go
+++ b/vendor/github.com/containers/image/v5/docker/archive/dest.go
@@ -3,9 +3,8 @@ package archive
import (
"context"
"io"
- "os"
- "github.com/containers/image/v5/docker/tarfile"
+ "github.com/containers/image/v5/docker/internal/tarfile"
"github.com/containers/image/v5/types"
"github.com/pkg/errors"
)
@@ -13,37 +12,38 @@ import (
type archiveImageDestination struct {
*tarfile.Destination // Implements most of types.ImageDestination
ref archiveReference
- writer io.Closer
+ archive *tarfile.Writer // Should only be closed if writer != nil
+ writer io.Closer // May be nil if the archive is shared
}
func newImageDestination(sys *types.SystemContext, ref archiveReference) (types.ImageDestination, error) {
- // ref.path can be either a pipe or a regular file
- // in the case of a pipe, we require that we can open it for write
- // in the case of a regular file, we don't want to overwrite any pre-existing file
- // so we check for Size() == 0 below (This is racy, but using O_EXCL would also be racy,
- // only in a different way. Either way, it’s up to the user to not have two writers to the same path.)
- fh, err := os.OpenFile(ref.path, os.O_WRONLY|os.O_CREATE, 0644)
- if err != nil {
- return nil, errors.Wrapf(err, "error opening file %q", ref.path)
+ if ref.sourceIndex != -1 {
+ return nil, errors.Errorf("Destination reference must not contain a manifest index @%d", ref.sourceIndex)
}
- fhStat, err := fh.Stat()
- if err != nil {
- return nil, errors.Wrapf(err, "error statting file %q", ref.path)
- }
+ var archive *tarfile.Writer
+ var writer io.Closer
+ if ref.archiveWriter != nil {
+ archive = ref.archiveWriter
+ writer = nil
+ } else {
+ fh, err := openArchiveForWriting(ref.path)
+ if err != nil {
+ return nil, err
+ }
- if fhStat.Mode().IsRegular() && fhStat.Size() != 0 {
- return nil, errors.New("docker-archive doesn't support modifying existing images")
+ archive = tarfile.NewWriter(fh)
+ writer = fh
}
-
- tarDest := tarfile.NewDestinationWithContext(sys, fh, ref.destinationRef)
+ tarDest := tarfile.NewDestination(sys, archive, ref.ref)
if sys != nil && sys.DockerArchiveAdditionalTags != nil {
tarDest.AddRepoTags(sys.DockerArchiveAdditionalTags)
}
return &archiveImageDestination{
Destination: tarDest,
ref: ref,
- writer: fh,
+ archive: archive,
+ writer: writer,
}, nil
}
@@ -60,7 +60,10 @@ func (d *archiveImageDestination) Reference() types.ImageReference {
// Close removes resources associated with an initialized ImageDestination, if any.
func (d *archiveImageDestination) Close() error {
- return d.writer.Close()
+ if d.writer != nil {
+ return d.writer.Close()
+ }
+ return nil
}
// Commit marks the process of storing the image as successful and asks for the image to be persisted.
@@ -68,5 +71,8 @@ func (d *archiveImageDestination) Close() error {
// - Uploaded data MAY be visible to others before Commit() is called
// - Uploaded data MAY be removed or MAY remain around if Close() is called without Commit() (i.e. rollback is allowed but not guaranteed)
func (d *archiveImageDestination) Commit(ctx context.Context, unparsedToplevel types.UnparsedImage) error {
- return d.Destination.Commit(ctx)
+ if d.writer != nil {
+ return d.archive.Close()
+ }
+ return nil
}
diff --git a/vendor/github.com/containers/image/v5/docker/archive/reader.go b/vendor/github.com/containers/image/v5/docker/archive/reader.go
new file mode 100644
index 000000000..c7bb311bc
--- /dev/null
+++ b/vendor/github.com/containers/image/v5/docker/archive/reader.go
@@ -0,0 +1,120 @@
+package archive
+
+import (
+ "github.com/containers/image/v5/docker/internal/tarfile"
+ "github.com/containers/image/v5/docker/reference"
+ "github.com/containers/image/v5/transports"
+ "github.com/containers/image/v5/types"
+ "github.com/pkg/errors"
+)
+
+// Reader manages a single Docker archive, allows listing its contents and accessing
+// individual images with less overhead than creating image references individually
+// (because the archive is, if necessary, copied or decompressed only once).
+type Reader struct {
+ path string // The original, user-specified path; not the maintained temporary file, if any
+ archive *tarfile.Reader
+}
+
+// NewReader returns a Reader for path.
+// The caller should call .Close() on the returned object.
+func NewReader(sys *types.SystemContext, path string) (*Reader, error) {
+ archive, err := tarfile.NewReaderFromFile(sys, path)
+ if err != nil {
+ return nil, err
+ }
+ return &Reader{
+ path: path,
+ archive: archive,
+ }, nil
+}
+
+// Close deletes temporary files associated with the Reader, if any.
+func (r *Reader) Close() error {
+ return r.archive.Close()
+}
+
+// NewReaderForReference creates a Reader from a Reader-independent imageReference, which must be from docker/archive.Transport,
+// and a variant of imageReference that points at the same image within the reader.
+// The caller should call .Close() on the returned Reader.
+func NewReaderForReference(sys *types.SystemContext, ref types.ImageReference) (*Reader, types.ImageReference, error) {
+ standalone, ok := ref.(archiveReference)
+ if !ok {
+ return nil, nil, errors.Errorf("Internal error: NewReaderForReference called for a non-docker/archive ImageReference %s", transports.ImageName(ref))
+ }
+ if standalone.archiveReader != nil {
+ return nil, nil, errors.Errorf("Internal error: NewReaderForReference called for a reader-bound reference %s", standalone.StringWithinTransport())
+ }
+ reader, err := NewReader(sys, standalone.path)
+ if err != nil {
+ return nil, nil, err
+ }
+ succeeded := false
+ defer func() {
+ if !succeeded {
+ reader.Close()
+ }
+ }()
+ readerRef, err := newReference(standalone.path, standalone.ref, standalone.sourceIndex, reader.archive, nil)
+ if err != nil {
+ return nil, nil, err
+ }
+ succeeded = true
+ return reader, readerRef, nil
+}
+
+// List returns the a set of references for images in the Reader,
+// grouped by the image the references point to.
+// The references are valid only until the Reader is closed.
+func (r *Reader) List() ([][]types.ImageReference, error) {
+ res := [][]types.ImageReference{}
+ for imageIndex, image := range r.archive.Manifest {
+ refs := []types.ImageReference{}
+ for _, tag := range image.RepoTags {
+ parsedTag, err := reference.ParseNormalizedNamed(tag)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Invalid tag %#v in manifest item @%d", tag, imageIndex)
+ }
+ nt, ok := parsedTag.(reference.NamedTagged)
+ if !ok {
+ return nil, errors.Errorf("Invalid tag %s (%s): does not contain a tag", tag, parsedTag.String())
+ }
+ ref, err := newReference(r.path, nt, -1, r.archive, nil)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Error creating a reference for tag %#v in manifest item @%d", tag, imageIndex)
+ }
+ refs = append(refs, ref)
+ }
+ if len(refs) == 0 {
+ ref, err := newReference(r.path, nil, imageIndex, r.archive, nil)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Error creating a reference for manifest item @%d", imageIndex)
+ }
+ refs = append(refs, ref)
+ }
+ res = append(res, refs)
+ }
+ return res, nil
+}
+
+// ManifestTagsForReference returns the set of tags “matching” ref in reader, as strings
+// (i.e. exposing the short names before normalization).
+// The function reports an error if ref does not identify a single image.
+// If ref contains a NamedTagged reference, only a single tag “matching” ref is returned;
+// If ref contains a source index, or neither a NamedTagged nor a source index, all tags
+// matching the image are returned.
+// Almost all users should use List() or ImageReference.DockerReference() instead.
+func (r *Reader) ManifestTagsForReference(ref types.ImageReference) ([]string, error) {
+ archiveRef, ok := ref.(archiveReference)
+ if !ok {
+ return nil, errors.Errorf("Internal error: ManifestTagsForReference called for a non-docker/archive ImageReference %s", transports.ImageName(ref))
+ }
+ manifestItem, tagIndex, err := r.archive.ChooseManifestItem(archiveRef.ref, archiveRef.sourceIndex)
+ if err != nil {
+ return nil, err
+ }
+ if tagIndex != -1 {
+ return []string{manifestItem.RepoTags[tagIndex]}, nil
+ }
+ return manifestItem.RepoTags, nil
+}
diff --git a/vendor/github.com/containers/image/v5/docker/archive/src.go b/vendor/github.com/containers/image/v5/docker/archive/src.go
index 6a628508d..7acca210e 100644
--- a/vendor/github.com/containers/image/v5/docker/archive/src.go
+++ b/vendor/github.com/containers/image/v5/docker/archive/src.go
@@ -3,9 +3,8 @@ package archive
import (
"context"
- "github.com/containers/image/v5/docker/tarfile"
+ "github.com/containers/image/v5/docker/internal/tarfile"
"github.com/containers/image/v5/types"
- "github.com/sirupsen/logrus"
)
type archiveImageSource struct {
@@ -16,13 +15,20 @@ type archiveImageSource struct {
// newImageSource returns a types.ImageSource for the specified image reference.
// The caller must call .Close() on the returned ImageSource.
func newImageSource(ctx context.Context, sys *types.SystemContext, ref archiveReference) (types.ImageSource, error) {
- if ref.destinationRef != nil {
- logrus.Warnf("docker-archive: references are not supported for sources (ignoring)")
- }
- src, err := tarfile.NewSourceFromFileWithContext(sys, ref.path)
- if err != nil {
- return nil, err
+ var archive *tarfile.Reader
+ var closeArchive bool
+ if ref.archiveReader != nil {
+ archive = ref.archiveReader
+ closeArchive = false
+ } else {
+ a, err := tarfile.NewReaderFromFile(sys, ref.path)
+ if err != nil {
+ return nil, err
+ }
+ archive = a
+ closeArchive = true
}
+ src := tarfile.NewSource(archive, closeArchive, ref.ref, ref.sourceIndex)
return &archiveImageSource{
Source: src,
ref: ref,
diff --git a/vendor/github.com/containers/image/v5/docker/archive/transport.go b/vendor/github.com/containers/image/v5/docker/archive/transport.go
index 26bc687e0..ff9e27482 100644
--- a/vendor/github.com/containers/image/v5/docker/archive/transport.go
+++ b/vendor/github.com/containers/image/v5/docker/archive/transport.go
@@ -3,8 +3,10 @@ package archive
import (
"context"
"fmt"
+ "strconv"
"strings"
+ "github.com/containers/image/v5/docker/internal/tarfile"
"github.com/containers/image/v5/docker/reference"
ctrImage "github.com/containers/image/v5/image"
"github.com/containers/image/v5/transports"
@@ -42,9 +44,16 @@ func (t archiveTransport) ValidatePolicyConfigurationScope(scope string) error {
// archiveReference is an ImageReference for Docker images.
type archiveReference struct {
path string
- // only used for destinations,
- // archiveReference.destinationRef is optional and can be nil for destinations as well.
- destinationRef reference.NamedTagged
+ // May be nil to read the only image in an archive, or to create an untagged image.
+ ref reference.NamedTagged
+ // If not -1, a zero-based index of the image in the manifest. Valid only for sources.
+ // Must not be set if ref is set.
+ sourceIndex int
+ // If not nil, must have been created from path (but archiveReader.path may point at a temporary
+ // file, not necesarily path precisely).
+ archiveReader *tarfile.Reader
+ // If not nil, must have been created for path
+ archiveWriter *tarfile.Writer
}
// ParseReference converts a string, which should not start with the ImageTransport.Name prefix, into an Docker ImageReference.
@@ -55,37 +64,69 @@ func ParseReference(refString string) (types.ImageReference, error) {
parts := strings.SplitN(refString, ":", 2)
path := parts[0]
- var destinationRef reference.NamedTagged
+ var nt reference.NamedTagged
+ sourceIndex := -1
- // A :tag was specified, which is only necessary for destinations.
if len(parts) == 2 {
- ref, err := reference.ParseNormalizedNamed(parts[1])
- if err != nil {
- return nil, errors.Wrapf(err, "docker-archive parsing reference")
+ // A :tag or :@index was specified.
+ if len(parts[1]) > 0 && parts[1][0] == '@' {
+ i, err := strconv.Atoi(parts[1][1:])
+ if err != nil {
+ return nil, errors.Wrapf(err, "Invalid source index %s", parts[1])
+ }
+ if i < 0 {
+ return nil, errors.Errorf("Invalid source index @%d: must not be negative", i)
+ }
+ sourceIndex = i
+ } else {
+ ref, err := reference.ParseNormalizedNamed(parts[1])
+ if err != nil {
+ return nil, errors.Wrapf(err, "docker-archive parsing reference")
+ }
+ ref = reference.TagNameOnly(ref)
+ refTagged, isTagged := ref.(reference.NamedTagged)
+ if !isTagged { // If ref contains a digest, TagNameOnly does not change it
+ return nil, errors.Errorf("reference does not include a tag: %s", ref.String())
+ }
+ nt = refTagged
}
- ref = reference.TagNameOnly(ref)
- refTagged, isTagged := ref.(reference.NamedTagged)
- if !isTagged {
- // Really shouldn't be hit...
- return nil, errors.Errorf("internal error: reference is not tagged even after reference.TagNameOnly: %s", refString)
- }
- destinationRef = refTagged
}
- return NewReference(path, destinationRef)
+ return newReference(path, nt, sourceIndex, nil, nil)
+}
+
+// NewReference returns a Docker archive reference for a path and an optional reference.
+func NewReference(path string, ref reference.NamedTagged) (types.ImageReference, error) {
+ return newReference(path, ref, -1, nil, nil)
}
-// NewReference rethrns a Docker archive reference for a path and an optional destination reference.
-func NewReference(path string, destinationRef reference.NamedTagged) (types.ImageReference, error) {
+// NewIndexReference returns a Docker archive reference for a path and a zero-based source manifest index.
+func NewIndexReference(path string, sourceIndex int) (types.ImageReference, error) {
+ return newReference(path, nil, sourceIndex, nil, nil)
+}
+
+// newReference returns a docker archive reference for a path, an optional reference or sourceIndex,
+// and optionally a tarfile.Reader and/or a tarfile.Writer matching path.
+func newReference(path string, ref reference.NamedTagged, sourceIndex int,
+ archiveReader *tarfile.Reader, archiveWriter *tarfile.Writer) (types.ImageReference, error) {
if strings.Contains(path, ":") {
return nil, errors.Errorf("Invalid docker-archive: reference: colon in path %q is not supported", path)
}
- if _, isDigest := destinationRef.(reference.Canonical); isDigest {
- return nil, errors.Errorf("docker-archive doesn't support digest references: %s", destinationRef.String())
+ if ref != nil && sourceIndex != -1 {
+ return nil, errors.Errorf("Invalid docker-archive: reference: cannot use both a tag and a source index")
+ }
+ if _, isDigest := ref.(reference.Canonical); isDigest {
+ return nil, errors.Errorf("docker-archive doesn't support digest references: %s", ref.String())
+ }
+ if sourceIndex != -1 && sourceIndex < 0 {
+ return nil, errors.Errorf("Invalid docker-archive: reference: index @%d must not be negative", sourceIndex)
}
return archiveReference{
- path: path,
- destinationRef: destinationRef,
+ path: path,
+ ref: ref,
+ sourceIndex: sourceIndex,
+ archiveReader: archiveReader,
+ archiveWriter: archiveWriter,
}, nil
}
@@ -99,17 +140,21 @@ func (ref archiveReference) Transport() types.ImageTransport {
// e.g. default attribute values omitted by the user may be filled in in the return value, or vice versa.
// WARNING: Do not use the return value in the UI to describe an image, it does not contain the Transport().Name() prefix.
func (ref archiveReference) StringWithinTransport() string {
- if ref.destinationRef == nil {
+ switch {
+ case ref.ref != nil:
+ return fmt.Sprintf("%s:%s", ref.path, ref.ref.String())
+ case ref.sourceIndex != -1:
+ return fmt.Sprintf("%s:@%d", ref.path, ref.sourceIndex)
+ default:
return ref.path
}
- return fmt.Sprintf("%s:%s", ref.path, ref.destinationRef.String())
}
// DockerReference returns a Docker reference associated with this reference
// (fully explicit, i.e. !reference.IsNameOnly, but reflecting user intent,
// not e.g. after redirect or alias processing), or nil if unknown/not applicable.
func (ref archiveReference) DockerReference() reference.Named {
- return ref.destinationRef
+ return ref.ref
}
// PolicyConfigurationIdentity returns a string representation of the reference, suitable for policy lookup.
diff --git a/vendor/github.com/containers/image/v5/docker/archive/writer.go b/vendor/github.com/containers/image/v5/docker/archive/writer.go
new file mode 100644
index 000000000..afac2aaee
--- /dev/null
+++ b/vendor/github.com/containers/image/v5/docker/archive/writer.go
@@ -0,0 +1,82 @@
+package archive
+
+import (
+ "io"
+ "os"
+
+ "github.com/containers/image/v5/docker/internal/tarfile"
+ "github.com/containers/image/v5/docker/reference"
+ "github.com/containers/image/v5/types"
+ "github.com/pkg/errors"
+)
+
+// Writer manages a single in-progress Docker archive and allows adding images to it.
+type Writer struct {
+ path string // The original, user-specified path; not the maintained temporary file, if any
+ archive *tarfile.Writer
+ writer io.Closer
+}
+
+// NewWriter returns a Writer for path.
+// The caller should call .Close() on the returned object.
+func NewWriter(sys *types.SystemContext, path string) (*Writer, error) {
+ fh, err := openArchiveForWriting(path)
+ if err != nil {
+ return nil, err
+ }
+ archive := tarfile.NewWriter(fh)
+
+ return &Writer{
+ path: path,
+ archive: archive,
+ writer: fh,
+ }, nil
+}
+
+// Close writes all outstanding data about images to the archive, and
+// releases state associated with the Writer, if any.
+// No more images can be added after this is called.
+func (w *Writer) Close() error {
+ err := w.archive.Close()
+ if err2 := w.writer.Close(); err2 != nil && err == nil {
+ err = err2
+ }
+ return err
+}
+
+// NewReference returns an ImageReference that allows adding an image to Writer,
+// with an optional reference.
+func (w *Writer) NewReference(destinationRef reference.NamedTagged) (types.ImageReference, error) {
+ return newReference(w.path, destinationRef, -1, nil, w.archive)
+}
+
+// openArchiveForWriting opens path for writing a tar archive,
+// making a few sanity checks.
+func openArchiveForWriting(path string) (*os.File, error) {
+ // path can be either a pipe or a regular file
+ // in the case of a pipe, we require that we can open it for write
+ // in the case of a regular file, we don't want to overwrite any pre-existing file
+ // so we check for Size() == 0 below (This is racy, but using O_EXCL would also be racy,
+ // only in a different way. Either way, it’s up to the user to not have two writers to the same path.)
+ fh, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error opening file %q", path)
+ }
+ succeeded := false
+ defer func() {
+ if !succeeded {
+ fh.Close()
+ }
+ }()
+ fhStat, err := fh.Stat()
+ if err != nil {
+ return nil, errors.Wrapf(err, "error statting file %q", path)
+ }
+
+ if fhStat.Mode().IsRegular() && fhStat.Size() != 0 {
+ return nil, errors.New("docker-archive doesn't support modifying existing images")
+ }
+
+ succeeded = true
+ return fh, nil
+}
diff --git a/vendor/github.com/containers/image/v5/docker/daemon/daemon_dest.go b/vendor/github.com/containers/image/v5/docker/daemon/daemon_dest.go
index c6afd4bde..88609b3dc 100644
--- a/vendor/github.com/containers/image/v5/docker/daemon/daemon_dest.go
+++ b/vendor/github.com/containers/image/v5/docker/daemon/daemon_dest.go
@@ -4,8 +4,8 @@ import (
"context"
"io"
+ "github.com/containers/image/v5/docker/internal/tarfile"
"github.com/containers/image/v5/docker/reference"
- "github.com/containers/image/v5/docker/tarfile"
"github.com/containers/image/v5/types"
"github.com/docker/docker/client"
"github.com/pkg/errors"
@@ -16,6 +16,7 @@ type daemonImageDestination struct {
ref daemonReference
mustMatchRuntimeOS bool
*tarfile.Destination // Implements most of types.ImageDestination
+ archive *tarfile.Writer
// For talking to imageLoadGoroutine
goroutineCancel context.CancelFunc
statusChannel <-chan error
@@ -45,6 +46,7 @@ func newImageDestination(ctx context.Context, sys *types.SystemContext, ref daem
}
reader, writer := io.Pipe()
+ archive := tarfile.NewWriter(writer)
// Commit() may never be called, so we may never read from this channel; so, make this buffered to allow imageLoadGoroutine to write status and terminate even if we never read it.
statusChannel := make(chan error, 1)
@@ -54,7 +56,8 @@ func newImageDestination(ctx context.Context, sys *types.SystemContext, ref daem
return &daemonImageDestination{
ref: ref,
mustMatchRuntimeOS: mustMatchRuntimeOS,
- Destination: tarfile.NewDestinationWithContext(sys, writer, namedTaggedRef),
+ Destination: tarfile.NewDestination(sys, archive, namedTaggedRef),
+ archive: archive,
goroutineCancel: goroutineCancel,
statusChannel: statusChannel,
writer: writer,
@@ -130,7 +133,7 @@ func (d *daemonImageDestination) Reference() types.ImageReference {
// - Uploaded data MAY be removed or MAY remain around if Close() is called without Commit() (i.e. rollback is allowed but not guaranteed)
func (d *daemonImageDestination) Commit(ctx context.Context, unparsedToplevel types.UnparsedImage) error {
logrus.Debugf("docker-daemon: Closing tar stream")
- if err := d.Destination.Commit(ctx); err != nil {
+ if err := d.archive.Close(); err != nil {
return err
}
if err := d.writer.Close(); err != nil {
diff --git a/vendor/github.com/containers/image/v5/docker/daemon/daemon_src.go b/vendor/github.com/containers/image/v5/docker/daemon/daemon_src.go
index 1827f811d..74a678817 100644
--- a/vendor/github.com/containers/image/v5/docker/daemon/daemon_src.go
+++ b/vendor/github.com/containers/image/v5/docker/daemon/daemon_src.go
@@ -3,7 +3,7 @@ package daemon
import (
"context"
- "github.com/containers/image/v5/docker/tarfile"
+ "github.com/containers/image/v5/docker/internal/tarfile"
"github.com/containers/image/v5/types"
"github.com/pkg/errors"
)
@@ -35,10 +35,11 @@ func newImageSource(ctx context.Context, sys *types.SystemContext, ref daemonRef
}
defer inputStream.Close()
- src, err := tarfile.NewSourceFromStreamWithSystemContext(sys, inputStream)
+ archive, err := tarfile.NewReaderFromStream(sys, inputStream)
if err != nil {
return nil, err
}
+ src := tarfile.NewSource(archive, true, nil, -1)
return &daemonImageSource{
ref: ref,
Source: src,
diff --git a/vendor/github.com/containers/image/v5/docker/docker_image_dest.go b/vendor/github.com/containers/image/v5/docker/docker_image_dest.go
index 979100ee3..576dec495 100644
--- a/vendor/github.com/containers/image/v5/docker/docker_image_dest.go
+++ b/vendor/github.com/containers/image/v5/docker/docker_image_dest.go
@@ -22,7 +22,6 @@ import (
"github.com/containers/image/v5/types"
"github.com/docker/distribution/registry/api/errcode"
v2 "github.com/docker/distribution/registry/api/v2"
- "github.com/docker/distribution/registry/client"
"github.com/opencontainers/go-digest"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
@@ -154,7 +153,7 @@ func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader,
defer res.Body.Close()
if res.StatusCode != http.StatusAccepted {
logrus.Debugf("Error initiating layer upload, response %#v", *res)
- return types.BlobInfo{}, errors.Wrapf(client.HandleErrorResponse(res), "Error initiating layer upload to %s in %s", uploadPath, d.c.registry)
+ return types.BlobInfo{}, errors.Wrapf(registryHTTPResponseToError(res), "Error initiating layer upload to %s in %s", uploadPath, d.c.registry)
}
uploadLocation, err := res.Location()
if err != nil {
@@ -175,7 +174,7 @@ func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader,
}
defer res.Body.Close()
if !successStatus(res.StatusCode) {
- return nil, errors.Wrapf(client.HandleErrorResponse(res), "Error uploading layer chunked")
+ return nil, errors.Wrapf(registryHTTPResponseToError(res), "Error uploading layer chunked")
}
uploadLocation, err := res.Location()
if err != nil {
@@ -201,7 +200,7 @@ func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader,
defer res.Body.Close()
if res.StatusCode != http.StatusCreated {
logrus.Debugf("Error uploading layer, response %#v", *res)
- return types.BlobInfo{}, errors.Wrapf(client.HandleErrorResponse(res), "Error uploading layer to %s", uploadLocation)
+ return types.BlobInfo{}, errors.Wrapf(registryHTTPResponseToError(res), "Error uploading layer to %s", uploadLocation)
}
logrus.Debugf("Upload of layer %s complete", computedDigest)
@@ -226,7 +225,7 @@ func (d *dockerImageDestination) blobExists(ctx context.Context, repo reference.
return true, getBlobSize(res), nil
case http.StatusUnauthorized:
logrus.Debugf("... not authorized")
- return false, -1, errors.Wrapf(client.HandleErrorResponse(res), "Error checking whether a blob %s exists in %s", digest, repo.Name())
+ return false, -1, errors.Wrapf(registryHTTPResponseToError(res), "Error checking whether a blob %s exists in %s", digest, repo.Name())
case http.StatusNotFound:
logrus.Debugf("... not present")
return false, -1, nil
@@ -277,7 +276,7 @@ func (d *dockerImageDestination) mountBlob(ctx context.Context, srcRepo referenc
return fmt.Errorf("Mounting %s from %s to %s started an upload instead", srcDigest, srcRepo.Name(), d.ref.ref.Name())
default:
logrus.Debugf("Error mounting, response %#v", *res)
- return errors.Wrapf(client.HandleErrorResponse(res), "Error mounting %s from %s to %s", srcDigest, srcRepo.Name(), d.ref.ref.Name())
+ return errors.Wrapf(registryHTTPResponseToError(res), "Error mounting %s from %s to %s", srcDigest, srcRepo.Name(), d.ref.ref.Name())
}
}
@@ -414,7 +413,7 @@ func (d *dockerImageDestination) PutManifest(ctx context.Context, m []byte, inst
}
defer res.Body.Close()
if !successStatus(res.StatusCode) {
- err = errors.Wrapf(client.HandleErrorResponse(res), "Error uploading manifest %s to %s", refTail, d.ref.ref.Name())
+ err = errors.Wrapf(registryHTTPResponseToError(res), "Error uploading manifest %s to %s", refTail, d.ref.ref.Name())
if isManifestInvalidError(errors.Cause(err)) {
err = types.ManifestTypeRejectedError{Err: err}
}
@@ -641,7 +640,7 @@ sigExists:
logrus.Debugf("Error body %s", string(body))
}
logrus.Debugf("Error uploading signature, status %d, %#v", res.StatusCode, res)
- return errors.Wrapf(client.HandleErrorResponse(res), "Error uploading signature to %s in %s", path, d.c.registry)
+ return errors.Wrapf(registryHTTPResponseToError(res), "Error uploading signature to %s in %s", path, d.c.registry)
}
}
diff --git a/vendor/github.com/containers/image/v5/docker/docker_image_src.go b/vendor/github.com/containers/image/v5/docker/docker_image_src.go
index 55eb38824..4d2a9ed6c 100644
--- a/vendor/github.com/containers/image/v5/docker/docker_image_src.go
+++ b/vendor/github.com/containers/image/v5/docker/docker_image_src.go
@@ -17,7 +17,6 @@ import (
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/pkg/sysregistriesv2"
"github.com/containers/image/v5/types"
- "github.com/docker/distribution/registry/client"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -193,7 +192,7 @@ func (s *dockerImageSource) fetchManifest(ctx context.Context, tagOrDigest strin
logrus.Debugf("Content-Type from manifest GET is %q", res.Header.Get("Content-Type"))
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
- return nil, "", errors.Wrapf(client.HandleErrorResponse(res), "Error reading manifest %s in %s", tagOrDigest, s.physicalRef.ref.Name())
+ return nil, "", errors.Wrapf(registryHTTPResponseToError(res), "Error reading manifest %s in %s", tagOrDigest, s.physicalRef.ref.Name())
}
manblob, err := iolimits.ReadAtMost(res.Body, iolimits.MaxManifestBodySize)
@@ -235,6 +234,9 @@ func (s *dockerImageSource) getExternalBlob(ctx context.Context, urls []string)
resp *http.Response
err error
)
+ if len(urls) == 0 {
+ return nil, 0, errors.New("internal error: getExternalBlob called with no URLs")
+ }
for _, url := range urls {
resp, err = s.c.makeRequestToResolvedURL(ctx, "GET", url, nil, nil, -1, noAuth, nil)
if err == nil {
diff --git a/vendor/github.com/containers/image/v5/docker/errors.go b/vendor/github.com/containers/image/v5/docker/errors.go
index f626cc7da..5b5008af7 100644
--- a/vendor/github.com/containers/image/v5/docker/errors.go
+++ b/vendor/github.com/containers/image/v5/docker/errors.go
@@ -44,3 +44,17 @@ func httpResponseToError(res *http.Response, context string) error {
return perrors.Errorf("%sinvalid status code from registry %d (%s)", context, res.StatusCode, http.StatusText(res.StatusCode))
}
}
+
+// registryHTTPResponseToError creates a Go error from an HTTP error response of a docker/distribution
+// registry
+func registryHTTPResponseToError(res *http.Response) error {
+ errResponse := client.HandleErrorResponse(res)
+ if e, ok := perrors.Cause(errResponse).(*client.UnexpectedHTTPResponseError); ok {
+ response := string(e.Response)
+ if len(response) > 50 {
+ response = response[:50] + "..."
+ }
+ errResponse = fmt.Errorf("StatusCode: %d, %s", e.StatusCode, response)
+ }
+ return errResponse
+}
diff --git a/vendor/github.com/containers/image/v5/docker/internal/tarfile/dest.go b/vendor/github.com/containers/image/v5/docker/internal/tarfile/dest.go
new file mode 100644
index 000000000..8c38094cf
--- /dev/null
+++ b/vendor/github.com/containers/image/v5/docker/internal/tarfile/dest.go
@@ -0,0 +1,217 @@
+package tarfile
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "io"
+ "io/ioutil"
+ "os"
+
+ "github.com/containers/image/v5/docker/reference"
+ "github.com/containers/image/v5/internal/iolimits"
+ "github.com/containers/image/v5/internal/tmpdir"
+ "github.com/containers/image/v5/manifest"
+ "github.com/containers/image/v5/types"
+ "github.com/opencontainers/go-digest"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+// Destination is a partial implementation of types.ImageDestination for writing to an io.Writer.
+type Destination struct {
+ archive *Writer
+ repoTags []reference.NamedTagged
+ // Other state.
+ config []byte
+ sysCtx *types.SystemContext
+}
+
+// NewDestination returns a tarfile.Destination adding images to the specified Writer.
+func NewDestination(sys *types.SystemContext, archive *Writer, ref reference.NamedTagged) *Destination {
+ repoTags := []reference.NamedTagged{}
+ if ref != nil {
+ repoTags = append(repoTags, ref)
+ }
+ return &Destination{
+ archive: archive,
+ repoTags: repoTags,
+ sysCtx: sys,
+ }
+}
+
+// AddRepoTags adds the specified tags to the destination's repoTags.
+func (d *Destination) AddRepoTags(tags []reference.NamedTagged) {
+ d.repoTags = append(d.repoTags, tags...)
+}
+
+// SupportedManifestMIMETypes tells which manifest mime types the destination supports
+// If an empty slice or nil it's returned, then any mime type can be tried to upload
+func (d *Destination) SupportedManifestMIMETypes() []string {
+ return []string{
+ manifest.DockerV2Schema2MediaType, // We rely on the types.Image.UpdatedImage schema conversion capabilities.
+ }
+}
+
+// SupportsSignatures returns an error (to be displayed to the user) if the destination certainly can't store signatures.
+// Note: It is still possible for PutSignatures to fail if SupportsSignatures returns nil.
+func (d *Destination) SupportsSignatures(ctx context.Context) error {
+ return errors.Errorf("Storing signatures for docker tar files is not supported")
+}
+
+// AcceptsForeignLayerURLs returns false iff foreign layers in manifest should be actually
+// uploaded to the image destination, true otherwise.
+func (d *Destination) AcceptsForeignLayerURLs() bool {
+ return false
+}
+
+// MustMatchRuntimeOS returns true iff the destination can store only images targeted for the current runtime architecture and OS. False otherwise.
+func (d *Destination) MustMatchRuntimeOS() bool {
+ return false
+}
+
+// IgnoresEmbeddedDockerReference returns true iff the destination does not care about Image.EmbeddedDockerReferenceConflicts(),
+// and would prefer to receive an unmodified manifest instead of one modified for the destination.
+// Does not make a difference if Reference().DockerReference() is nil.
+func (d *Destination) IgnoresEmbeddedDockerReference() bool {
+ return false // N/A, we only accept schema2 images where EmbeddedDockerReferenceConflicts() is always false.
+}
+
+// HasThreadSafePutBlob indicates whether PutBlob can be executed concurrently.
+func (d *Destination) HasThreadSafePutBlob() bool {
+ // The code _is_ actually thread-safe, but apart from computing sizes/digests of layers where
+ // this is unknown in advance, the actual copy is serialized by d.archive, so there probably isn’t
+ // much benefit from concurrency, mostly just extra CPU, memory and I/O contention.
+ return false
+}
+
+// PutBlob writes contents of stream and returns data representing the result (with all data filled in).
+// inputInfo.Digest can be optionally provided if known; it is not mandatory for the implementation to verify it.
+// inputInfo.Size is the expected length of stream, if known.
+// May update cache.
+// WARNING: The contents of stream are being verified on the fly. Until stream.Read() returns io.EOF, the contents of the data SHOULD NOT be available
+// to any other readers for download using the supplied digest.
+// If stream.Read() at any time, ESPECIALLY at end of input, returns an error, PutBlob MUST 1) fail, and 2) delete any data stored so far.
+func (d *Destination) PutBlob(ctx context.Context, stream io.Reader, inputInfo types.BlobInfo, cache types.BlobInfoCache, isConfig bool) (types.BlobInfo, error) {
+ // Ouch, we need to stream the blob into a temporary file just to determine the size.
+ // When the layer is decompressed, we also have to generate the digest on uncompressed datas.
+ if inputInfo.Size == -1 || inputInfo.Digest.String() == "" {
+ logrus.Debugf("docker tarfile: input with unknown size, streaming to disk first ...")
+ streamCopy, err := ioutil.TempFile(tmpdir.TemporaryDirectoryForBigFiles(d.sysCtx), "docker-tarfile-blob")
+ if err != nil {
+ return types.BlobInfo{}, err
+ }
+ defer os.Remove(streamCopy.Name())
+ defer streamCopy.Close()
+
+ digester := digest.Canonical.Digester()
+ tee := io.TeeReader(stream, digester.Hash())
+ // TODO: This can take quite some time, and should ideally be cancellable using ctx.Done().
+ size, err := io.Copy(streamCopy, tee)
+ if err != nil {
+ return types.BlobInfo{}, err
+ }
+ _, err = streamCopy.Seek(0, io.SeekStart)
+ if err != nil {
+ return types.BlobInfo{}, err
+ }
+ inputInfo.Size = size // inputInfo is a struct, so we are only modifying our copy.
+ if inputInfo.Digest == "" {
+ inputInfo.Digest = digester.Digest()
+ }
+ stream = streamCopy
+ logrus.Debugf("... streaming done")
+ }
+
+ if err := d.archive.lock(); err != nil {
+ return types.BlobInfo{}, err
+ }
+ defer d.archive.unlock()
+
+ // Maybe the blob has been already sent
+ ok, reusedInfo, err := d.archive.tryReusingBlobLocked(inputInfo)
+ if err != nil {
+ return types.BlobInfo{}, err
+ }
+ if ok {
+ return reusedInfo, nil
+ }
+
+ if isConfig {
+ buf, err := iolimits.ReadAtMost(stream, iolimits.MaxConfigBodySize)
+ if err != nil {
+ return types.BlobInfo{}, errors.Wrap(err, "Error reading Config file stream")
+ }
+ d.config = buf
+ if err := d.archive.sendFileLocked(d.archive.configPath(inputInfo.Digest), inputInfo.Size, bytes.NewReader(buf)); err != nil {
+ return types.BlobInfo{}, errors.Wrap(err, "Error writing Config file")
+ }
+ } else {
+ if err := d.archive.sendFileLocked(d.archive.physicalLayerPath(inputInfo.Digest), inputInfo.Size, stream); err != nil {
+ return types.BlobInfo{}, err
+ }
+ }
+ d.archive.recordBlobLocked(types.BlobInfo{Digest: inputInfo.Digest, Size: inputInfo.Size})
+ return types.BlobInfo{Digest: inputInfo.Digest, Size: inputInfo.Size}, nil
+}
+
+// TryReusingBlob checks whether the transport already contains, or can efficiently reuse, a blob, and if so, applies it to the current destination
+// (e.g. if the blob is a filesystem layer, this signifies that the changes it describes need to be applied again when composing a filesystem tree).
+// info.Digest must not be empty.
+// If canSubstitute, TryReusingBlob can use an equivalent equivalent of the desired blob; in that case the returned info may not match the input.
+// If the blob has been succesfully reused, returns (true, info, nil); info must contain at least a digest and size.
+// If the transport can not reuse the requested blob, TryReusingBlob returns (false, {}, nil); it returns a non-nil error only on an unexpected failure.
+// May use and/or update cache.
+func (d *Destination) TryReusingBlob(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache, canSubstitute bool) (bool, types.BlobInfo, error) {
+ if err := d.archive.lock(); err != nil {
+ return false, types.BlobInfo{}, err
+ }
+ defer d.archive.unlock()
+
+ return d.archive.tryReusingBlobLocked(info)
+}
+
+// PutManifest writes manifest to the destination.
+// The instanceDigest value is expected to always be nil, because this transport does not support manifest lists, so
+// there can be no secondary manifests.
+// FIXME? This should also receive a MIME type if known, to differentiate between schema versions.
+// If the destination is in principle available, refuses this manifest type (e.g. it does not recognize the schema),
+// but may accept a different manifest type, the returned error must be an ManifestTypeRejectedError.
+func (d *Destination) PutManifest(ctx context.Context, m []byte, instanceDigest *digest.Digest) error {
+ if instanceDigest != nil {
+ return errors.New(`Manifest lists are not supported for docker tar files`)
+ }
+ // We do not bother with types.ManifestTypeRejectedError; our .SupportedManifestMIMETypes() above is already providing only one alternative,
+ // so the caller trying a different manifest kind would be pointless.
+ var man manifest.Schema2
+ if err := json.Unmarshal(m, &man); err != nil {
+ return errors.Wrap(err, "Error parsing manifest")
+ }
+ if man.SchemaVersion != 2 || man.MediaType != manifest.DockerV2Schema2MediaType {
+ return errors.Errorf("Unsupported manifest type, need a Docker schema 2 manifest")
+ }
+
+ if err := d.archive.lock(); err != nil {
+ return err
+ }
+ defer d.archive.unlock()
+
+ if err := d.archive.writeLegacyMetadataLocked(man.LayersDescriptors, d.config, d.repoTags); err != nil {
+ return err
+ }
+
+ return d.archive.ensureManifestItemLocked(man.LayersDescriptors, man.ConfigDescriptor.Digest, d.repoTags)
+}
+
+// PutSignatures would add the given signatures to the docker tarfile (currently not supported).
+// The instanceDigest value is expected to always be nil, because this transport does not support manifest lists, so
+// there can be no secondary manifests. MUST be called after PutManifest (signatures reference manifest contents).
+func (d *Destination) PutSignatures(ctx context.Context, signatures [][]byte, instanceDigest *digest.Digest) error {
+ if instanceDigest != nil {
+ return errors.Errorf(`Manifest lists are not supported for docker tar files`)
+ }
+ if len(signatures) != 0 {
+ return errors.Errorf("Storing signatures for docker tar files is not supported")
+ }
+ return nil
+}
diff --git a/vendor/github.com/containers/image/v5/docker/internal/tarfile/reader.go b/vendor/github.com/containers/image/v5/docker/internal/tarfile/reader.go
new file mode 100644
index 000000000..83de0c520
--- /dev/null
+++ b/vendor/github.com/containers/image/v5/docker/internal/tarfile/reader.go
@@ -0,0 +1,269 @@
+package tarfile
+
+import (
+ "archive/tar"
+ "encoding/json"
+ "io"
+ "io/ioutil"
+ "os"
+ "path"
+
+ "github.com/containers/image/v5/docker/reference"
+ "github.com/containers/image/v5/internal/iolimits"
+ "github.com/containers/image/v5/internal/tmpdir"
+ "github.com/containers/image/v5/pkg/compression"
+ "github.com/containers/image/v5/types"
+ "github.com/pkg/errors"
+)
+
+// Reader is a ((docker save)-formatted) tar archive that allows random access to any component.
+type Reader struct {
+ // None of the fields below are modified after the archive is created, until .Close();
+ // this allows concurrent readers of the same archive.
+ path string // "" if the archive has already been closed.
+ removeOnClose bool // Remove file on close if true
+ Manifest []ManifestItem // Guaranteed to exist after the archive is created.
+}
+
+// NewReaderFromFile returns a Reader for the specified path.
+// The caller should call .Close() on the returned archive when done.
+func NewReaderFromFile(sys *types.SystemContext, path string) (*Reader, error) {
+ file, err := os.Open(path)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error opening file %q", path)
+ }
+ defer file.Close()
+
+ // If the file is already not compressed we can just return the file itself
+ // as a source. Otherwise we pass the stream to NewReaderFromStream.
+ stream, isCompressed, err := compression.AutoDecompress(file)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Error detecting compression for file %q", path)
+ }
+ defer stream.Close()
+ if !isCompressed {
+ return newReader(path, false)
+ }
+ return NewReaderFromStream(sys, stream)
+}
+
+// NewReaderFromStream returns a Reader for the specified inputStream,
+// which can be either compressed or uncompressed. The caller can close the
+// inputStream immediately after NewReaderFromFile returns.
+// The caller should call .Close() on the returned archive when done.
+func NewReaderFromStream(sys *types.SystemContext, inputStream io.Reader) (*Reader, error) {
+ // Save inputStream to a temporary file
+ tarCopyFile, err := ioutil.TempFile(tmpdir.TemporaryDirectoryForBigFiles(sys), "docker-tar")
+ if err != nil {
+ return nil, errors.Wrap(err, "error creating temporary file")
+ }
+ defer tarCopyFile.Close()
+
+ succeeded := false
+ defer func() {
+ if !succeeded {
+ os.Remove(tarCopyFile.Name())
+ }
+ }()
+
+ // In order to be compatible with docker-load, we need to support
+ // auto-decompression (it's also a nice quality-of-life thing to avoid
+ // giving users really confusing "invalid tar header" errors).
+ uncompressedStream, _, err := compression.AutoDecompress(inputStream)
+ if err != nil {
+ return nil, errors.Wrap(err, "Error auto-decompressing input")
+ }
+ defer uncompressedStream.Close()
+
+ // Copy the plain archive to the temporary file.
+ //
+ // TODO: This can take quite some time, and should ideally be cancellable
+ // using a context.Context.
+ if _, err := io.Copy(tarCopyFile, uncompressedStream); err != nil {
+ return nil, errors.Wrapf(err, "error copying contents to temporary file %q", tarCopyFile.Name())
+ }
+ succeeded = true
+
+ return newReader(tarCopyFile.Name(), true)
+}
+
+// newReader creates a Reader for the specified path and removeOnClose flag.
+// The caller should call .Close() on the returned archive when done.
+func newReader(path string, removeOnClose bool) (*Reader, error) {
+ // This is a valid enough archive, except Manifest is not yet filled.
+ r := Reader{
+ path: path,
+ removeOnClose: removeOnClose,
+ }
+ succeeded := false
+ defer func() {
+ if !succeeded {
+ r.Close()
+ }
+ }()
+
+ // We initialize Manifest immediately when constructing the Reader instead
+ // of later on-demand because every caller will need the data, and because doing it now
+ // removes the need to synchronize the access/creation of the data if the archive is later
+ // used from multiple goroutines to access different images.
+
+ // FIXME? Do we need to deal with the legacy format?
+ bytes, err := r.readTarComponent(manifestFileName, iolimits.MaxTarFileManifestSize)
+ if err != nil {
+ return nil, err
+ }
+ if err := json.Unmarshal(bytes, &r.Manifest); err != nil {
+ return nil, errors.Wrap(err, "Error decoding tar manifest.json")
+ }
+
+ succeeded = true
+ return &r, nil
+}
+
+// Close removes resources associated with an initialized Reader, if any.
+func (r *Reader) Close() error {
+ path := r.path
+ r.path = "" // Mark the archive as closed
+ if r.removeOnClose {
+ return os.Remove(path)
+ }
+ return nil
+}
+
+// ChooseManifestItem selects a manifest item from r.Manifest matching (ref, sourceIndex), one or
+// both of which should be (nil, -1).
+// On success, it returns the manifest item and an index of the matching tag, if a tag was used
+// for matching; the index is -1 if a tag was not used.
+func (r *Reader) ChooseManifestItem(ref reference.NamedTagged, sourceIndex int) (*ManifestItem, int, error) {
+ switch {
+ case ref != nil && sourceIndex != -1:
+ return nil, -1, errors.Errorf("Internal error: Cannot have both ref %s and source index @%d",
+ ref.String(), sourceIndex)
+
+ case ref != nil:
+ refString := ref.String()
+ for i := range r.Manifest {
+ for tagIndex, tag := range r.Manifest[i].RepoTags {
+ parsedTag, err := reference.ParseNormalizedNamed(tag)
+ if err != nil {
+ return nil, -1, errors.Wrapf(err, "Invalid tag %#v in manifest.json item @%d", tag, i)
+ }
+ if parsedTag.String() == refString {
+ return &r.Manifest[i], tagIndex, nil
+ }
+ }
+ }
+ return nil, -1, errors.Errorf("Tag %#v not found", refString)
+
+ case sourceIndex != -1:
+ if sourceIndex >= len(r.Manifest) {
+ return nil, -1, errors.Errorf("Invalid source index @%d, only %d manifest items available",
+ sourceIndex, len(r.Manifest))
+ }
+ return &r.Manifest[sourceIndex], -1, nil
+
+ default:
+ if len(r.Manifest) != 1 {
+ return nil, -1, errors.Errorf("Unexpected tar manifest.json: expected 1 item, got %d", len(r.Manifest))
+ }
+ return &r.Manifest[0], -1, nil
+ }
+}
+
+// tarReadCloser is a way to close the backing file of a tar.Reader when the user no longer needs the tar component.
+type tarReadCloser struct {
+ *tar.Reader
+ backingFile *os.File
+}
+
+func (t *tarReadCloser) Close() error {
+ return t.backingFile.Close()
+}
+
+// openTarComponent returns a ReadCloser for the specific file within the archive.
+// This is linear scan; we assume that the tar file will have a fairly small amount of files (~layers),
+// and that filesystem caching will make the repeated seeking over the (uncompressed) tarPath cheap enough.
+// It is safe to call this method from multiple goroutines simultaneously.
+// The caller should call .Close() on the returned stream.
+func (r *Reader) openTarComponent(componentPath string) (io.ReadCloser, error) {
+ // This is only a sanity check; if anyone did concurrently close ra, this access is technically
+ // racy against the write in .Close().
+ if r.path == "" {
+ return nil, errors.New("Internal error: trying to read an already closed tarfile.Reader")
+ }
+
+ f, err := os.Open(r.path)
+ if err != nil {
+ return nil, err
+ }
+ succeeded := false
+ defer func() {
+ if !succeeded {
+ f.Close()
+ }
+ }()
+
+ tarReader, header, err := findTarComponent(f, componentPath)
+ if err != nil {
+ return nil, err
+ }
+ if header == nil {
+ return nil, os.ErrNotExist
+ }
+ if header.FileInfo().Mode()&os.ModeType == os.ModeSymlink { // FIXME: untested
+ // We follow only one symlink; so no loops are possible.
+ if _, err := f.Seek(0, io.SeekStart); err != nil {
+ return nil, err
+ }
+ // The new path could easily point "outside" the archive, but we only compare it to existing tar headers without extracting the archive,
+ // so we don't care.
+ tarReader, header, err = findTarComponent(f, path.Join(path.Dir(componentPath), header.Linkname))
+ if err != nil {
+ return nil, err
+ }
+ if header == nil {
+ return nil, os.ErrNotExist
+ }
+ }
+
+ if !header.FileInfo().Mode().IsRegular() {
+ return nil, errors.Errorf("Error reading tar archive component %s: not a regular file", header.Name)
+ }
+ succeeded = true
+ return &tarReadCloser{Reader: tarReader, backingFile: f}, nil
+}
+
+// findTarComponent returns a header and a reader matching componentPath within inputFile,
+// or (nil, nil, nil) if not found.
+func findTarComponent(inputFile io.Reader, componentPath string) (*tar.Reader, *tar.Header, error) {
+ t := tar.NewReader(inputFile)
+ componentPath = path.Clean(componentPath)
+ for {
+ h, err := t.Next()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return nil, nil, err
+ }
+ if path.Clean(h.Name) == componentPath {
+ return t, h, nil
+ }
+ }
+ return nil, nil, nil
+}
+
+// readTarComponent returns full contents of componentPath.
+// It is safe to call this method from multiple goroutines simultaneously.
+func (r *Reader) readTarComponent(path string, limit int) ([]byte, error) {
+ file, err := r.openTarComponent(path)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Error loading tar component %s", path)
+ }
+ defer file.Close()
+ bytes, err := iolimits.ReadAtMost(file, limit)
+ if err != nil {
+ return nil, err
+ }
+ return bytes, nil
+}
diff --git a/vendor/github.com/containers/image/v5/docker/internal/tarfile/src.go b/vendor/github.com/containers/image/v5/docker/internal/tarfile/src.go
new file mode 100644
index 000000000..0db9a72b5
--- /dev/null
+++ b/vendor/github.com/containers/image/v5/docker/internal/tarfile/src.go
@@ -0,0 +1,331 @@
+package tarfile
+
+import (
+ "archive/tar"
+ "bytes"
+ "context"
+ "encoding/json"
+ "io"
+ "io/ioutil"
+ "os"
+ "path"
+ "sync"
+
+ "github.com/containers/image/v5/docker/reference"
+ "github.com/containers/image/v5/internal/iolimits"
+ "github.com/containers/image/v5/manifest"
+ "github.com/containers/image/v5/pkg/compression"
+ "github.com/containers/image/v5/types"
+ digest "github.com/opencontainers/go-digest"
+ "github.com/pkg/errors"
+)
+
+// Source is a partial implementation of types.ImageSource for reading from tarPath.
+type Source struct {
+ archive *Reader
+ closeArchive bool // .Close() the archive when the source is closed.
+ // If ref is nil and sourceIndex is -1, indicates the only image in the archive.
+ ref reference.NamedTagged // May be nil
+ sourceIndex int // May be -1
+ // The following data is only available after ensureCachedDataIsPresent() succeeds
+ tarManifest *ManifestItem // nil if not available yet.
+ configBytes []byte
+ configDigest digest.Digest
+ orderedDiffIDList []digest.Digest
+ knownLayers map[digest.Digest]*layerInfo
+ // Other state
+ generatedManifest []byte // Private cache for GetManifest(), nil if not set yet.
+ cacheDataLock sync.Once // Private state for ensureCachedDataIsPresent to make it concurrency-safe
+ cacheDataResult error // Private state for ensureCachedDataIsPresent
+}
+
+type layerInfo struct {
+ path string
+ size int64
+}
+
+// NewSource returns a tarfile.Source for an image in the specified archive matching ref
+// and sourceIndex (or the only image if they are (nil, -1)).
+// The archive will be closed if closeArchive
+func NewSource(archive *Reader, closeArchive bool, ref reference.NamedTagged, sourceIndex int) *Source {
+ return &Source{
+ archive: archive,
+ closeArchive: closeArchive,
+ ref: ref,
+ sourceIndex: sourceIndex,
+ }
+}
+
+// ensureCachedDataIsPresent loads data necessary for any of the public accessors.
+// It is safe to call this from multi-threaded code.
+func (s *Source) ensureCachedDataIsPresent() error {
+ s.cacheDataLock.Do(func() {
+ s.cacheDataResult = s.ensureCachedDataIsPresentPrivate()
+ })
+ return s.cacheDataResult
+}
+
+// ensureCachedDataIsPresentPrivate is a private implementation detail of ensureCachedDataIsPresent.
+// Call ensureCachedDataIsPresent instead.
+func (s *Source) ensureCachedDataIsPresentPrivate() error {
+ tarManifest, _, err := s.archive.ChooseManifestItem(s.ref, s.sourceIndex)
+ if err != nil {
+ return err
+ }
+
+ // Read and parse config.
+ configBytes, err := s.archive.readTarComponent(tarManifest.Config, iolimits.MaxConfigBodySize)
+ if err != nil {
+ return err
+ }
+ var parsedConfig manifest.Schema2Image // There's a lot of info there, but we only really care about layer DiffIDs.
+ if err := json.Unmarshal(configBytes, &parsedConfig); err != nil {
+ return errors.Wrapf(err, "Error decoding tar config %s", tarManifest.Config)
+ }
+ if parsedConfig.RootFS == nil {
+ return errors.Errorf("Invalid image config (rootFS is not set): %s", tarManifest.Config)
+ }
+
+ knownLayers, err := s.prepareLayerData(tarManifest, &parsedConfig)
+ if err != nil {
+ return err
+ }
+
+ // Success; commit.
+ s.tarManifest = tarManifest
+ s.configBytes = configBytes
+ s.configDigest = digest.FromBytes(configBytes)
+ s.orderedDiffIDList = parsedConfig.RootFS.DiffIDs
+ s.knownLayers = knownLayers
+ return nil
+}
+
+// Close removes resources associated with an initialized Source, if any.
+func (s *Source) Close() error {
+ if s.closeArchive {
+ return s.archive.Close()
+ }
+ return nil
+}
+
+// TarManifest returns contents of manifest.json
+func (s *Source) TarManifest() []ManifestItem {
+ return s.archive.Manifest
+}
+
+func (s *Source) prepareLayerData(tarManifest *ManifestItem, parsedConfig *manifest.Schema2Image) (map[digest.Digest]*layerInfo, error) {
+ // Collect layer data available in manifest and config.
+ if len(tarManifest.Layers) != len(parsedConfig.RootFS.DiffIDs) {
+ return nil, errors.Errorf("Inconsistent layer count: %d in manifest, %d in config", len(tarManifest.Layers), len(parsedConfig.RootFS.DiffIDs))
+ }
+ knownLayers := map[digest.Digest]*layerInfo{}
+ unknownLayerSizes := map[string]*layerInfo{} // Points into knownLayers, a "to do list" of items with unknown sizes.
+ for i, diffID := range parsedConfig.RootFS.DiffIDs {
+ if _, ok := knownLayers[diffID]; ok {
+ // Apparently it really can happen that a single image contains the same layer diff more than once.
+ // In that case, the diffID validation ensures that both layers truly are the same, and it should not matter
+ // which of the tarManifest.Layers paths is used; (docker save) actually makes the duplicates symlinks to the original.
+ continue
+ }
+ layerPath := path.Clean(tarManifest.Layers[i])
+ if _, ok := unknownLayerSizes[layerPath]; ok {
+ return nil, errors.Errorf("Layer tarfile %s used for two different DiffID values", layerPath)
+ }
+ li := &layerInfo{ // A new element in each iteration
+ path: layerPath,
+ size: -1,
+ }
+ knownLayers[diffID] = li
+ unknownLayerSizes[layerPath] = li
+ }
+
+ // Scan the tar file to collect layer sizes.
+ file, err := os.Open(s.archive.path)
+ if err != nil {
+ return nil, err
+ }
+ defer file.Close()
+ t := tar.NewReader(file)
+ for {
+ h, err := t.Next()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return nil, err
+ }
+ layerPath := path.Clean(h.Name)
+ // FIXME: Cache this data across images in Reader.
+ if li, ok := unknownLayerSizes[layerPath]; ok {
+ // Since GetBlob will decompress layers that are compressed we need
+ // to do the decompression here as well, otherwise we will
+ // incorrectly report the size. Pretty critical, since tools like
+ // umoci always compress layer blobs. Obviously we only bother with
+ // the slower method of checking if it's compressed.
+ uncompressedStream, isCompressed, err := compression.AutoDecompress(t)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Error auto-decompressing %s to determine its size", layerPath)
+ }
+ defer uncompressedStream.Close()
+
+ uncompressedSize := h.Size
+ if isCompressed {
+ uncompressedSize, err = io.Copy(ioutil.Discard, uncompressedStream)
+ if err != nil {
+ return nil, errors.Wrapf(err, "Error reading %s to find its size", layerPath)
+ }
+ }
+ li.size = uncompressedSize
+ delete(unknownLayerSizes, layerPath)
+ }
+ }
+ if len(unknownLayerSizes) != 0 {
+ return nil, errors.Errorf("Some layer tarfiles are missing in the tarball") // This could do with a better error reporting, if this ever happened in practice.
+ }
+
+ return knownLayers, nil
+}
+
+// GetManifest returns the image's manifest along with its MIME type (which may be empty when it can't be determined but the manifest is available).
+// It may use a remote (= slow) service.
+// If instanceDigest is not nil, it contains a digest of the specific manifest instance to retrieve (when the primary manifest is a manifest list);
+// this never happens if the primary manifest is not a manifest list (e.g. if the source never returns manifest lists).
+// This source implementation does not support manifest lists, so the passed-in instanceDigest should always be nil,
+// as the primary manifest can not be a list, so there can be no secondary instances.
+func (s *Source) GetManifest(ctx context.Context, instanceDigest *digest.Digest) ([]byte, string, error) {
+ if instanceDigest != nil {
+ // How did we even get here? GetManifest(ctx, nil) has returned a manifest.DockerV2Schema2MediaType.
+ return nil, "", errors.New(`Manifest lists are not supported by "docker-daemon:"`)
+ }
+ if s.generatedManifest == nil {
+ if err := s.ensureCachedDataIsPresent(); err != nil {
+ return nil, "", err
+ }
+ m := manifest.Schema2{
+ SchemaVersion: 2,
+ MediaType: manifest.DockerV2Schema2MediaType,
+ ConfigDescriptor: manifest.Schema2Descriptor{
+ MediaType: manifest.DockerV2Schema2ConfigMediaType,
+ Size: int64(len(s.configBytes)),
+ Digest: s.configDigest,
+ },
+ LayersDescriptors: []manifest.Schema2Descriptor{},
+ }
+ for _, diffID := range s.orderedDiffIDList {
+ li, ok := s.knownLayers[diffID]
+ if !ok {
+ return nil, "", errors.Errorf("Internal inconsistency: Information about layer %s missing", diffID)
+ }
+ m.LayersDescriptors = append(m.LayersDescriptors, manifest.Schema2Descriptor{
+ Digest: diffID, // diffID is a digest of the uncompressed tarball
+ MediaType: manifest.DockerV2Schema2LayerMediaType,
+ Size: li.size,
+ })
+ }
+ manifestBytes, err := json.Marshal(&m)
+ if err != nil {
+ return nil, "", err
+ }
+ s.generatedManifest = manifestBytes
+ }
+ return s.generatedManifest, manifest.DockerV2Schema2MediaType, nil
+}
+
+// uncompressedReadCloser is an io.ReadCloser that closes both the uncompressed stream and the underlying input.
+type uncompressedReadCloser struct {
+ io.Reader
+ underlyingCloser func() error
+ uncompressedCloser func() error
+}
+
+func (r uncompressedReadCloser) Close() error {
+ var res error
+ if err := r.uncompressedCloser(); err != nil {
+ res = err
+ }
+ if err := r.underlyingCloser(); err != nil && res == nil {
+ res = err
+ }
+ return res
+}
+
+// HasThreadSafeGetBlob indicates whether GetBlob can be executed concurrently.
+func (s *Source) HasThreadSafeGetBlob() bool {
+ return true
+}
+
+// GetBlob returns a stream for the specified blob, and the blob’s size (or -1 if unknown).
+// The Digest field in BlobInfo is guaranteed to be provided, Size may be -1 and MediaType may be optionally provided.
+// May update BlobInfoCache, preferably after it knows for certain that a blob truly exists at a specific location.
+func (s *Source) GetBlob(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache) (io.ReadCloser, int64, error) {
+ if err := s.ensureCachedDataIsPresent(); err != nil {
+ return nil, 0, err
+ }
+
+ if info.Digest == s.configDigest { // FIXME? Implement a more general algorithm matching instead of assuming sha256.
+ return ioutil.NopCloser(bytes.NewReader(s.configBytes)), int64(len(s.configBytes)), nil
+ }
+
+ if li, ok := s.knownLayers[info.Digest]; ok { // diffID is a digest of the uncompressed tarball,
+ underlyingStream, err := s.archive.openTarComponent(li.path)
+ if err != nil {
+ return nil, 0, err
+ }
+ closeUnderlyingStream := true
+ defer func() {
+ if closeUnderlyingStream {
+ underlyingStream.Close()
+ }
+ }()
+
+ // In order to handle the fact that digests != diffIDs (and thus that a
+ // caller which is trying to verify the blob will run into problems),
+ // we need to decompress blobs. This is a bit ugly, but it's a
+ // consequence of making everything addressable by their DiffID rather
+ // than by their digest...
+ //
+ // In particular, because the v2s2 manifest being generated uses
+ // DiffIDs, any caller of GetBlob is going to be asking for DiffIDs of
+ // layers not their _actual_ digest. The result is that copy/... will
+ // be verifing a "digest" which is not the actual layer's digest (but
+ // is instead the DiffID).
+
+ uncompressedStream, _, err := compression.AutoDecompress(underlyingStream)
+ if err != nil {
+ return nil, 0, errors.Wrapf(err, "Error auto-decompressing blob %s", info.Digest)
+ }
+
+ newStream := uncompressedReadCloser{
+ Reader: uncompressedStream,
+ underlyingCloser: underlyingStream.Close,
+ uncompressedCloser: uncompressedStream.Close,
+ }
+ closeUnderlyingStream = false
+
+ return newStream, li.size, nil
+ }
+
+ return nil, 0, errors.Errorf("Unknown blob %s", info.Digest)
+}
+
+// GetSignatures returns the image's signatures. It may use a remote (= slow) service.
+// This source implementation does not support manifest lists, so the passed-in instanceDigest should always be nil,
+// as there can be no secondary manifests.
+func (s *Source) GetSignatures(ctx context.Context, instanceDigest *digest.Digest) ([][]byte, error) {
+ if instanceDigest != nil {
+ // How did we even get here? GetManifest(ctx, nil) has returned a manifest.DockerV2Schema2MediaType.
+ return nil, errors.Errorf(`Manifest lists are not supported by "docker-daemon:"`)
+ }
+ return [][]byte{}, nil
+}
+
+// LayerInfosForCopy returns either nil (meaning the values in the manifest are fine), or updated values for the layer
+// blobsums that are listed in the image's manifest. If values are returned, they should be used when using GetBlob()
+// to read the image's layers.
+// This source implementation does not support manifest lists, so the passed-in instanceDigest should always be nil,
+// as the primary manifest can not be a list, so there can be no secondary manifests.
+// The Digest field is guaranteed to be provided; Size may be -1.
+// WARNING: The list may contain duplicates, and they are semantically relevant.
+func (s *Source) LayerInfosForCopy(context.Context, *digest.Digest) ([]types.BlobInfo, error) {
+ return nil, nil
+}
diff --git a/vendor/github.com/containers/image/v5/docker/internal/tarfile/types.go b/vendor/github.com/containers/image/v5/docker/internal/tarfile/types.go
new file mode 100644
index 000000000..6e6ccd2d8
--- /dev/null
+++ b/vendor/github.com/containers/image/v5/docker/internal/tarfile/types.go
@@ -0,0 +1,28 @@
+package tarfile
+
+import (
+ "github.com/containers/image/v5/manifest"
+ "github.com/opencontainers/go-digest"
+)
+
+// Various data structures.
+
+// Based on github.com/docker/docker/image/tarexport/tarexport.go
+const (
+ manifestFileName = "manifest.json"
+ legacyLayerFileName = "layer.tar"
+ legacyConfigFileName = "json"
+ legacyVersionFileName = "VERSION"
+ legacyRepositoriesFileName = "repositories"
+)
+
+// ManifestItem is an element of the array stored in the top-level manifest.json file.
+type ManifestItem struct { // NOTE: This is visible as docker/tarfile.ManifestItem, and a part of the stable API.
+ Config string
+ RepoTags []string
+ Layers []string
+ Parent imageID `json:",omitempty"`
+ LayerSources map[digest.Digest]manifest.Schema2Descriptor `json:",omitempty"`
+}
+
+type imageID string
diff --git a/vendor/github.com/containers/image/v5/docker/internal/tarfile/writer.go b/vendor/github.com/containers/image/v5/docker/internal/tarfile/writer.go
new file mode 100644
index 000000000..fd2c461d0
--- /dev/null
+++ b/vendor/github.com/containers/image/v5/docker/internal/tarfile/writer.go
@@ -0,0 +1,381 @@
+package tarfile
+
+import (
+ "archive/tar"
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "sync"
+ "time"
+
+ "github.com/containers/image/v5/docker/reference"
+ "github.com/containers/image/v5/manifest"
+ "github.com/containers/image/v5/types"
+ "github.com/opencontainers/go-digest"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+// Writer allows creating a (docker save)-formatted tar archive containing one or more images.
+type Writer struct {
+ mutex sync.Mutex
+ // ALL of the following members can only be accessed with the mutex held.
+ // Use Writer.lock() to obtain the mutex.
+ writer io.Writer
+ tar *tar.Writer // nil if the Writer has already been closed.
+ // Other state.
+ blobs map[digest.Digest]types.BlobInfo // list of already-sent blobs
+ repositories map[string]map[string]string
+ legacyLayers map[string]struct{} // A set of IDs of legacy layers that have been already sent.
+ manifest []ManifestItem
+ manifestByConfig map[digest.Digest]int // A map from config digest to an entry index in manifest above.
+}
+
+// NewWriter returns a Writer for the specified io.Writer.
+// The caller must eventually call .Close() on the returned object to create a valid archive.
+func NewWriter(dest io.Writer) *Writer {
+ return &Writer{
+ writer: dest,
+ tar: tar.NewWriter(dest),
+ blobs: make(map[digest.Digest]types.BlobInfo),
+ repositories: map[string]map[string]string{},
+ legacyLayers: map[string]struct{}{},
+ manifestByConfig: map[digest.Digest]int{},
+ }
+}
+
+// lock does some sanity checks and locks the Writer.
+// If this function suceeds, the caller must call w.unlock.
+// Do not use Writer.mutex directly.
+func (w *Writer) lock() error {
+ w.mutex.Lock()
+ if w.tar == nil {
+ w.mutex.Unlock()
+ return errors.New("Internal error: trying to use an already closed tarfile.Writer")
+ }
+ return nil
+}
+
+// unlock releases the lock obtained by Writer.lock
+// Do not use Writer.mutex directly.
+func (w *Writer) unlock() {
+ w.mutex.Unlock()
+}
+
+// tryReusingBlobLocked checks whether the transport already contains, a blob, and if so, returns its metadata.
+// info.Digest must not be empty.
+// If the blob has been succesfully reused, returns (true, info, nil); info must contain at least a digest and size.
+// If the transport can not reuse the requested blob, tryReusingBlob returns (false, {}, nil); it returns a non-nil error only on an unexpected failure.
+// The caller must have locked the Writer.
+func (w *Writer) tryReusingBlobLocked(info types.BlobInfo) (bool, types.BlobInfo, error) {
+ if info.Digest == "" {
+ return false, types.BlobInfo{}, errors.Errorf("Can not check for a blob with unknown digest")
+ }
+ if blob, ok := w.blobs[info.Digest]; ok {
+ return true, types.BlobInfo{Digest: info.Digest, Size: blob.Size}, nil
+ }
+ return false, types.BlobInfo{}, nil
+}
+
+// recordBlob records metadata of a recorded blob, which must contain at least a digest and size.
+// The caller must have locked the Writer.
+func (w *Writer) recordBlobLocked(info types.BlobInfo) {
+ w.blobs[info.Digest] = info
+}
+
+// ensureSingleLegacyLayerLocked writes legacy VERSION and configuration files for a single layer
+// The caller must have locked the Writer.
+func (w *Writer) ensureSingleLegacyLayerLocked(layerID string, layerDigest digest.Digest, configBytes []byte) error {
+ if _, ok := w.legacyLayers[layerID]; !ok {
+ // Create a symlink for the legacy format, where there is one subdirectory per layer ("image").
+ // See also the comment in physicalLayerPath.
+ physicalLayerPath := w.physicalLayerPath(layerDigest)
+ if err := w.sendSymlinkLocked(filepath.Join(layerID, legacyLayerFileName), filepath.Join("..", physicalLayerPath)); err != nil {
+ return errors.Wrap(err, "Error creating layer symbolic link")
+ }
+
+ b := []byte("1.0")
+ if err := w.sendBytesLocked(filepath.Join(layerID, legacyVersionFileName), b); err != nil {
+ return errors.Wrap(err, "Error writing VERSION file")
+ }
+
+ if err := w.sendBytesLocked(filepath.Join(layerID, legacyConfigFileName), configBytes); err != nil {
+ return errors.Wrap(err, "Error writing config json file")
+ }
+
+ w.legacyLayers[layerID] = struct{}{}
+ }
+ return nil
+}
+
+// writeLegacyMetadataLocked writes legacy layer metadata and records tags for a single image.
+func (w *Writer) writeLegacyMetadataLocked(layerDescriptors []manifest.Schema2Descriptor, configBytes []byte, repoTags []reference.NamedTagged) error {
+ var chainID digest.Digest
+ lastLayerID := ""
+ for i, l := range layerDescriptors {
+ // The legacy format requires a config file per layer
+ layerConfig := make(map[string]interface{})
+
+ // The root layer doesn't have any parent
+ if lastLayerID != "" {
+ layerConfig["parent"] = lastLayerID
+ }
+ // The top layer configuration file is generated by using subpart of the image configuration
+ if i == len(layerDescriptors)-1 {
+ var config map[string]*json.RawMessage
+ err := json.Unmarshal(configBytes, &config)
+ if err != nil {
+ return errors.Wrap(err, "Error unmarshaling config")
+ }
+ for _, attr := range [7]string{"architecture", "config", "container", "container_config", "created", "docker_version", "os"} {
+ layerConfig[attr] = config[attr]
+ }
+ }
+
+ // This chainID value matches the computation in docker/docker/layer.CreateChainID …
+ if chainID == "" {
+ chainID = l.Digest
+ } else {
+ chainID = digest.Canonical.FromString(chainID.String() + " " + l.Digest.String())
+ }
+ // … but note that the image ID does not _exactly_ match docker/docker/image/v1.CreateID, primarily because
+ // we create the image configs differently in details. At least recent versions allocate new IDs on load,
+ // so this is fine as long as the IDs we use are unique / cannot loop.
+ //
+ // For intermediate images, we could just use the chainID as an image ID, but using a digest of ~the created
+ // config makes sure that everything uses the same “namespace”; a bit less efficient but clearer.
+ //
+ // Temporarily add the chainID to the config, only for the purpose of generating the image ID.
+ layerConfig["layer_id"] = chainID
+ b, err := json.Marshal(layerConfig) // Note that layerConfig["id"] is not set yet at this point.
+ if err != nil {
+ return errors.Wrap(err, "Error marshaling layer config")
+ }
+ delete(layerConfig, "layer_id")
+ layerID := digest.Canonical.FromBytes(b).Hex()
+ layerConfig["id"] = layerID
+
+ configBytes, err := json.Marshal(layerConfig)
+ if err != nil {
+ return errors.Wrap(err, "Error marshaling layer config")
+ }
+
+ if err := w.ensureSingleLegacyLayerLocked(layerID, l.Digest, configBytes); err != nil {
+ return err
+ }
+
+ lastLayerID = layerID
+ }
+
+ if lastLayerID != "" {
+ for _, repoTag := range repoTags {
+ if val, ok := w.repositories[repoTag.Name()]; ok {
+ val[repoTag.Tag()] = lastLayerID
+ } else {
+ w.repositories[repoTag.Name()] = map[string]string{repoTag.Tag(): lastLayerID}
+ }
+ }
+ }
+ return nil
+}
+
+// checkManifestItemsMatch checks that a and b describe the same image,
+// and returns an error if that’s not the case (which should never happen).
+func checkManifestItemsMatch(a, b *ManifestItem) error {
+ if a.Config != b.Config {
+ return fmt.Errorf("Internal error: Trying to reuse ManifestItem values with configs %#v vs. %#v", a.Config, b.Config)
+ }
+ if len(a.Layers) != len(b.Layers) {
+ return fmt.Errorf("Internal error: Trying to reuse ManifestItem values with layers %#v vs. %#v", a.Layers, b.Layers)
+ }
+ for i := range a.Layers {
+ if a.Layers[i] != b.Layers[i] {
+ return fmt.Errorf("Internal error: Trying to reuse ManifestItem values with layers[i] %#v vs. %#v", a.Layers[i], b.Layers[i])
+ }
+ }
+ // Ignore RepoTags, that will be built later.
+ // Ignore Parent and LayerSources, which we don’t set to anything meaningful.
+ return nil
+}
+
+// ensureManifestItemLocked ensures that there is a manifest item pointing to (layerDescriptors, configDigest) with repoTags
+// The caller must have locked the Writer.
+func (w *Writer) ensureManifestItemLocked(layerDescriptors []manifest.Schema2Descriptor, configDigest digest.Digest, repoTags []reference.NamedTagged) error {
+ layerPaths := []string{}
+ for _, l := range layerDescriptors {
+ layerPaths = append(layerPaths, w.physicalLayerPath(l.Digest))
+ }
+
+ var item *ManifestItem
+ newItem := ManifestItem{
+ Config: w.configPath(configDigest),
+ RepoTags: []string{},
+ Layers: layerPaths,
+ Parent: "", // We don’t have this information
+ LayerSources: nil,
+ }
+ if i, ok := w.manifestByConfig[configDigest]; ok {
+ item = &w.manifest[i]
+ if err := checkManifestItemsMatch(item, &newItem); err != nil {
+ return err
+ }
+ } else {
+ i := len(w.manifest)
+ w.manifestByConfig[configDigest] = i
+ w.manifest = append(w.manifest, newItem)
+ item = &w.manifest[i]
+ }
+
+ knownRepoTags := map[string]struct{}{}
+ for _, repoTag := range item.RepoTags {
+ knownRepoTags[repoTag] = struct{}{}
+ }
+ for _, tag := range repoTags {
+ // For github.com/docker/docker consumers, this works just as well as
+ // refString := ref.String()
+ // because when reading the RepoTags strings, github.com/docker/docker/reference
+ // normalizes both of them to the same value.
+ //
+ // Doing it this way to include the normalized-out `docker.io[/library]` does make
+ // a difference for github.com/projectatomic/docker consumers, with the
+ // “Add --add-registry and --block-registry options to docker daemon” patch.
+ // These consumers treat reference strings which include a hostname and reference
+ // strings without a hostname differently.
+ //
+ // Using the host name here is more explicit about the intent, and it has the same
+ // effect as (docker pull) in projectatomic/docker, which tags the result using
+ // a hostname-qualified reference.
+ // See https://github.com/containers/image/issues/72 for a more detailed
+ // analysis and explanation.
+ refString := fmt.Sprintf("%s:%s", tag.Name(), tag.Tag())
+
+ if _, ok := knownRepoTags[refString]; !ok {
+ item.RepoTags = append(item.RepoTags, refString)
+ knownRepoTags[refString] = struct{}{}
+ }
+ }
+
+ return nil
+}
+
+// Close writes all outstanding data about images to the archive, and finishes writing data
+// to the underlying io.Writer.
+// No more images can be added after this is called.
+func (w *Writer) Close() error {
+ if err := w.lock(); err != nil {
+ return err
+ }
+ defer w.unlock()
+
+ b, err := json.Marshal(&w.manifest)
+ if err != nil {
+ return err
+ }
+ if err := w.sendBytesLocked(manifestFileName, b); err != nil {
+ return err
+ }
+
+ b, err = json.Marshal(w.repositories)
+ if err != nil {
+ return errors.Wrap(err, "Error marshaling repositories")
+ }
+ if err := w.sendBytesLocked(legacyRepositoriesFileName, b); err != nil {
+ return errors.Wrap(err, "Error writing config json file")
+ }
+
+ if err := w.tar.Close(); err != nil {
+ return err
+ }
+ w.tar = nil // Mark the Writer as closed.
+ return nil
+}
+
+// configPath returns a path we choose for storing a config with the specified digest.
+// NOTE: This is an internal implementation detail, not a format property, and can change
+// any time.
+func (w *Writer) configPath(configDigest digest.Digest) string {
+ return configDigest.Hex() + ".json"
+}
+
+// physicalLayerPath returns a path we choose for storing a layer with the specified digest
+// (the actual path, i.e. a regular file, not a symlink that may be used in the legacy format).
+// NOTE: This is an internal implementation detail, not a format property, and can change
+// any time.
+func (w *Writer) physicalLayerPath(layerDigest digest.Digest) string {
+ // Note that this can't be e.g. filepath.Join(l.Digest.Hex(), legacyLayerFileName); due to the way
+ // writeLegacyMetadata constructs layer IDs differently from inputinfo.Digest values (as described
+ // inside it), most of the layers would end up in subdirectories alone without any metadata; (docker load)
+ // tries to load every subdirectory as an image and fails if the config is missing. So, keep the layers
+ // in the root of the tarball.
+ return layerDigest.Hex() + ".tar"
+}
+
+type tarFI struct {
+ path string
+ size int64
+ isSymlink bool
+}
+
+func (t *tarFI) Name() string {
+ return t.path
+}
+func (t *tarFI) Size() int64 {
+ return t.size
+}
+func (t *tarFI) Mode() os.FileMode {
+ if t.isSymlink {
+ return os.ModeSymlink
+ }
+ return 0444
+}
+func (t *tarFI) ModTime() time.Time {
+ return time.Unix(0, 0)
+}
+func (t *tarFI) IsDir() bool {
+ return false
+}
+func (t *tarFI) Sys() interface{} {
+ return nil
+}
+
+// sendSymlinkLocked sends a symlink into the tar stream.
+// The caller must have locked the Writer.
+func (w *Writer) sendSymlinkLocked(path string, target string) error {
+ hdr, err := tar.FileInfoHeader(&tarFI{path: path, size: 0, isSymlink: true}, target)
+ if err != nil {
+ return nil
+ }
+ logrus.Debugf("Sending as tar link %s -> %s", path, target)
+ return w.tar.WriteHeader(hdr)
+}
+
+// sendBytesLocked sends a path into the tar stream.
+// The caller must have locked the Writer.
+func (w *Writer) sendBytesLocked(path string, b []byte) error {
+ return w.sendFileLocked(path, int64(len(b)), bytes.NewReader(b))
+}
+
+// sendFileLocked sends a file into the tar stream.
+// The caller must have locked the Writer.
+func (w *Writer) sendFileLocked(path string, expectedSize int64, stream io.Reader) error {
+ hdr, err := tar.FileInfoHeader(&tarFI{path: path, size: expectedSize}, "")
+ if err != nil {
+ return nil
+ }
+ logrus.Debugf("Sending as tar file %s", path)
+ if err := w.tar.WriteHeader(hdr); err != nil {
+ return err
+ }
+ // TODO: This can take quite some time, and should ideally be cancellable using a context.Context.
+ size, err := io.Copy(w.tar, stream)
+ if err != nil {
+ return err
+ }
+ if size != expectedSize {
+ return errors.Errorf("Size mismatch when copying %s, expected %d, got %d", path, expectedSize, size)
+ }
+ return nil
+}
diff --git a/vendor/github.com/containers/image/v5/docker/lookaside.go b/vendor/github.com/containers/image/v5/docker/lookaside.go
index 918c0f838..6931fd07b 100644
--- a/vendor/github.com/containers/image/v5/docker/lookaside.go
+++ b/vendor/github.com/containers/image/v5/docker/lookaside.go
@@ -11,6 +11,7 @@ import (
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/types"
+ "github.com/containers/storage/pkg/homedir"
"github.com/ghodss/yaml"
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
@@ -26,6 +27,9 @@ var systemRegistriesDirPath = builtinRegistriesDirPath
// DO NOT change this, instead see systemRegistriesDirPath above.
const builtinRegistriesDirPath = "/etc/containers/registries.d"
+// userRegistriesDirPath is the path to the per user registries.d.
+var userRegistriesDir = filepath.FromSlash(".config/containers/registries.d")
+
// registryConfiguration is one of the files in registriesDirPath configuring lookaside locations, or the result of merging them all.
// NOTE: Keep this in sync with docs/registries.d.md!
type registryConfiguration struct {
@@ -75,14 +79,17 @@ func configuredSignatureStorageBase(sys *types.SystemContext, ref dockerReferenc
// registriesDirPath returns a path to registries.d
func registriesDirPath(sys *types.SystemContext) string {
- if sys != nil {
- if sys.RegistriesDirPath != "" {
- return sys.RegistriesDirPath
- }
- if sys.RootForImplicitAbsolutePaths != "" {
- return filepath.Join(sys.RootForImplicitAbsolutePaths, systemRegistriesDirPath)
- }
+ if sys != nil && sys.RegistriesDirPath != "" {
+ return sys.RegistriesDirPath
}
+ userRegistriesDirPath := filepath.Join(homedir.Get(), userRegistriesDir)
+ if _, err := os.Stat(userRegistriesDirPath); err == nil {
+ return userRegistriesDirPath
+ }
+ if sys != nil && sys.RootForImplicitAbsolutePaths != "" {
+ return filepath.Join(sys.RootForImplicitAbsolutePaths, systemRegistriesDirPath)
+ }
+
return systemRegistriesDirPath
}
diff --git a/vendor/github.com/containers/image/v5/docker/tarfile/dest.go b/vendor/github.com/containers/image/v5/docker/tarfile/dest.go
index c171da505..af1690683 100644
--- a/vendor/github.com/containers/image/v5/docker/tarfile/dest.go
+++ b/vendor/github.com/containers/image/v5/docker/tarfile/dest.go
@@ -1,36 +1,19 @@
package tarfile
import (
- "archive/tar"
- "bytes"
"context"
- "encoding/json"
- "fmt"
"io"
- "io/ioutil"
- "os"
- "path/filepath"
- "time"
+ internal "github.com/containers/image/v5/docker/internal/tarfile"
"github.com/containers/image/v5/docker/reference"
- "github.com/containers/image/v5/internal/iolimits"
- "github.com/containers/image/v5/internal/tmpdir"
- "github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/types"
"github.com/opencontainers/go-digest"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
)
// Destination is a partial implementation of types.ImageDestination for writing to an io.Writer.
type Destination struct {
- writer io.Writer
- tar *tar.Writer
- repoTags []reference.NamedTagged
- // Other state.
- blobs map[digest.Digest]types.BlobInfo // list of already-sent blobs
- config []byte
- sysCtx *types.SystemContext
+ internal *internal.Destination
+ archive *internal.Writer
}
// NewDestination returns a tarfile.Destination for the specified io.Writer.
@@ -41,59 +24,51 @@ func NewDestination(dest io.Writer, ref reference.NamedTagged) *Destination {
// NewDestinationWithContext returns a tarfile.Destination for the specified io.Writer.
func NewDestinationWithContext(sys *types.SystemContext, dest io.Writer, ref reference.NamedTagged) *Destination {
- repoTags := []reference.NamedTagged{}
- if ref != nil {
- repoTags = append(repoTags, ref)
- }
+ archive := internal.NewWriter(dest)
return &Destination{
- writer: dest,
- tar: tar.NewWriter(dest),
- repoTags: repoTags,
- blobs: make(map[digest.Digest]types.BlobInfo),
- sysCtx: sys,
+ internal: internal.NewDestination(sys, archive, ref),
+ archive: archive,
}
}
// AddRepoTags adds the specified tags to the destination's repoTags.
func (d *Destination) AddRepoTags(tags []reference.NamedTagged) {
- d.repoTags = append(d.repoTags, tags...)
+ d.internal.AddRepoTags(tags)
}
// SupportedManifestMIMETypes tells which manifest mime types the destination supports
// If an empty slice or nil it's returned, then any mime type can be tried to upload
func (d *Destination) SupportedManifestMIMETypes() []string {
- return []string{
- manifest.DockerV2Schema2MediaType, // We rely on the types.Image.UpdatedImage schema conversion capabilities.
- }
+ return d.internal.SupportedManifestMIMETypes()
}
// SupportsSignatures returns an error (to be displayed to the user) if the destination certainly can't store signatures.
// Note: It is still possible for PutSignatures to fail if SupportsSignatures returns nil.
func (d *Destination) SupportsSignatures(ctx context.Context) error {
- return errors.Errorf("Storing signatures for docker tar files is not supported")
+ return d.internal.SupportsSignatures(ctx)
}
// AcceptsForeignLayerURLs returns false iff foreign layers in manifest should be actually
// uploaded to the image destination, true otherwise.
func (d *Destination) AcceptsForeignLayerURLs() bool {
- return false
+ return d.internal.AcceptsForeignLayerURLs()
}
// MustMatchRuntimeOS returns true iff the destination can store only images targeted for the current runtime architecture and OS. False otherwise.
func (d *Destination) MustMatchRuntimeOS() bool {
- return false
+ return d.internal.MustMatchRuntimeOS()
}
// IgnoresEmbeddedDockerReference returns true iff the destination does not care about Image.EmbeddedDockerReferenceConflicts(),
// and would prefer to receive an unmodified manifest instead of one modified for the destination.
// Does not make a difference if Reference().DockerReference() is nil.
func (d *Destination) IgnoresEmbeddedDockerReference() bool {
- return false // N/A, we only accept schema2 images where EmbeddedDockerReferenceConflicts() is always false.
+ return d.internal.IgnoresEmbeddedDockerReference()
}
// HasThreadSafePutBlob indicates whether PutBlob can be executed concurrently.
func (d *Destination) HasThreadSafePutBlob() bool {
- return false
+ return d.internal.HasThreadSafePutBlob()
}
// PutBlob writes contents of stream and returns data representing the result (with all data filled in).
@@ -104,66 +79,7 @@ func (d *Destination) HasThreadSafePutBlob() bool {
// to any other readers for download using the supplied digest.
// If stream.Read() at any time, ESPECIALLY at end of input, returns an error, PutBlob MUST 1) fail, and 2) delete any data stored so far.
func (d *Destination) PutBlob(ctx context.Context, stream io.Reader, inputInfo types.BlobInfo, cache types.BlobInfoCache, isConfig bool) (types.BlobInfo, error) {
- // Ouch, we need to stream the blob into a temporary file just to determine the size.
- // When the layer is decompressed, we also have to generate the digest on uncompressed datas.
- if inputInfo.Size == -1 || inputInfo.Digest.String() == "" {
- logrus.Debugf("docker tarfile: input with unknown size, streaming to disk first ...")
- streamCopy, err := ioutil.TempFile(tmpdir.TemporaryDirectoryForBigFiles(d.sysCtx), "docker-tarfile-blob")
- if err != nil {
- return types.BlobInfo{}, err
- }
- defer os.Remove(streamCopy.Name())
- defer streamCopy.Close()
-
- digester := digest.Canonical.Digester()
- tee := io.TeeReader(stream, digester.Hash())
- // TODO: This can take quite some time, and should ideally be cancellable using ctx.Done().
- size, err := io.Copy(streamCopy, tee)
- if err != nil {
- return types.BlobInfo{}, err
- }
- _, err = streamCopy.Seek(0, io.SeekStart)
- if err != nil {
- return types.BlobInfo{}, err
- }
- inputInfo.Size = size // inputInfo is a struct, so we are only modifying our copy.
- if inputInfo.Digest == "" {
- inputInfo.Digest = digester.Digest()
- }
- stream = streamCopy
- logrus.Debugf("... streaming done")
- }
-
- // Maybe the blob has been already sent
- ok, reusedInfo, err := d.TryReusingBlob(ctx, inputInfo, cache, false)
- if err != nil {
- return types.BlobInfo{}, err
- }
- if ok {
- return reusedInfo, nil
- }
-
- if isConfig {
- buf, err := iolimits.ReadAtMost(stream, iolimits.MaxConfigBodySize)
- if err != nil {
- return types.BlobInfo{}, errors.Wrap(err, "Error reading Config file stream")
- }
- d.config = buf
- if err := d.sendFile(inputInfo.Digest.Hex()+".json", inputInfo.Size, bytes.NewReader(buf)); err != nil {
- return types.BlobInfo{}, errors.Wrap(err, "Error writing Config file")
- }
- } else {
- // Note that this can't be e.g. filepath.Join(l.Digest.Hex(), legacyLayerFileName); due to the way
- // writeLegacyLayerMetadata constructs layer IDs differently from inputinfo.Digest values (as described
- // inside it), most of the layers would end up in subdirectories alone without any metadata; (docker load)
- // tries to load every subdirectory as an image and fails if the config is missing. So, keep the layers
- // in the root of the tarball.
- if err := d.sendFile(inputInfo.Digest.Hex()+".tar", inputInfo.Size, stream); err != nil {
- return types.BlobInfo{}, err
- }
- }
- d.blobs[inputInfo.Digest] = types.BlobInfo{Digest: inputInfo.Digest, Size: inputInfo.Size}
- return types.BlobInfo{Digest: inputInfo.Digest, Size: inputInfo.Size}, nil
+ return d.internal.PutBlob(ctx, stream, inputInfo, cache, isConfig)
}
// TryReusingBlob checks whether the transport already contains, or can efficiently reuse, a blob, and if so, applies it to the current destination
@@ -174,33 +90,7 @@ func (d *Destination) PutBlob(ctx context.Context, stream io.Reader, inputInfo t
// If the transport can not reuse the requested blob, TryReusingBlob returns (false, {}, nil); it returns a non-nil error only on an unexpected failure.
// May use and/or update cache.
func (d *Destination) TryReusingBlob(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache, canSubstitute bool) (bool, types.BlobInfo, error) {
- if info.Digest == "" {
- return false, types.BlobInfo{}, errors.Errorf("Can not check for a blob with unknown digest")
- }
- if blob, ok := d.blobs[info.Digest]; ok {
- return true, types.BlobInfo{Digest: info.Digest, Size: blob.Size}, nil
- }
- return false, types.BlobInfo{}, nil
-}
-
-func (d *Destination) createRepositoriesFile(rootLayerID string) error {
- repositories := map[string]map[string]string{}
- for _, repoTag := range d.repoTags {
- if val, ok := repositories[repoTag.Name()]; ok {
- val[repoTag.Tag()] = rootLayerID
- } else {
- repositories[repoTag.Name()] = map[string]string{repoTag.Tag(): rootLayerID}
- }
- }
-
- b, err := json.Marshal(repositories)
- if err != nil {
- return errors.Wrap(err, "Error marshaling repositories")
- }
- if err := d.sendBytes(legacyRepositoriesFileName, b); err != nil {
- return errors.Wrap(err, "Error writing config json file")
- }
- return nil
+ return d.internal.TryReusingBlob(ctx, info, cache, canSubstitute)
}
// PutManifest writes manifest to the destination.
@@ -210,215 +100,18 @@ func (d *Destination) createRepositoriesFile(rootLayerID string) error {
// If the destination is in principle available, refuses this manifest type (e.g. it does not recognize the schema),
// but may accept a different manifest type, the returned error must be an ManifestTypeRejectedError.
func (d *Destination) PutManifest(ctx context.Context, m []byte, instanceDigest *digest.Digest) error {
- if instanceDigest != nil {
- return errors.New(`Manifest lists are not supported for docker tar files`)
- }
- // We do not bother with types.ManifestTypeRejectedError; our .SupportedManifestMIMETypes() above is already providing only one alternative,
- // so the caller trying a different manifest kind would be pointless.
- var man manifest.Schema2
- if err := json.Unmarshal(m, &man); err != nil {
- return errors.Wrap(err, "Error parsing manifest")
- }
- if man.SchemaVersion != 2 || man.MediaType != manifest.DockerV2Schema2MediaType {
- return errors.Errorf("Unsupported manifest type, need a Docker schema 2 manifest")
- }
-
- layerPaths, lastLayerID, err := d.writeLegacyLayerMetadata(man.LayersDescriptors)
- if err != nil {
- return err
- }
-
- if len(man.LayersDescriptors) > 0 {
- if err := d.createRepositoriesFile(lastLayerID); err != nil {
- return err
- }
- }
-
- repoTags := []string{}
- for _, tag := range d.repoTags {
- // For github.com/docker/docker consumers, this works just as well as
- // refString := ref.String()
- // because when reading the RepoTags strings, github.com/docker/docker/reference
- // normalizes both of them to the same value.
- //
- // Doing it this way to include the normalized-out `docker.io[/library]` does make
- // a difference for github.com/projectatomic/docker consumers, with the
- // “Add --add-registry and --block-registry options to docker daemon” patch.
- // These consumers treat reference strings which include a hostname and reference
- // strings without a hostname differently.
- //
- // Using the host name here is more explicit about the intent, and it has the same
- // effect as (docker pull) in projectatomic/docker, which tags the result using
- // a hostname-qualified reference.
- // See https://github.com/containers/image/issues/72 for a more detailed
- // analysis and explanation.
- refString := fmt.Sprintf("%s:%s", tag.Name(), tag.Tag())
- repoTags = append(repoTags, refString)
- }
-
- items := []ManifestItem{{
- Config: man.ConfigDescriptor.Digest.Hex() + ".json",
- RepoTags: repoTags,
- Layers: layerPaths,
- Parent: "",
- LayerSources: nil,
- }}
- itemsBytes, err := json.Marshal(&items)
- if err != nil {
- return err
- }
-
- // FIXME? Do we also need to support the legacy format?
- return d.sendBytes(manifestFileName, itemsBytes)
-}
-
-// writeLegacyLayerMetadata writes legacy VERSION and configuration files for all layers
-func (d *Destination) writeLegacyLayerMetadata(layerDescriptors []manifest.Schema2Descriptor) (layerPaths []string, lastLayerID string, err error) {
- var chainID digest.Digest
- lastLayerID = ""
- for i, l := range layerDescriptors {
- // This chainID value matches the computation in docker/docker/layer.CreateChainID …
- if chainID == "" {
- chainID = l.Digest
- } else {
- chainID = digest.Canonical.FromString(chainID.String() + " " + l.Digest.String())
- }
- // … but note that this image ID does not match docker/docker/image/v1.CreateID. At least recent
- // versions allocate new IDs on load, as long as the IDs we use are unique / cannot loop.
- //
- // Overall, the goal of computing a digest dependent on the full history is to avoid reusing an image ID
- // (and possibly creating a loop in the "parent" links) if a layer with the same DiffID appears two or more
- // times in layersDescriptors. The ChainID values are sufficient for this, the v1.CreateID computation
- // which also mixes in the full image configuration seems unnecessary, at least as long as we are storing
- // only a single image per tarball, i.e. all DiffID prefixes are unique (can’t differ only with
- // configuration).
- layerID := chainID.Hex()
-
- physicalLayerPath := l.Digest.Hex() + ".tar"
- // The layer itself has been stored into physicalLayerPath in PutManifest.
- // So, use that path for layerPaths used in the non-legacy manifest
- layerPaths = append(layerPaths, physicalLayerPath)
- // ... and create a symlink for the legacy format;
- if err := d.sendSymlink(filepath.Join(layerID, legacyLayerFileName), filepath.Join("..", physicalLayerPath)); err != nil {
- return nil, "", errors.Wrap(err, "Error creating layer symbolic link")
- }
-
- b := []byte("1.0")
- if err := d.sendBytes(filepath.Join(layerID, legacyVersionFileName), b); err != nil {
- return nil, "", errors.Wrap(err, "Error writing VERSION file")
- }
-
- // The legacy format requires a config file per layer
- layerConfig := make(map[string]interface{})
- layerConfig["id"] = layerID
-
- // The root layer doesn't have any parent
- if lastLayerID != "" {
- layerConfig["parent"] = lastLayerID
- }
- // The root layer configuration file is generated by using subpart of the image configuration
- if i == len(layerDescriptors)-1 {
- var config map[string]*json.RawMessage
- err := json.Unmarshal(d.config, &config)
- if err != nil {
- return nil, "", errors.Wrap(err, "Error unmarshaling config")
- }
- for _, attr := range [7]string{"architecture", "config", "container", "container_config", "created", "docker_version", "os"} {
- layerConfig[attr] = config[attr]
- }
- }
- b, err := json.Marshal(layerConfig)
- if err != nil {
- return nil, "", errors.Wrap(err, "Error marshaling layer config")
- }
- if err := d.sendBytes(filepath.Join(layerID, legacyConfigFileName), b); err != nil {
- return nil, "", errors.Wrap(err, "Error writing config json file")
- }
-
- lastLayerID = layerID
- }
- return layerPaths, lastLayerID, nil
-}
-
-type tarFI struct {
- path string
- size int64
- isSymlink bool
-}
-
-func (t *tarFI) Name() string {
- return t.path
-}
-func (t *tarFI) Size() int64 {
- return t.size
-}
-func (t *tarFI) Mode() os.FileMode {
- if t.isSymlink {
- return os.ModeSymlink
- }
- return 0444
-}
-func (t *tarFI) ModTime() time.Time {
- return time.Unix(0, 0)
-}
-func (t *tarFI) IsDir() bool {
- return false
-}
-func (t *tarFI) Sys() interface{} {
- return nil
-}
-
-// sendSymlink sends a symlink into the tar stream.
-func (d *Destination) sendSymlink(path string, target string) error {
- hdr, err := tar.FileInfoHeader(&tarFI{path: path, size: 0, isSymlink: true}, target)
- if err != nil {
- return nil
- }
- logrus.Debugf("Sending as tar link %s -> %s", path, target)
- return d.tar.WriteHeader(hdr)
-}
-
-// sendBytes sends a path into the tar stream.
-func (d *Destination) sendBytes(path string, b []byte) error {
- return d.sendFile(path, int64(len(b)), bytes.NewReader(b))
-}
-
-// sendFile sends a file into the tar stream.
-func (d *Destination) sendFile(path string, expectedSize int64, stream io.Reader) error {
- hdr, err := tar.FileInfoHeader(&tarFI{path: path, size: expectedSize}, "")
- if err != nil {
- return nil
- }
- logrus.Debugf("Sending as tar file %s", path)
- if err := d.tar.WriteHeader(hdr); err != nil {
- return err
- }
- // TODO: This can take quite some time, and should ideally be cancellable using a context.Context.
- size, err := io.Copy(d.tar, stream)
- if err != nil {
- return err
- }
- if size != expectedSize {
- return errors.Errorf("Size mismatch when copying %s, expected %d, got %d", path, expectedSize, size)
- }
- return nil
+ return d.internal.PutManifest(ctx, m, instanceDigest)
}
// PutSignatures would add the given signatures to the docker tarfile (currently not supported).
// The instanceDigest value is expected to always be nil, because this transport does not support manifest lists, so
// there can be no secondary manifests. MUST be called after PutManifest (signatures reference manifest contents).
func (d *Destination) PutSignatures(ctx context.Context, signatures [][]byte, instanceDigest *digest.Digest) error {
- if instanceDigest != nil {
- return errors.Errorf(`Manifest lists are not supported for docker tar files`)
- }
- if len(signatures) != 0 {
- return errors.Errorf("Storing signatures for docker tar files is not supported")
- }
- return nil
+ return d.internal.PutSignatures(ctx, signatures, instanceDigest)
}
// Commit finishes writing data to the underlying io.Writer.
// It is the caller's responsibility to close it, if necessary.
func (d *Destination) Commit(ctx context.Context) error {
- return d.tar.Close()
+ return d.archive.Close()
}
diff --git a/vendor/github.com/containers/image/v5/docker/tarfile/src.go b/vendor/github.com/containers/image/v5/docker/tarfile/src.go
index 4d2368c70..ee341eb39 100644
--- a/vendor/github.com/containers/image/v5/docker/tarfile/src.go
+++ b/vendor/github.com/containers/image/v5/docker/tarfile/src.go
@@ -1,51 +1,20 @@
package tarfile
import (
- "archive/tar"
- "bytes"
"context"
- "encoding/json"
"io"
- "io/ioutil"
- "os"
- "path"
- "sync"
- "github.com/containers/image/v5/internal/iolimits"
- "github.com/containers/image/v5/internal/tmpdir"
- "github.com/containers/image/v5/manifest"
- "github.com/containers/image/v5/pkg/compression"
+ internal "github.com/containers/image/v5/docker/internal/tarfile"
"github.com/containers/image/v5/types"
digest "github.com/opencontainers/go-digest"
- "github.com/pkg/errors"
)
// Source is a partial implementation of types.ImageSource for reading from tarPath.
+// Most users should use this via implementations of ImageReference from docker/archive or docker/daemon.
type Source struct {
- tarPath string
- removeTarPathOnClose bool // Remove temp file on close if true
- // The following data is only available after ensureCachedDataIsPresent() succeeds
- tarManifest *ManifestItem // nil if not available yet.
- configBytes []byte
- configDigest digest.Digest
- orderedDiffIDList []digest.Digest
- knownLayers map[digest.Digest]*layerInfo
- // Other state
- generatedManifest []byte // Private cache for GetManifest(), nil if not set yet.
- cacheDataLock sync.Once // Private state for ensureCachedDataIsPresent to make it concurrency-safe
- cacheDataResult error // Private state for ensureCachedDataIsPresent
+ internal *internal.Source
}
-type layerInfo struct {
- path string
- size int64
-}
-
-// TODO: We could add support for multiple images in a single archive, so
-// that people could use docker-archive:opensuse.tar:opensuse:leap as
-// the source of an image.
-// To do for both the NewSourceFromFile and NewSourceFromStream functions
-
// NewSourceFromFile returns a tarfile.Source for the specified path.
// Deprecated: Please use NewSourceFromFileWithContext which will allows you to configure temp directory
// for big files through SystemContext.BigFilesTemporaryDir
@@ -55,25 +24,12 @@ func NewSourceFromFile(path string) (*Source, error) {
// NewSourceFromFileWithContext returns a tarfile.Source for the specified path.
func NewSourceFromFileWithContext(sys *types.SystemContext, path string) (*Source, error) {
- file, err := os.Open(path)
- if err != nil {
- return nil, errors.Wrapf(err, "error opening file %q", path)
- }
- defer file.Close()
-
- // If the file is already not compressed we can just return the file itself
- // as a source. Otherwise we pass the stream to NewSourceFromStream.
- stream, isCompressed, err := compression.AutoDecompress(file)
+ archive, err := internal.NewReaderFromFile(sys, path)
if err != nil {
- return nil, errors.Wrapf(err, "Error detecting compression for file %q", path)
- }
- defer stream.Close()
- if !isCompressed {
- return &Source{
- tarPath: path,
- }, nil
+ return nil, err
}
- return NewSourceFromStreamWithSystemContext(sys, stream)
+ src := internal.NewSource(archive, true, nil, -1)
+ return &Source{internal: src}, nil
}
// NewSourceFromStream returns a tarfile.Source for the specified inputStream,
@@ -89,280 +45,22 @@ func NewSourceFromStream(inputStream io.Reader) (*Source, error) {
// which can be either compressed or uncompressed. The caller can close the
// inputStream immediately after NewSourceFromFile returns.
func NewSourceFromStreamWithSystemContext(sys *types.SystemContext, inputStream io.Reader) (*Source, error) {
- // FIXME: use SystemContext here.
- // Save inputStream to a temporary file
- tarCopyFile, err := ioutil.TempFile(tmpdir.TemporaryDirectoryForBigFiles(sys), "docker-tar")
- if err != nil {
- return nil, errors.Wrap(err, "error creating temporary file")
- }
- defer tarCopyFile.Close()
-
- succeeded := false
- defer func() {
- if !succeeded {
- os.Remove(tarCopyFile.Name())
- }
- }()
-
- // In order to be compatible with docker-load, we need to support
- // auto-decompression (it's also a nice quality-of-life thing to avoid
- // giving users really confusing "invalid tar header" errors).
- uncompressedStream, _, err := compression.AutoDecompress(inputStream)
- if err != nil {
- return nil, errors.Wrap(err, "Error auto-decompressing input")
- }
- defer uncompressedStream.Close()
-
- // Copy the plain archive to the temporary file.
- //
- // TODO: This can take quite some time, and should ideally be cancellable
- // using a context.Context.
- if _, err := io.Copy(tarCopyFile, uncompressedStream); err != nil {
- return nil, errors.Wrapf(err, "error copying contents to temporary file %q", tarCopyFile.Name())
- }
- succeeded = true
-
- return &Source{
- tarPath: tarCopyFile.Name(),
- removeTarPathOnClose: true,
- }, nil
-}
-
-// tarReadCloser is a way to close the backing file of a tar.Reader when the user no longer needs the tar component.
-type tarReadCloser struct {
- *tar.Reader
- backingFile *os.File
-}
-
-func (t *tarReadCloser) Close() error {
- return t.backingFile.Close()
-}
-
-// openTarComponent returns a ReadCloser for the specific file within the archive.
-// This is linear scan; we assume that the tar file will have a fairly small amount of files (~layers),
-// and that filesystem caching will make the repeated seeking over the (uncompressed) tarPath cheap enough.
-// The caller should call .Close() on the returned stream.
-func (s *Source) openTarComponent(componentPath string) (io.ReadCloser, error) {
- f, err := os.Open(s.tarPath)
- if err != nil {
- return nil, err
- }
- succeeded := false
- defer func() {
- if !succeeded {
- f.Close()
- }
- }()
-
- tarReader, header, err := findTarComponent(f, componentPath)
- if err != nil {
- return nil, err
- }
- if header == nil {
- return nil, os.ErrNotExist
- }
- if header.FileInfo().Mode()&os.ModeType == os.ModeSymlink { // FIXME: untested
- // We follow only one symlink; so no loops are possible.
- if _, err := f.Seek(0, io.SeekStart); err != nil {
- return nil, err
- }
- // The new path could easily point "outside" the archive, but we only compare it to existing tar headers without extracting the archive,
- // so we don't care.
- tarReader, header, err = findTarComponent(f, path.Join(path.Dir(componentPath), header.Linkname))
- if err != nil {
- return nil, err
- }
- if header == nil {
- return nil, os.ErrNotExist
- }
- }
-
- if !header.FileInfo().Mode().IsRegular() {
- return nil, errors.Errorf("Error reading tar archive component %s: not a regular file", header.Name)
- }
- succeeded = true
- return &tarReadCloser{Reader: tarReader, backingFile: f}, nil
-}
-
-// findTarComponent returns a header and a reader matching path within inputFile,
-// or (nil, nil, nil) if not found.
-func findTarComponent(inputFile io.Reader, path string) (*tar.Reader, *tar.Header, error) {
- t := tar.NewReader(inputFile)
- for {
- h, err := t.Next()
- if err == io.EOF {
- break
- }
- if err != nil {
- return nil, nil, err
- }
- if h.Name == path {
- return t, h, nil
- }
- }
- return nil, nil, nil
-}
-
-// readTarComponent returns full contents of componentPath.
-func (s *Source) readTarComponent(path string, limit int) ([]byte, error) {
- file, err := s.openTarComponent(path)
- if err != nil {
- return nil, errors.Wrapf(err, "Error loading tar component %s", path)
- }
- defer file.Close()
- bytes, err := iolimits.ReadAtMost(file, limit)
- if err != nil {
- return nil, err
- }
- return bytes, nil
-}
-
-// ensureCachedDataIsPresent loads data necessary for any of the public accessors.
-// It is safe to call this from multi-threaded code.
-func (s *Source) ensureCachedDataIsPresent() error {
- s.cacheDataLock.Do(func() {
- s.cacheDataResult = s.ensureCachedDataIsPresentPrivate()
- })
- return s.cacheDataResult
-}
-
-// ensureCachedDataIsPresentPrivate is a private implementation detail of ensureCachedDataIsPresent.
-// Call ensureCachedDataIsPresent instead.
-func (s *Source) ensureCachedDataIsPresentPrivate() error {
- // Read and parse manifest.json
- tarManifest, err := s.loadTarManifest()
- if err != nil {
- return err
- }
-
- // Check to make sure length is 1
- if len(tarManifest) != 1 {
- return errors.Errorf("Unexpected tar manifest.json: expected 1 item, got %d", len(tarManifest))
- }
-
- // Read and parse config.
- configBytes, err := s.readTarComponent(tarManifest[0].Config, iolimits.MaxConfigBodySize)
- if err != nil {
- return err
- }
- var parsedConfig manifest.Schema2Image // There's a lot of info there, but we only really care about layer DiffIDs.
- if err := json.Unmarshal(configBytes, &parsedConfig); err != nil {
- return errors.Wrapf(err, "Error decoding tar config %s", tarManifest[0].Config)
- }
- if parsedConfig.RootFS == nil {
- return errors.Errorf("Invalid image config (rootFS is not set): %s", tarManifest[0].Config)
- }
-
- knownLayers, err := s.prepareLayerData(&tarManifest[0], &parsedConfig)
- if err != nil {
- return err
- }
-
- // Success; commit.
- s.tarManifest = &tarManifest[0]
- s.configBytes = configBytes
- s.configDigest = digest.FromBytes(configBytes)
- s.orderedDiffIDList = parsedConfig.RootFS.DiffIDs
- s.knownLayers = knownLayers
- return nil
-}
-
-// loadTarManifest loads and decodes the manifest.json.
-func (s *Source) loadTarManifest() ([]ManifestItem, error) {
- // FIXME? Do we need to deal with the legacy format?
- bytes, err := s.readTarComponent(manifestFileName, iolimits.MaxTarFileManifestSize)
+ archive, err := internal.NewReaderFromStream(sys, inputStream)
if err != nil {
return nil, err
}
- var items []ManifestItem
- if err := json.Unmarshal(bytes, &items); err != nil {
- return nil, errors.Wrap(err, "Error decoding tar manifest.json")
- }
- return items, nil
+ src := internal.NewSource(archive, true, nil, -1)
+ return &Source{internal: src}, nil
}
// Close removes resources associated with an initialized Source, if any.
func (s *Source) Close() error {
- if s.removeTarPathOnClose {
- return os.Remove(s.tarPath)
- }
- return nil
+ return s.internal.Close()
}
// LoadTarManifest loads and decodes the manifest.json
func (s *Source) LoadTarManifest() ([]ManifestItem, error) {
- return s.loadTarManifest()
-}
-
-func (s *Source) prepareLayerData(tarManifest *ManifestItem, parsedConfig *manifest.Schema2Image) (map[digest.Digest]*layerInfo, error) {
- // Collect layer data available in manifest and config.
- if len(tarManifest.Layers) != len(parsedConfig.RootFS.DiffIDs) {
- return nil, errors.Errorf("Inconsistent layer count: %d in manifest, %d in config", len(tarManifest.Layers), len(parsedConfig.RootFS.DiffIDs))
- }
- knownLayers := map[digest.Digest]*layerInfo{}
- unknownLayerSizes := map[string]*layerInfo{} // Points into knownLayers, a "to do list" of items with unknown sizes.
- for i, diffID := range parsedConfig.RootFS.DiffIDs {
- if _, ok := knownLayers[diffID]; ok {
- // Apparently it really can happen that a single image contains the same layer diff more than once.
- // In that case, the diffID validation ensures that both layers truly are the same, and it should not matter
- // which of the tarManifest.Layers paths is used; (docker save) actually makes the duplicates symlinks to the original.
- continue
- }
- layerPath := tarManifest.Layers[i]
- if _, ok := unknownLayerSizes[layerPath]; ok {
- return nil, errors.Errorf("Layer tarfile %s used for two different DiffID values", layerPath)
- }
- li := &layerInfo{ // A new element in each iteration
- path: layerPath,
- size: -1,
- }
- knownLayers[diffID] = li
- unknownLayerSizes[layerPath] = li
- }
-
- // Scan the tar file to collect layer sizes.
- file, err := os.Open(s.tarPath)
- if err != nil {
- return nil, err
- }
- defer file.Close()
- t := tar.NewReader(file)
- for {
- h, err := t.Next()
- if err == io.EOF {
- break
- }
- if err != nil {
- return nil, err
- }
- if li, ok := unknownLayerSizes[h.Name]; ok {
- // Since GetBlob will decompress layers that are compressed we need
- // to do the decompression here as well, otherwise we will
- // incorrectly report the size. Pretty critical, since tools like
- // umoci always compress layer blobs. Obviously we only bother with
- // the slower method of checking if it's compressed.
- uncompressedStream, isCompressed, err := compression.AutoDecompress(t)
- if err != nil {
- return nil, errors.Wrapf(err, "Error auto-decompressing %s to determine its size", h.Name)
- }
- defer uncompressedStream.Close()
-
- uncompressedSize := h.Size
- if isCompressed {
- uncompressedSize, err = io.Copy(ioutil.Discard, uncompressedStream)
- if err != nil {
- return nil, errors.Wrapf(err, "Error reading %s to find its size", h.Name)
- }
- }
- li.size = uncompressedSize
- delete(unknownLayerSizes, h.Name)
- }
- }
- if len(unknownLayerSizes) != 0 {
- return nil, errors.Errorf("Some layer tarfiles are missing in the tarball") // This could do with a better error reporting, if this ever happened in practice.
- }
-
- return knownLayers, nil
+ return s.internal.TarManifest(), nil
}
// GetManifest returns the image's manifest along with its MIME type (which may be empty when it can't be determined but the manifest is available).
@@ -372,130 +70,26 @@ func (s *Source) prepareLayerData(tarManifest *ManifestItem, parsedConfig *manif
// This source implementation does not support manifest lists, so the passed-in instanceDigest should always be nil,
// as the primary manifest can not be a list, so there can be no secondary instances.
func (s *Source) GetManifest(ctx context.Context, instanceDigest *digest.Digest) ([]byte, string, error) {
- if instanceDigest != nil {
- // How did we even get here? GetManifest(ctx, nil) has returned a manifest.DockerV2Schema2MediaType.
- return nil, "", errors.New(`Manifest lists are not supported by "docker-daemon:"`)
- }
- if s.generatedManifest == nil {
- if err := s.ensureCachedDataIsPresent(); err != nil {
- return nil, "", err
- }
- m := manifest.Schema2{
- SchemaVersion: 2,
- MediaType: manifest.DockerV2Schema2MediaType,
- ConfigDescriptor: manifest.Schema2Descriptor{
- MediaType: manifest.DockerV2Schema2ConfigMediaType,
- Size: int64(len(s.configBytes)),
- Digest: s.configDigest,
- },
- LayersDescriptors: []manifest.Schema2Descriptor{},
- }
- for _, diffID := range s.orderedDiffIDList {
- li, ok := s.knownLayers[diffID]
- if !ok {
- return nil, "", errors.Errorf("Internal inconsistency: Information about layer %s missing", diffID)
- }
- m.LayersDescriptors = append(m.LayersDescriptors, manifest.Schema2Descriptor{
- Digest: diffID, // diffID is a digest of the uncompressed tarball
- MediaType: manifest.DockerV2Schema2LayerMediaType,
- Size: li.size,
- })
- }
- manifestBytes, err := json.Marshal(&m)
- if err != nil {
- return nil, "", err
- }
- s.generatedManifest = manifestBytes
- }
- return s.generatedManifest, manifest.DockerV2Schema2MediaType, nil
-}
-
-// uncompressedReadCloser is an io.ReadCloser that closes both the uncompressed stream and the underlying input.
-type uncompressedReadCloser struct {
- io.Reader
- underlyingCloser func() error
- uncompressedCloser func() error
-}
-
-func (r uncompressedReadCloser) Close() error {
- var res error
- if err := r.uncompressedCloser(); err != nil {
- res = err
- }
- if err := r.underlyingCloser(); err != nil && res == nil {
- res = err
- }
- return res
+ return s.internal.GetManifest(ctx, instanceDigest)
}
// HasThreadSafeGetBlob indicates whether GetBlob can be executed concurrently.
func (s *Source) HasThreadSafeGetBlob() bool {
- return true
+ return s.internal.HasThreadSafeGetBlob()
}
// GetBlob returns a stream for the specified blob, and the blob’s size (or -1 if unknown).
// The Digest field in BlobInfo is guaranteed to be provided, Size may be -1 and MediaType may be optionally provided.
// May update BlobInfoCache, preferably after it knows for certain that a blob truly exists at a specific location.
func (s *Source) GetBlob(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache) (io.ReadCloser, int64, error) {
- if err := s.ensureCachedDataIsPresent(); err != nil {
- return nil, 0, err
- }
-
- if info.Digest == s.configDigest { // FIXME? Implement a more general algorithm matching instead of assuming sha256.
- return ioutil.NopCloser(bytes.NewReader(s.configBytes)), int64(len(s.configBytes)), nil
- }
-
- if li, ok := s.knownLayers[info.Digest]; ok { // diffID is a digest of the uncompressed tarball,
- underlyingStream, err := s.openTarComponent(li.path)
- if err != nil {
- return nil, 0, err
- }
- closeUnderlyingStream := true
- defer func() {
- if closeUnderlyingStream {
- underlyingStream.Close()
- }
- }()
-
- // In order to handle the fact that digests != diffIDs (and thus that a
- // caller which is trying to verify the blob will run into problems),
- // we need to decompress blobs. This is a bit ugly, but it's a
- // consequence of making everything addressable by their DiffID rather
- // than by their digest...
- //
- // In particular, because the v2s2 manifest being generated uses
- // DiffIDs, any caller of GetBlob is going to be asking for DiffIDs of
- // layers not their _actual_ digest. The result is that copy/... will
- // be verifing a "digest" which is not the actual layer's digest (but
- // is instead the DiffID).
-
- uncompressedStream, _, err := compression.AutoDecompress(underlyingStream)
- if err != nil {
- return nil, 0, errors.Wrapf(err, "Error auto-decompressing blob %s", info.Digest)
- }
-
- newStream := uncompressedReadCloser{
- Reader: uncompressedStream,
- underlyingCloser: underlyingStream.Close,
- uncompressedCloser: uncompressedStream.Close,
- }
- closeUnderlyingStream = false
-
- return newStream, li.size, nil
- }
-
- return nil, 0, errors.Errorf("Unknown blob %s", info.Digest)
+ return s.internal.GetBlob(ctx, info, cache)
}
// GetSignatures returns the image's signatures. It may use a remote (= slow) service.
// This source implementation does not support manifest lists, so the passed-in instanceDigest should always be nil,
// as there can be no secondary manifests.
func (s *Source) GetSignatures(ctx context.Context, instanceDigest *digest.Digest) ([][]byte, error) {
- if instanceDigest != nil {
- // How did we even get here? GetManifest(ctx, nil) has returned a manifest.DockerV2Schema2MediaType.
- return nil, errors.Errorf(`Manifest lists are not supported by "docker-daemon:"`)
- }
- return [][]byte{}, nil
+ return s.internal.GetSignatures(ctx, instanceDigest)
}
// LayerInfosForCopy returns either nil (meaning the values in the manifest are fine), or updated values for the layer
@@ -505,6 +99,6 @@ func (s *Source) GetSignatures(ctx context.Context, instanceDigest *digest.Diges
// as the primary manifest can not be a list, so there can be no secondary manifests.
// The Digest field is guaranteed to be provided; Size may be -1.
// WARNING: The list may contain duplicates, and they are semantically relevant.
-func (s *Source) LayerInfosForCopy(context.Context, *digest.Digest) ([]types.BlobInfo, error) {
- return nil, nil
+func (s *Source) LayerInfosForCopy(ctx context.Context, instanceDigest *digest.Digest) ([]types.BlobInfo, error) {
+ return s.internal.LayerInfosForCopy(ctx, instanceDigest)
}
diff --git a/vendor/github.com/containers/image/v5/docker/tarfile/types.go b/vendor/github.com/containers/image/v5/docker/tarfile/types.go
index ac222528a..0f14389e6 100644
--- a/vendor/github.com/containers/image/v5/docker/tarfile/types.go
+++ b/vendor/github.com/containers/image/v5/docker/tarfile/types.go
@@ -1,28 +1,8 @@
package tarfile
import (
- "github.com/containers/image/v5/manifest"
- "github.com/opencontainers/go-digest"
-)
-
-// Various data structures.
-
-// Based on github.com/docker/docker/image/tarexport/tarexport.go
-const (
- manifestFileName = "manifest.json"
- legacyLayerFileName = "layer.tar"
- legacyConfigFileName = "json"
- legacyVersionFileName = "VERSION"
- legacyRepositoriesFileName = "repositories"
+ internal "github.com/containers/image/v5/docker/internal/tarfile"
)
// ManifestItem is an element of the array stored in the top-level manifest.json file.
-type ManifestItem struct {
- Config string
- RepoTags []string
- Layers []string
- Parent imageID `json:",omitempty"`
- LayerSources map[digest.Digest]manifest.Schema2Descriptor `json:",omitempty"`
-}
-
-type imageID string
+type ManifestItem = internal.ManifestItem // All public members from the internal package remain accessible.
diff --git a/vendor/github.com/containers/image/v5/oci/layout/oci_src.go b/vendor/github.com/containers/image/v5/oci/layout/oci_src.go
index f515203df..9925aeda7 100644
--- a/vendor/github.com/containers/image/v5/oci/layout/oci_src.go
+++ b/vendor/github.com/containers/image/v5/oci/layout/oci_src.go
@@ -141,6 +141,10 @@ func (s *ociImageSource) GetSignatures(ctx context.Context, instanceDigest *dige
}
func (s *ociImageSource) getExternalBlob(ctx context.Context, urls []string) (io.ReadCloser, int64, error) {
+ if len(urls) == 0 {
+ return nil, 0, errors.New("internal error: getExternalBlob called with no URLs")
+ }
+
errWrap := errors.New("failed fetching external blob from all urls")
for _, url := range urls {
diff --git a/vendor/github.com/containers/image/v5/pkg/docker/config/config.go b/vendor/github.com/containers/image/v5/pkg/docker/config/config.go
index ce85af18a..5d7598648 100644
--- a/vendor/github.com/containers/image/v5/pkg/docker/config/config.go
+++ b/vendor/github.com/containers/image/v5/pkg/docker/config/config.go
@@ -11,9 +11,9 @@ import (
"strings"
"github.com/containers/image/v5/types"
+ "github.com/containers/storage/pkg/homedir"
helperclient "github.com/docker/docker-credential-helpers/client"
"github.com/docker/docker-credential-helpers/credentials"
- "github.com/docker/docker/pkg/homedir"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -345,7 +345,7 @@ func modifyJSON(sys *types.SystemContext, editor func(auths *dockerConfigFile) (
return errors.Wrapf(err, "error marshaling JSON %q", path)
}
- if err = ioutil.WriteFile(path, newData, 0755); err != nil {
+ if err = ioutil.WriteFile(path, newData, 0600); err != nil {
return errors.Wrapf(err, "error writing to file %q", path)
}
}
diff --git a/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/system_registries_v2.go b/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/system_registries_v2.go
index 8ecb47de4..9a5712654 100644
--- a/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/system_registries_v2.go
+++ b/vendor/github.com/containers/image/v5/pkg/sysregistriesv2/system_registries_v2.go
@@ -338,55 +338,86 @@ func (config *V2RegistriesConf) postProcess() error {
}
// ConfigPath returns the path to the system-wide registry configuration file.
+// Deprecated: This API implies configuration is read from files, and that there is only one.
+// Please use ConfigurationSourceDescription to obtain a string usable for error messages.
func ConfigPath(ctx *types.SystemContext) string {
- if ctx != nil && ctx.SystemRegistriesConfPath != "" {
- return ctx.SystemRegistriesConfPath
- }
-
- userRegistriesFilePath := filepath.Join(homedir.Get(), userRegistriesFile)
- if _, err := os.Stat(userRegistriesFilePath); err == nil {
- return userRegistriesFilePath
- }
-
- if ctx != nil && ctx.RootForImplicitAbsolutePaths != "" {
- return filepath.Join(ctx.RootForImplicitAbsolutePaths, systemRegistriesConfPath)
- }
-
- return systemRegistriesConfPath
+ return newConfigWrapper(ctx).configPath
}
-// ConfigDirPath returns the path to the system-wide directory for drop-in
+// ConfigDirPath returns the path to the directory for drop-in
// registry configuration files.
+// Deprecated: This API implies configuration is read from directories, and that there is only one.
+// Please use ConfigurationSourceDescription to obtain a string usable for error messages.
func ConfigDirPath(ctx *types.SystemContext) string {
- if ctx != nil && ctx.SystemRegistriesConfDirPath != "" {
- return ctx.SystemRegistriesConfDirPath
+ configWrapper := newConfigWrapper(ctx)
+ if configWrapper.userConfigDirPath != "" {
+ return configWrapper.userConfigDirPath
}
-
- userRegistriesDirPath := filepath.Join(homedir.Get(), userRegistriesDir)
- if _, err := os.Stat(userRegistriesDirPath); err == nil {
- return userRegistriesDirPath
- }
-
- if ctx != nil && ctx.RootForImplicitAbsolutePaths != "" {
- return filepath.Join(ctx.RootForImplicitAbsolutePaths, systemRegistriesConfDirPath)
- }
-
- return systemRegistriesConfDirPath
+ return configWrapper.configDirPath
}
// configWrapper is used to store the paths from ConfigPath and ConfigDirPath
// and acts as a key to the internal cache.
type configWrapper struct {
- configPath string
+ // path to the registries.conf file
+ configPath string
+ // path to system-wide registries.conf.d directory, or "" if not used
configDirPath string
+ // path to user specificed registries.conf.d directory, or "" if not used
+ userConfigDirPath string
}
// newConfigWrapper returns a configWrapper for the specified SystemContext.
func newConfigWrapper(ctx *types.SystemContext) configWrapper {
- return configWrapper{
- configPath: ConfigPath(ctx),
- configDirPath: ConfigDirPath(ctx),
+ var wrapper configWrapper
+ userRegistriesFilePath := filepath.Join(homedir.Get(), userRegistriesFile)
+ userRegistriesDirPath := filepath.Join(homedir.Get(), userRegistriesDir)
+
+ // decide configPath using per-user path or system file
+ if ctx != nil && ctx.SystemRegistriesConfPath != "" {
+ wrapper.configPath = ctx.SystemRegistriesConfPath
+ } else if _, err := os.Stat(userRegistriesFilePath); err == nil {
+ // per-user registries.conf exists, not reading system dir
+ // return config dirs from ctx or per-user one
+ wrapper.configPath = userRegistriesFilePath
+ if ctx != nil && ctx.SystemRegistriesConfDirPath != "" {
+ wrapper.configDirPath = ctx.SystemRegistriesConfDirPath
+ } else {
+ wrapper.userConfigDirPath = userRegistriesDirPath
+ }
+ return wrapper
+ } else if ctx != nil && ctx.RootForImplicitAbsolutePaths != "" {
+ wrapper.configPath = filepath.Join(ctx.RootForImplicitAbsolutePaths, systemRegistriesConfPath)
+ } else {
+ wrapper.configPath = systemRegistriesConfPath
+ }
+
+ // potentially use both system and per-user dirs if not using per-user config file
+ if ctx != nil && ctx.SystemRegistriesConfDirPath != "" {
+ // dir explicitly chosen: use only that one
+ wrapper.configDirPath = ctx.SystemRegistriesConfDirPath
+ } else if ctx != nil && ctx.RootForImplicitAbsolutePaths != "" {
+ wrapper.configDirPath = filepath.Join(ctx.RootForImplicitAbsolutePaths, systemRegistriesConfDirPath)
+ wrapper.userConfigDirPath = userRegistriesDirPath
+ } else {
+ wrapper.configDirPath = systemRegistriesConfDirPath
+ wrapper.userConfigDirPath = userRegistriesDirPath
}
+
+ return wrapper
+}
+
+// ConfigurationSourceDescription returns a string containres paths of registries.conf and registries.conf.d
+func ConfigurationSourceDescription(ctx *types.SystemContext) string {
+ wrapper := newConfigWrapper(ctx)
+ configSources := []string{wrapper.configPath}
+ if wrapper.configDirPath != "" {
+ configSources = append(configSources, wrapper.configDirPath)
+ }
+ if wrapper.userConfigDirPath != "" {
+ configSources = append(configSources, wrapper.userConfigDirPath)
+ }
+ return strings.Join(configSources, ", ")
}
// configMutex is used to synchronize concurrent accesses to configCache.
@@ -422,39 +453,49 @@ func getConfig(ctx *types.SystemContext) (*V2RegistriesConf, error) {
// dropInConfigs returns a slice of drop-in-configs from the registries.conf.d
// directory.
func dropInConfigs(wrapper configWrapper) ([]string, error) {
- var configs []string
-
- err := filepath.Walk(wrapper.configDirPath,
- // WalkFunc to read additional configs
- func(path string, info os.FileInfo, err error) error {
- switch {
- case err != nil:
- // return error (could be a permission problem)
- return err
- case info == nil:
- // this should only happen when err != nil but let's be sure
- return nil
- case info.IsDir():
- if path != wrapper.configDirPath {
- // make sure to not recurse into sub-directories
- return filepath.SkipDir
- }
- // ignore directories
- return nil
- default:
- // only add *.conf files
- if strings.HasSuffix(path, ".conf") {
- configs = append(configs, path)
- }
- return nil
- }
- },
+ var (
+ configs []string
+ dirPaths []string
)
+ if wrapper.configDirPath != "" {
+ dirPaths = append(dirPaths, wrapper.configDirPath)
+ }
+ if wrapper.userConfigDirPath != "" {
+ dirPaths = append(dirPaths, wrapper.userConfigDirPath)
+ }
+ for _, dirPath := range dirPaths {
+ err := filepath.Walk(dirPath,
+ // WalkFunc to read additional configs
+ func(path string, info os.FileInfo, err error) error {
+ switch {
+ case err != nil:
+ // return error (could be a permission problem)
+ return err
+ case info == nil:
+ // this should only happen when err != nil but let's be sure
+ return nil
+ case info.IsDir():
+ if path != dirPath {
+ // make sure to not recurse into sub-directories
+ return filepath.SkipDir
+ }
+ // ignore directories
+ return nil
+ default:
+ // only add *.conf files
+ if strings.HasSuffix(path, ".conf") {
+ configs = append(configs, path)
+ }
+ return nil
+ }
+ },
+ )
- if err != nil && !os.IsNotExist(err) {
- // Ignore IsNotExist errors: most systems won't have a registries.conf.d
- // directory.
- return nil, errors.Wrapf(err, "error reading registries.conf.d")
+ if err != nil && !os.IsNotExist(err) {
+ // Ignore IsNotExist errors: most systems won't have a registries.conf.d
+ // directory.
+ return nil, errors.Wrapf(err, "error reading registries.conf.d")
+ }
}
return configs, nil
diff --git a/vendor/github.com/containers/image/v5/version/version.go b/vendor/github.com/containers/image/v5/version/version.go
index 2f56effae..f4f902386 100644
--- a/vendor/github.com/containers/image/v5/version/version.go
+++ b/vendor/github.com/containers/image/v5/version/version.go
@@ -11,7 +11,7 @@ const (
VersionPatch = 2
// VersionDev indicates development branch. Releases will be empty string.
- VersionDev = ""
+ VersionDev = "-dev"
)
// Version is the specification version that the package types support.
diff --git a/vendor/github.com/containers/storage/VERSION b/vendor/github.com/containers/storage/VERSION
index 14bee92c9..ca8ec414e 100644
--- a/vendor/github.com/containers/storage/VERSION
+++ b/vendor/github.com/containers/storage/VERSION
@@ -1 +1 @@
-1.23.2
+1.23.5
diff --git a/vendor/github.com/containers/storage/go.mod b/vendor/github.com/containers/storage/go.mod
index 77eef7598..39db66641 100644
--- a/vendor/github.com/containers/storage/go.mod
+++ b/vendor/github.com/containers/storage/go.mod
@@ -8,10 +8,11 @@ require (
github.com/Microsoft/hcsshim v0.8.9
github.com/docker/go-units v0.4.0
github.com/hashicorp/go-multierror v1.1.0
- github.com/klauspost/compress v1.10.11
- github.com/klauspost/pgzip v1.2.4
+ github.com/klauspost/compress v1.11.0
+ github.com/klauspost/pgzip v1.2.5
github.com/mattn/go-shellwords v1.0.10
github.com/mistifyio/go-zfs v2.1.1+incompatible
+ github.com/moby/sys/mountinfo v0.1.3
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/runc v1.0.0-rc91
github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2
diff --git a/vendor/github.com/containers/storage/go.sum b/vendor/github.com/containers/storage/go.sum
index 04d48eb4f..d1fb711b1 100644
--- a/vendor/github.com/containers/storage/go.sum
+++ b/vendor/github.com/containers/storage/go.sum
@@ -62,10 +62,10 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/compress v1.10.11 h1:K9z59aO18Aywg2b/WSgBaUX99mHy2BES18Cr5lBKZHk=
-github.com/klauspost/compress v1.10.11/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
-github.com/klauspost/pgzip v1.2.4 h1:TQ7CNpYKovDOmqzRHKxJh0BeaBI7UdQZYc6p7pMQh1A=
-github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
+github.com/klauspost/compress v1.11.0 h1:wJbzvpYMVGG9iTI9VxpnNZfd4DzMPoCWze3GgSqz8yg=
+github.com/klauspost/compress v1.11.0/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
+github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
diff --git a/vendor/github.com/containers/storage/layers.go b/vendor/github.com/containers/storage/layers.go
index dc21f75fd..52577299c 100644
--- a/vendor/github.com/containers/storage/layers.go
+++ b/vendor/github.com/containers/storage/layers.go
@@ -1342,6 +1342,7 @@ func (r *layerStore) ApplyDiff(to string, diff io.Reader) (size int64, err error
if err != nil {
return -1, err
}
+ defer idLogger.Close()
payload, err := asm.NewInputTarStream(io.TeeReader(uncompressed, io.MultiWriter(uncompressedCounter, idLogger)), metadata, storage.NewDiscardFilePutter())
if err != nil {
return -1, err
@@ -1356,7 +1357,6 @@ func (r *layerStore) ApplyDiff(to string, diff io.Reader) (size int64, err error
return -1, err
}
compressor.Close()
- idLogger.Close()
if err == nil {
if err := os.MkdirAll(filepath.Dir(r.tspath(layer.ID)), 0700); err != nil {
return -1, err
diff --git a/vendor/github.com/containers/storage/pkg/mount/mount.go b/vendor/github.com/containers/storage/pkg/mount/mount.go
index 4b888dceb..8273ab5a9 100644
--- a/vendor/github.com/containers/storage/pkg/mount/mount.go
+++ b/vendor/github.com/containers/storage/pkg/mount/mount.go
@@ -4,8 +4,6 @@ import (
"sort"
"strconv"
"strings"
-
- "github.com/containers/storage/pkg/fileutils"
)
// mountError holds an error from a mount or unmount operation
@@ -43,33 +41,6 @@ func (e *mountError) Cause() error {
return e.err
}
-// GetMounts retrieves a list of mounts for the current running process.
-func GetMounts() ([]*Info, error) {
- return parseMountTable()
-}
-
-// Mounted determines if a specified mountpoint has been mounted.
-// On Linux it looks at /proc/self/mountinfo and on Solaris at mnttab.
-func Mounted(mountpoint string) (bool, error) {
- entries, err := parseMountTable()
- if err != nil {
- return false, err
- }
-
- mountpoint, err = fileutils.ReadSymlinkedPath(mountpoint)
- if err != nil {
- return false, err
- }
-
- // Search the table for the mountpoint
- for _, e := range entries {
- if e.Mountpoint == mountpoint {
- return true, nil
- }
- }
- return false, nil
-}
-
// Mount will mount filesystem according to the specified configuration, on the
// condition that the target path is *not* already mounted. Options must be
// specified like the mount or fstab unix commands: "opt1=val1,opt2=val2". See
diff --git a/vendor/github.com/containers/storage/pkg/mount/mountinfo.go b/vendor/github.com/containers/storage/pkg/mount/mountinfo.go
index e3fc3535e..efc6c406e 100644
--- a/vendor/github.com/containers/storage/pkg/mount/mountinfo.go
+++ b/vendor/github.com/containers/storage/pkg/mount/mountinfo.go
@@ -1,40 +1,21 @@
package mount
-// Info reveals information about a particular mounted filesystem. This
-// struct is populated from the content in the /proc/<pid>/mountinfo file.
-type Info struct {
- // ID is a unique identifier of the mount (may be reused after umount).
- ID int
+import (
+ "github.com/containers/storage/pkg/fileutils"
+ "github.com/moby/sys/mountinfo"
+)
- // Parent indicates the ID of the mount parent (or of self for the top of the
- // mount tree).
- Parent int
+type Info = mountinfo.Info
- // Major indicates one half of the device ID which identifies the device class.
- Major int
-
- // Minor indicates one half of the device ID which identifies a specific
- // instance of device.
- Minor int
-
- // Root of the mount within the filesystem.
- Root string
-
- // Mountpoint indicates the mount point relative to the process's root.
- Mountpoint string
-
- // Opts represents mount-specific options.
- Opts string
-
- // Optional represents optional fields.
- Optional string
-
- // Fstype indicates the type of filesystem, such as EXT3.
- Fstype string
-
- // Source indicates filesystem specific information or "none".
- Source string
+func GetMounts() ([]*Info, error) {
+ return mountinfo.GetMounts(nil)
+}
- // VfsOpts represents per super block options.
- VfsOpts string
+// Mounted determines if a specified mountpoint has been mounted.
+func Mounted(mountpoint string) (bool, error) {
+ mountpoint, err := fileutils.ReadSymlinkedPath(mountpoint)
+ if err != nil {
+ return false, err
+ }
+ return mountinfo.Mounted(mountpoint)
}
diff --git a/vendor/github.com/containers/storage/pkg/mount/mountinfo_linux.go b/vendor/github.com/containers/storage/pkg/mount/mountinfo_linux.go
index 19556d06b..cbc0299fb 100644
--- a/vendor/github.com/containers/storage/pkg/mount/mountinfo_linux.go
+++ b/vendor/github.com/containers/storage/pkg/mount/mountinfo_linux.go
@@ -1,120 +1,5 @@
package mount
-import (
- "bufio"
- "fmt"
- "io"
- "os"
- "strconv"
- "strings"
+import "github.com/moby/sys/mountinfo"
- "github.com/pkg/errors"
-)
-
-// Parse /proc/self/mountinfo because comparing Dev and ino does not work from
-// bind mounts
-func parseMountTable() ([]*Info, error) {
- f, err := os.Open("/proc/self/mountinfo")
- if err != nil {
- return nil, err
- }
- defer f.Close()
-
- return parseInfoFile(f)
-}
-
-func parseInfoFile(r io.Reader) ([]*Info, error) {
- s := bufio.NewScanner(r)
- out := []*Info{}
-
- for s.Scan() {
- /*
- 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
- (0)(1)(2) (3) (4) (5) (6) (7) (8) (9) (10)
-
- (0) mount ID: unique identifier of the mount (may be reused after umount)
- (1) parent ID: ID of parent (or of self for the top of the mount tree)
- (2) major:minor: value of st_dev for files on filesystem
- (3) root: root of the mount within the filesystem
- (4) mount point: mount point relative to the process's root
- (5) mount options: per mount options
- (6) optional fields: zero or more fields of the form "tag[:value]"
- (7) separator: marks the end of the optional fields
- (8) filesystem type: name of filesystem of the form "type[.subtype]"
- (9) mount source: filesystem specific information or "none"
- (10) super options: per super block options
- */
- text := s.Text()
- fields := strings.Split(text, " ")
- numFields := len(fields)
- if numFields < 10 {
- // should be at least 10 fields
- return nil, errors.Errorf("Parsing %q failed: not enough fields (%d)", text, numFields)
- }
-
- p := &Info{}
- // ignore any number parsing errors, there should not be any
- p.ID, _ = strconv.Atoi(fields[0])
- p.Parent, _ = strconv.Atoi(fields[1])
- mm := strings.Split(fields[2], ":")
- if len(mm) != 2 {
- return nil, fmt.Errorf("Parsing %q failed: unexpected minor:major pair %s", text, mm)
- }
- p.Major, _ = strconv.Atoi(mm[0])
- p.Minor, _ = strconv.Atoi(mm[1])
- p.Root = fields[3]
- p.Mountpoint = fields[4]
- p.Opts = fields[5]
-
- // one or more optional fields, when a separator (-)
- i := 6
- for ; i < numFields && fields[i] != "-"; i++ {
- switch i {
- case 6:
- p.Optional = string(fields[6])
- default:
- /* NOTE there might be more optional fields before the separator,
- such as fields[7] or fields[8], although as of Linux kernel 5.5
- the only known ones are mount propagation flags in fields[6].
- The correct behavior is to ignore any unknown optional fields.
- */
- }
- }
- if i == numFields {
- return nil, fmt.Errorf("Parsing %q failed: missing - separator", text)
- }
-
- // There should be 3 fields after the separator...
- if i+4 > numFields {
- return nil, fmt.Errorf("Parsing %q failed: not enough fields after a - separator", text)
- }
- // ... but in Linux <= 3.9 mounting a cifs with spaces in a share name
- // (like "//serv/My Documents") _may_ end up having a space in the last field
- // of mountinfo (like "unc=//serv/My Documents"). Since kernel 3.10-rc1, cifs
- // option unc= is ignored, so a space should not appear. In here we ignore
- // those "extra" fields caused by extra spaces.
- p.Fstype = fields[i+1]
- p.Source = fields[i+2]
- p.VfsOpts = fields[i+3]
-
- out = append(out, p)
- }
- if err := s.Err(); err != nil {
- return nil, err
- }
-
- return out, nil
-}
-
-// PidMountInfo collects the mounts for a specific process ID. If the process
-// ID is unknown, it is better to use `GetMounts` which will inspect
-// "/proc/self/mountinfo" instead.
-func PidMountInfo(pid int) ([]*Info, error) {
- f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid))
- if err != nil {
- return nil, err
- }
- defer f.Close()
-
- return parseInfoFile(f)
-}
+var PidMountInfo = mountinfo.PidMountInfo
diff --git a/vendor/github.com/containers/storage/pkg/mount/mountinfo_unsupported.go b/vendor/github.com/containers/storage/pkg/mount/mountinfo_unsupported.go
deleted file mode 100644
index 6cde1ed77..000000000
--- a/vendor/github.com/containers/storage/pkg/mount/mountinfo_unsupported.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// +build !linux
-
-package mount
-
-import (
- "fmt"
- "runtime"
-)
-
-func parseMountTable() ([]*Info, error) {
- return nil, fmt.Errorf("mount.parseMountTable is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
-}
diff --git a/vendor/github.com/containers/storage/utils.go b/vendor/github.com/containers/storage/utils.go
index d65d52718..b22263fe4 100644
--- a/vendor/github.com/containers/storage/utils.go
+++ b/vendor/github.com/containers/storage/utils.go
@@ -198,7 +198,7 @@ func getRootlessDirInfo(rootlessUID int) (string, string, error) {
}
// getRootlessStorageOpts returns the storage opts for containers running as non root
-func getRootlessStorageOpts(rootlessUID int) (StoreOptions, error) {
+func getRootlessStorageOpts(rootlessUID int, systemOpts StoreOptions) (StoreOptions, error) {
var opts StoreOptions
dataDir, rootlessRuntime, err := getRootlessDirInfo(rootlessUID)
@@ -207,10 +207,20 @@ func getRootlessStorageOpts(rootlessUID int) (StoreOptions, error) {
}
opts.RunRoot = rootlessRuntime
opts.GraphRoot = filepath.Join(dataDir, "containers", "storage")
- opts.RootlessStoragePath = opts.GraphRoot
+ if systemOpts.RootlessStoragePath != "" {
+ opts.RootlessStoragePath = systemOpts.RootlessStoragePath
+ } else {
+ opts.RootlessStoragePath = opts.GraphRoot
+ }
if path, err := exec.LookPath("fuse-overlayfs"); err == nil {
opts.GraphDriverName = "overlay"
opts.GraphDriverOptions = []string{fmt.Sprintf("overlay.mount_program=%s", path)}
+ for _, o := range systemOpts.GraphDriverOptions {
+ if strings.Contains(o, "ignore_chown_errors") {
+ opts.GraphDriverOptions = append(opts.GraphDriverOptions, o)
+ break
+ }
+ }
} else {
opts.GraphDriverName = "vfs"
}
@@ -242,7 +252,7 @@ func defaultStoreOptionsIsolated(rootless bool, rootlessUID int, storageConf str
)
storageOpts := defaultStoreOptions
if rootless && rootlessUID != 0 {
- storageOpts, err = getRootlessStorageOpts(rootlessUID)
+ storageOpts, err = getRootlessStorageOpts(rootlessUID, storageOpts)
if err != nil {
return storageOpts, err
}
diff --git a/vendor/github.com/imdario/mergo/README.md b/vendor/github.com/imdario/mergo/README.md
index 02fc81e06..876abb500 100644
--- a/vendor/github.com/imdario/mergo/README.md
+++ b/vendor/github.com/imdario/mergo/README.md
@@ -1,44 +1,54 @@
# Mergo
-A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements.
-
-Also a lovely [comune](http://en.wikipedia.org/wiki/Mergo) (municipality) in the Province of Ancona in the Italian region of Marche.
-
-## Status
-
-It is ready for production use. [It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, etc](https://github.com/imdario/mergo#mergo-in-the-wild).
[![GoDoc][3]][4]
-[![GoCard][5]][6]
+[![GitHub release][5]][6]
+[![GoCard][7]][8]
[![Build Status][1]][2]
-[![Coverage Status][7]][8]
-[![Sourcegraph][9]][10]
-[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fimdario%2Fmergo.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fimdario%2Fmergo?ref=badge_shield)
+[![Coverage Status][9]][10]
+[![Sourcegraph][11]][12]
+[![FOSSA Status][13]][14]
+
+[![GoCenter Kudos][15]][16]
[1]: https://travis-ci.org/imdario/mergo.png
[2]: https://travis-ci.org/imdario/mergo
[3]: https://godoc.org/github.com/imdario/mergo?status.svg
[4]: https://godoc.org/github.com/imdario/mergo
-[5]: https://goreportcard.com/badge/imdario/mergo
-[6]: https://goreportcard.com/report/github.com/imdario/mergo
-[7]: https://coveralls.io/repos/github/imdario/mergo/badge.svg?branch=master
-[8]: https://coveralls.io/github/imdario/mergo?branch=master
-[9]: https://sourcegraph.com/github.com/imdario/mergo/-/badge.svg
-[10]: https://sourcegraph.com/github.com/imdario/mergo?badge
+[5]: https://img.shields.io/github/release/imdario/mergo.svg
+[6]: https://github.com/imdario/mergo/releases
+[7]: https://goreportcard.com/badge/imdario/mergo
+[8]: https://goreportcard.com/report/github.com/imdario/mergo
+[9]: https://coveralls.io/repos/github/imdario/mergo/badge.svg?branch=master
+[10]: https://coveralls.io/github/imdario/mergo?branch=master
+[11]: https://sourcegraph.com/github.com/imdario/mergo/-/badge.svg
+[12]: https://sourcegraph.com/github.com/imdario/mergo?badge
+[13]: https://app.fossa.io/api/projects/git%2Bgithub.com%2Fimdario%2Fmergo.svg?type=shield
+[14]: https://app.fossa.io/projects/git%2Bgithub.com%2Fimdario%2Fmergo?ref=badge_shield
+[15]: https://search.gocenter.io/api/ui/badge/github.com%2Fimdario%2Fmergo
+[16]: https://search.gocenter.io/github.com/imdario/mergo
-### Latest release
+A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements.
-[Release v0.3.7](https://github.com/imdario/mergo/releases/tag/v0.3.7).
+Mergo merges same-type structs and maps by setting default values in zero-value fields. Mergo won't merge unexported (private) fields. It will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection).
+
+Also a lovely [comune](http://en.wikipedia.org/wiki/Mergo) (municipality) in the Province of Ancona in the Italian region of Marche.
+
+## Status
+
+It is ready for production use. [It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, etc](https://github.com/imdario/mergo#mergo-in-the-wild).
### Important note
-Please keep in mind that in [0.3.2](//github.com/imdario/mergo/releases/tag/0.3.2) Mergo changed `Merge()`and `Map()` signatures to support [transformers](#transformers). An optional/variadic argument has been added, so it won't break existing code.
+Please keep in mind that a problematic PR broke [0.3.9](//github.com/imdario/mergo/releases/tag/0.3.9). I reverted it in [0.3.10](//github.com/imdario/mergo/releases/tag/0.3.10), and I consider it stable but not bug-free. Also, this version adds suppot for go modules.
-If you were using Mergo **before** April 6th 2015, please check your project works as intended after updating your local copy with ```go get -u github.com/imdario/mergo```. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause (I hope it won't!) in existing projects after the change (release 0.2.0).
+Keep in mind that in [0.3.2](//github.com/imdario/mergo/releases/tag/0.3.2), Mergo changed `Merge()`and `Map()` signatures to support [transformers](#transformers). I added an optional/variadic argument so that it won't break the existing code.
+
+If you were using Mergo before April 6th, 2015, please check your project works as intended after updating your local copy with ```go get -u github.com/imdario/mergo```. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause in existing projects after the change (release 0.2.0).
### Donations
-If Mergo is useful to you, consider buying me a coffee, a beer or making a monthly donation so I can keep building great free software. :heart_eyes:
+If Mergo is useful to you, consider buying me a coffee, a beer, or making a monthly donation to allow me to keep building great free software. :heart_eyes:
<a href='https://ko-fi.com/B0B58839' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://az743702.vo.msecnd.net/cdn/kofi1.png?v=0' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
[![Beerpay](https://beerpay.io/imdario/mergo/badge.svg)](https://beerpay.io/imdario/mergo)
@@ -87,8 +97,9 @@ If Mergo is useful to you, consider buying me a coffee, a beer or making a month
- [mantasmatelis/whooplist-server](https://github.com/mantasmatelis/whooplist-server)
- [jnuthong/item_search](https://github.com/jnuthong/item_search)
- [bukalapak/snowboard](https://github.com/bukalapak/snowboard)
+- [janoszen/containerssh](https://github.com/janoszen/containerssh)
-## Installation
+## Install
go get github.com/imdario/mergo
@@ -99,7 +110,7 @@ If Mergo is useful to you, consider buying me a coffee, a beer or making a month
## Usage
-You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. It won't merge empty structs value as [they are not considered zero values](https://golang.org/ref/spec#The_zero_value) either. Also maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection).
+You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. It won't merge empty structs value as [they are zero values](https://golang.org/ref/spec#The_zero_value) too. Also, maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection).
```go
if err := mergo.Merge(&dst, src); err != nil {
@@ -125,9 +136,7 @@ if err := mergo.Map(&dst, srcMap); err != nil {
Warning: if you map a struct to map, it won't do it recursively. Don't expect Mergo to map struct members of your struct as `map[string]interface{}`. They will be just assigned as values.
-More information and examples in [godoc documentation](http://godoc.org/github.com/imdario/mergo).
-
-### Nice example
+Here is a nice example:
```go
package main
@@ -175,10 +184,10 @@ import (
"time"
)
-type timeTransfomer struct {
+type timeTransformer struct {
}
-func (t timeTransfomer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error {
+func (t timeTransformer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error {
if typ == reflect.TypeOf(time.Time{}) {
return func(dst, src reflect.Value) error {
if dst.CanSet() {
@@ -202,7 +211,7 @@ type Snapshot struct {
func main() {
src := Snapshot{time.Now()}
dest := Snapshot{}
- mergo.Merge(&dest, src, mergo.WithTransformers(timeTransfomer{}))
+ mergo.Merge(&dest, src, mergo.WithTransformers(timeTransformer{}))
fmt.Println(dest)
// Will print
// { 2018-01-12 01:15:00 +0000 UTC m=+0.000000001 }
diff --git a/vendor/github.com/imdario/mergo/doc.go b/vendor/github.com/imdario/mergo/doc.go
index 6e9aa7baf..fcd985f99 100644
--- a/vendor/github.com/imdario/mergo/doc.go
+++ b/vendor/github.com/imdario/mergo/doc.go
@@ -4,41 +4,140 @@
// license that can be found in the LICENSE file.
/*
-Package mergo merges same-type structs and maps by setting default values in zero-value fields.
+A helper to merge structs and maps in Golang. Useful for configuration default values, avoiding messy if-statements.
-Mergo won't merge unexported (private) fields but will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection).
+Mergo merges same-type structs and maps by setting default values in zero-value fields. Mergo won't merge unexported (private) fields. It will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection).
+
+Status
+
+It is ready for production use. It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, etc.
+
+Important note
+
+Please keep in mind that a problematic PR broke 0.3.9. We reverted it in 0.3.10. We consider 0.3.10 as stable but not bug-free. . Also, this version adds suppot for go modules.
+
+Keep in mind that in 0.3.2, Mergo changed Merge() and Map() signatures to support transformers. We added an optional/variadic argument so that it won't break the existing code.
+
+If you were using Mergo before April 6th, 2015, please check your project works as intended after updating your local copy with go get -u github.com/imdario/mergo. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause in existing projects after the change (release 0.2.0).
+
+Install
+
+Do your usual installation procedure:
+
+ go get github.com/imdario/mergo
+
+ // use in your .go code
+ import (
+ "github.com/imdario/mergo"
+ )
Usage
-From my own work-in-progress project:
+You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. It won't merge empty structs value as they are zero values too. Also, maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection).
+
+ if err := mergo.Merge(&dst, src); err != nil {
+ // ...
+ }
+
+Also, you can merge overwriting values using the transformer WithOverride.
+
+ if err := mergo.Merge(&dst, src, mergo.WithOverride); err != nil {
+ // ...
+ }
+
+Additionally, you can map a map[string]interface{} to a struct (and otherwise, from struct to map), following the same restrictions as in Merge(). Keys are capitalized to find each corresponding exported field.
+
+ if err := mergo.Map(&dst, srcMap); err != nil {
+ // ...
+ }
+
+Warning: if you map a struct to map, it won't do it recursively. Don't expect Mergo to map struct members of your struct as map[string]interface{}. They will be just assigned as values.
+
+Here is a nice example:
+
+ package main
+
+ import (
+ "fmt"
+ "github.com/imdario/mergo"
+ )
- type networkConfig struct {
- Protocol string
- Address string
- ServerType string `json: "server_type"`
- Port uint16
+ type Foo struct {
+ A string
+ B int64
}
- type FssnConfig struct {
- Network networkConfig
+ func main() {
+ src := Foo{
+ A: "one",
+ B: 2,
+ }
+ dest := Foo{
+ A: "two",
+ }
+ mergo.Merge(&dest, src)
+ fmt.Println(dest)
+ // Will print
+ // {two 2}
}
- var fssnDefault = FssnConfig {
- networkConfig {
- "tcp",
- "127.0.0.1",
- "http",
- 31560,
- },
+Transformers
+
+Transformers allow to merge specific types differently than in the default behavior. In other words, now you can customize how some types are merged. For example, time.Time is a struct; it doesn't have zero value but IsZero can return true because it has fields with zero value. How can we merge a non-zero time.Time?
+
+ package main
+
+ import (
+ "fmt"
+ "github.com/imdario/mergo"
+ "reflect"
+ "time"
+ )
+
+ type timeTransformer struct {
}
- // Inside a function [...]
+ func (t timeTransformer) Transformer(typ reflect.Type) func(dst, src reflect.Value) error {
+ if typ == reflect.TypeOf(time.Time{}) {
+ return func(dst, src reflect.Value) error {
+ if dst.CanSet() {
+ isZero := dst.MethodByName("IsZero")
+ result := isZero.Call([]reflect.Value{})
+ if result[0].Bool() {
+ dst.Set(src)
+ }
+ }
+ return nil
+ }
+ }
+ return nil
+ }
+
+ type Snapshot struct {
+ Time time.Time
+ // ...
+ }
- if err := mergo.Merge(&config, fssnDefault); err != nil {
- log.Fatal(err)
+ func main() {
+ src := Snapshot{time.Now()}
+ dest := Snapshot{}
+ mergo.Merge(&dest, src, mergo.WithTransformers(timeTransformer{}))
+ fmt.Println(dest)
+ // Will print
+ // { 2018-01-12 01:15:00 +0000 UTC m=+0.000000001 }
}
- // More code [...]
+Contact me
+
+If I can help you, you have an idea or you are using Mergo in your projects, don't hesitate to drop me a line (or a pull request): https://twitter.com/im_dario
+
+About
+
+Written by Dario Castañé: https://da.rio.hn
+
+License
+
+BSD 3-Clause license, as Go language.
*/
package mergo
diff --git a/vendor/github.com/imdario/mergo/go.mod b/vendor/github.com/imdario/mergo/go.mod
new file mode 100644
index 000000000..3d689d93e
--- /dev/null
+++ b/vendor/github.com/imdario/mergo/go.mod
@@ -0,0 +1,5 @@
+module github.com/imdario/mergo
+
+go 1.13
+
+require gopkg.in/yaml.v2 v2.3.0
diff --git a/vendor/github.com/imdario/mergo/go.sum b/vendor/github.com/imdario/mergo/go.sum
new file mode 100644
index 000000000..168980da5
--- /dev/null
+++ b/vendor/github.com/imdario/mergo/go.sum
@@ -0,0 +1,4 @@
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/vendor/github.com/imdario/mergo/map.go b/vendor/github.com/imdario/mergo/map.go
index d83258b4d..a13a7ee46 100644
--- a/vendor/github.com/imdario/mergo/map.go
+++ b/vendor/github.com/imdario/mergo/map.go
@@ -99,11 +99,11 @@ func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, conf
continue
}
if srcKind == dstKind {
- if _, err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
+ if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
return
}
} else if dstKind == reflect.Interface && dstElement.Kind() == reflect.Interface {
- if _, err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
+ if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
return
}
} else if srcKind == reflect.Map {
@@ -141,6 +141,9 @@ func MapWithOverwrite(dst, src interface{}, opts ...func(*Config)) error {
}
func _map(dst, src interface{}, opts ...func(*Config)) error {
+ if dst != nil && reflect.ValueOf(dst).Kind() != reflect.Ptr {
+ return ErrNonPointerAgument
+ }
var (
vDst, vSrc reflect.Value
err error
@@ -157,8 +160,7 @@ func _map(dst, src interface{}, opts ...func(*Config)) error {
// To be friction-less, we redirect equal-type arguments
// to deepMerge. Only because arguments can be anything.
if vSrc.Kind() == vDst.Kind() {
- _, err := deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
- return err
+ return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
}
switch vSrc.Kind() {
case reflect.Struct:
diff --git a/vendor/github.com/imdario/mergo/merge.go b/vendor/github.com/imdario/mergo/merge.go
index 3332c9c2a..afa84a1e2 100644
--- a/vendor/github.com/imdario/mergo/merge.go
+++ b/vendor/github.com/imdario/mergo/merge.go
@@ -11,26 +11,26 @@ package mergo
import (
"fmt"
"reflect"
- "unsafe"
)
-func hasExportedField(dst reflect.Value) (exported bool) {
+func hasMergeableFields(dst reflect.Value) (exported bool) {
for i, n := 0, dst.NumField(); i < n; i++ {
field := dst.Type().Field(i)
- if isExportedComponent(&field) {
- return true
+ if field.Anonymous && dst.Field(i).Kind() == reflect.Struct {
+ exported = exported || hasMergeableFields(dst.Field(i))
+ } else if isExportedComponent(&field) {
+ exported = exported || len(field.PkgPath) == 0
}
}
return
}
func isExportedComponent(field *reflect.StructField) bool {
- name := field.Name
pkgPath := field.PkgPath
if len(pkgPath) > 0 {
return false
}
- c := name[0]
+ c := field.Name[0]
if 'a' <= c && c <= 'z' || c == '_' {
return false
}
@@ -44,6 +44,8 @@ type Config struct {
Transformers Transformers
overwriteWithEmptyValue bool
overwriteSliceWithEmptyValue bool
+ sliceDeepCopy bool
+ debug bool
}
type Transformers interface {
@@ -53,17 +55,16 @@ type Transformers interface {
// Traverses recursively both values, assigning src's fields values to dst.
// The map argument tracks comparisons that have already been seen, which allows
// short circuiting on recursive types.
-func deepMerge(dstIn, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (dst reflect.Value, err error) {
- dst = dstIn
+func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) {
overwrite := config.Overwrite
typeCheck := config.TypeCheck
overwriteWithEmptySrc := config.overwriteWithEmptyValue
overwriteSliceWithEmptySrc := config.overwriteSliceWithEmptyValue
+ sliceDeepCopy := config.sliceDeepCopy
if !src.IsValid() {
return
}
-
if dst.CanAddr() {
addr := dst.UnsafeAddr()
h := 17 * addr
@@ -71,7 +72,7 @@ func deepMerge(dstIn, src reflect.Value, visited map[uintptr]*visit, depth int,
typ := dst.Type()
for p := seen; p != nil; p = p.next {
if p.ptr == addr && p.typ == typ {
- return dst, nil
+ return nil
}
}
// Remember, remember...
@@ -85,126 +86,154 @@ func deepMerge(dstIn, src reflect.Value, visited map[uintptr]*visit, depth int,
}
}
- if dst.IsValid() && src.IsValid() && src.Type() != dst.Type() {
- err = fmt.Errorf("cannot append two different types (%s, %s)", src.Kind(), dst.Kind())
- return
- }
-
switch dst.Kind() {
case reflect.Struct:
- if hasExportedField(dst) {
- dstCp := reflect.New(dst.Type()).Elem()
+ if hasMergeableFields(dst) {
for i, n := 0, dst.NumField(); i < n; i++ {
- dstField := dst.Field(i)
- structField := dst.Type().Field(i)
- // copy un-exported struct fields
- if !isExportedComponent(&structField) {
- rf := dstCp.Field(i)
- rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem() //nolint:gosec
- dstRF := dst.Field(i)
- if !dst.Field(i).CanAddr() {
- continue
- }
-
- dstRF = reflect.NewAt(dstRF.Type(), unsafe.Pointer(dstRF.UnsafeAddr())).Elem() //nolint:gosec
- rf.Set(dstRF)
- continue
- }
- dstField, err = deepMerge(dstField, src.Field(i), visited, depth+1, config)
- if err != nil {
+ if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, config); err != nil {
return
}
- dstCp.Field(i).Set(dstField)
}
-
- if dst.CanSet() {
- dst.Set(dstCp)
- } else {
- dst = dstCp
- }
- return
} else {
if (isReflectNil(dst) || overwrite) && (!isEmptyValue(src) || overwriteWithEmptySrc) {
- dst = src
+ dst.Set(src)
}
}
-
case reflect.Map:
if dst.IsNil() && !src.IsNil() {
- if dst.CanSet() {
- dst.Set(reflect.MakeMap(dst.Type()))
- } else {
- dst = src
- return
+ dst.Set(reflect.MakeMap(dst.Type()))
+ }
+
+ if src.Kind() != reflect.Map {
+ if overwrite {
+ dst.Set(src)
}
+ return
}
+
for _, key := range src.MapKeys() {
srcElement := src.MapIndex(key)
- dstElement := dst.MapIndex(key)
if !srcElement.IsValid() {
continue
}
- if dst.MapIndex(key).IsValid() {
- k := dstElement.Interface()
- dstElement = reflect.ValueOf(k)
- }
- if isReflectNil(srcElement) {
- if overwrite || isReflectNil(dstElement) {
- dst.SetMapIndex(key, srcElement)
+ dstElement := dst.MapIndex(key)
+ switch srcElement.Kind() {
+ case reflect.Chan, reflect.Func, reflect.Map, reflect.Interface, reflect.Slice:
+ if srcElement.IsNil() {
+ if overwrite {
+ dst.SetMapIndex(key, srcElement)
+ }
+ continue
+ }
+ fallthrough
+ default:
+ if !srcElement.CanInterface() {
+ continue
+ }
+ switch reflect.TypeOf(srcElement.Interface()).Kind() {
+ case reflect.Struct:
+ fallthrough
+ case reflect.Ptr:
+ fallthrough
+ case reflect.Map:
+ srcMapElm := srcElement
+ dstMapElm := dstElement
+ if srcMapElm.CanInterface() {
+ srcMapElm = reflect.ValueOf(srcMapElm.Interface())
+ if dstMapElm.IsValid() {
+ dstMapElm = reflect.ValueOf(dstMapElm.Interface())
+ }
+ }
+ if err = deepMerge(dstMapElm, srcMapElm, visited, depth+1, config); err != nil {
+ return
+ }
+ case reflect.Slice:
+ srcSlice := reflect.ValueOf(srcElement.Interface())
+
+ var dstSlice reflect.Value
+ if !dstElement.IsValid() || dstElement.IsNil() {
+ dstSlice = reflect.MakeSlice(srcSlice.Type(), 0, srcSlice.Len())
+ } else {
+ dstSlice = reflect.ValueOf(dstElement.Interface())
+ }
+
+ if (!isEmptyValue(src) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice && !sliceDeepCopy {
+ if typeCheck && srcSlice.Type() != dstSlice.Type() {
+ return fmt.Errorf("cannot override two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
+ }
+ dstSlice = srcSlice
+ } else if config.AppendSlice {
+ if srcSlice.Type() != dstSlice.Type() {
+ return fmt.Errorf("cannot append two slices with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
+ }
+ dstSlice = reflect.AppendSlice(dstSlice, srcSlice)
+ } else if sliceDeepCopy {
+ i := 0
+ for ; i < srcSlice.Len() && i < dstSlice.Len(); i++ {
+ srcElement := srcSlice.Index(i)
+ dstElement := dstSlice.Index(i)
+
+ if srcElement.CanInterface() {
+ srcElement = reflect.ValueOf(srcElement.Interface())
+ }
+ if dstElement.CanInterface() {
+ dstElement = reflect.ValueOf(dstElement.Interface())
+ }
+
+ if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
+ return
+ }
+ }
+
+ }
+ dst.SetMapIndex(key, dstSlice)
}
- continue
}
- if !srcElement.CanInterface() {
+ if dstElement.IsValid() && !isEmptyValue(dstElement) && (reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Map || reflect.TypeOf(srcElement.Interface()).Kind() == reflect.Slice) {
continue
}
- if srcElement.CanInterface() {
- srcElement = reflect.ValueOf(srcElement.Interface())
- if dstElement.IsValid() {
- dstElement = reflect.ValueOf(dstElement.Interface())
+ if srcElement.IsValid() && ((srcElement.Kind() != reflect.Ptr && overwrite) || !dstElement.IsValid() || isEmptyValue(dstElement)) {
+ if dst.IsNil() {
+ dst.Set(reflect.MakeMap(dst.Type()))
}
+ dst.SetMapIndex(key, srcElement)
}
- dstElement, err = deepMerge(dstElement, srcElement, visited, depth+1, config)
- if err != nil {
- return
- }
- dst.SetMapIndex(key, dstElement)
-
}
case reflect.Slice:
- newSlice := dst
- if (!isEmptyValue(src) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
- if typeCheck && src.Type() != dst.Type() {
- return dst, fmt.Errorf("cannot override two slices with different type (%s, %s)", src.Type(), dst.Type())
- }
- newSlice = src
- } else if config.AppendSlice {
- if typeCheck && src.Type() != dst.Type() {
- err = fmt.Errorf("cannot append two slice with different type (%s, %s)", src.Type(), dst.Type())
- return
- }
- newSlice = reflect.AppendSlice(dst, src)
- }
- if dst.CanSet() {
- dst.Set(newSlice)
- } else {
- dst = newSlice
- }
- case reflect.Ptr, reflect.Interface:
- if isReflectNil(src) {
+ if !dst.CanSet() {
break
}
+ if (!isEmptyValue(src) || overwriteWithEmptySrc || overwriteSliceWithEmptySrc) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice && !sliceDeepCopy {
+ dst.Set(src)
+ } else if config.AppendSlice {
+ if src.Type() != dst.Type() {
+ return fmt.Errorf("cannot append two slice with different type (%s, %s)", src.Type(), dst.Type())
+ }
+ dst.Set(reflect.AppendSlice(dst, src))
+ } else if sliceDeepCopy {
+ for i := 0; i < src.Len() && i < dst.Len(); i++ {
+ srcElement := src.Index(i)
+ dstElement := dst.Index(i)
+ if srcElement.CanInterface() {
+ srcElement = reflect.ValueOf(srcElement.Interface())
+ }
+ if dstElement.CanInterface() {
+ dstElement = reflect.ValueOf(dstElement.Interface())
+ }
- if dst.Kind() != reflect.Ptr && src.Type().AssignableTo(dst.Type()) {
- if dst.IsNil() || overwrite {
- if overwrite || isEmptyValue(dst) {
- if dst.CanSet() {
- dst.Set(src)
- } else {
- dst = src
- }
+ if err = deepMerge(dstElement, srcElement, visited, depth+1, config); err != nil {
+ return
}
}
+ }
+ case reflect.Ptr:
+ fallthrough
+ case reflect.Interface:
+ if isReflectNil(src) {
+ if overwriteWithEmptySrc && dst.CanSet() && src.Type().AssignableTo(dst.Type()) {
+ dst.Set(src)
+ }
break
}
@@ -214,33 +243,35 @@ func deepMerge(dstIn, src reflect.Value, visited map[uintptr]*visit, depth int,
dst.Set(src)
}
} else if src.Kind() == reflect.Ptr {
- if dst, err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
+ if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
return
}
- dst = dst.Addr()
} else if dst.Elem().Type() == src.Type() {
- if dst, err = deepMerge(dst.Elem(), src, visited, depth+1, config); err != nil {
+ if err = deepMerge(dst.Elem(), src, visited, depth+1, config); err != nil {
return
}
} else {
- return dst, ErrDifferentArgumentsTypes
+ return ErrDifferentArgumentsTypes
}
break
}
+
if dst.IsNil() || overwrite {
- if (overwrite || isEmptyValue(dst)) && (overwriteWithEmptySrc || !isEmptyValue(src)) {
- if dst.CanSet() {
- dst.Set(src)
- } else {
- dst = src
- }
+ if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
+ dst.Set(src)
}
- } else if _, err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
- return
+ break
+ }
+
+ if dst.Elem().Kind() == src.Elem().Kind() {
+ if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
+ return
+ }
+ break
}
default:
- overwriteFull := (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst))
- if overwriteFull {
+ mustSet := (isEmptyValue(dst) || overwrite) && (!isEmptyValue(src) || overwriteWithEmptySrc)
+ if mustSet {
if dst.CanSet() {
dst.Set(src)
} else {
@@ -281,6 +312,7 @@ func WithOverride(config *Config) {
// WithOverwriteWithEmptyValue will make merge override non empty dst attributes with empty src attributes values.
func WithOverwriteWithEmptyValue(config *Config) {
+ config.Overwrite = true
config.overwriteWithEmptyValue = true
}
@@ -299,7 +331,16 @@ func WithTypeCheck(config *Config) {
config.TypeCheck = true
}
+// WithSliceDeepCopy will merge slice element one by one with Overwrite flag.
+func WithSliceDeepCopy(config *Config) {
+ config.sliceDeepCopy = true
+ config.Overwrite = true
+}
+
func merge(dst, src interface{}, opts ...func(*Config)) error {
+ if dst != nil && reflect.ValueOf(dst).Kind() != reflect.Ptr {
+ return ErrNonPointerAgument
+ }
var (
vDst, vSrc reflect.Value
err error
@@ -314,14 +355,10 @@ func merge(dst, src interface{}, opts ...func(*Config)) error {
if vDst, vSrc, err = resolveValues(dst, src); err != nil {
return err
}
- if !vDst.CanSet() {
- return fmt.Errorf("cannot set dst, needs reference")
- }
if vDst.Type() != vSrc.Type() {
return ErrDifferentArgumentsTypes
}
- _, err = deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
- return err
+ return deepMerge(vDst, vSrc, make(map[uintptr]*visit), 0, config)
}
// IsReflectNil is the reflect value provided nil
diff --git a/vendor/github.com/imdario/mergo/mergo.go b/vendor/github.com/imdario/mergo/mergo.go
index a82fea2fd..3cc926c7f 100644
--- a/vendor/github.com/imdario/mergo/mergo.go
+++ b/vendor/github.com/imdario/mergo/mergo.go
@@ -20,6 +20,7 @@ var (
ErrNotSupported = errors.New("only structs and maps are supported")
ErrExpectedMapAsDestination = errors.New("dst was expected to be a map")
ErrExpectedStructAsDestination = errors.New("dst was expected to be a struct")
+ ErrNonPointerAgument = errors.New("dst must be a pointer")
)
// During deepMerge, must keep track of checks that are
@@ -75,23 +76,3 @@ func resolveValues(dst, src interface{}) (vDst, vSrc reflect.Value, err error) {
}
return
}
-
-// Traverses recursively both values, assigning src's fields values to dst.
-// The map argument tracks comparisons that have already been seen, which allows
-// short circuiting on recursive types.
-func deeper(dst, src reflect.Value, visited map[uintptr]*visit, depth int) (err error) {
- if dst.CanAddr() {
- addr := dst.UnsafeAddr()
- h := 17 * addr
- seen := visited[h]
- typ := dst.Type()
- for p := seen; p != nil; p = p.next {
- if p.ptr == addr && p.typ == typ {
- return nil
- }
- }
- // Remember, remember...
- visited[h] = &visit{addr, typ, seen}
- }
- return // TODO refactor
-}
diff --git a/vendor/github.com/klauspost/compress/flate/fast_encoder.go b/vendor/github.com/klauspost/compress/flate/fast_encoder.go
index 6d4c1e98b..4a73e1bdd 100644
--- a/vendor/github.com/klauspost/compress/flate/fast_encoder.go
+++ b/vendor/github.com/klauspost/compress/flate/fast_encoder.go
@@ -127,7 +127,7 @@ func (e *fastGen) addBlock(src []byte) int32 {
// hash4 returns the hash of u to fit in a hash table with h bits.
// Preferably h should be a constant and should always be <32.
func hash4u(u uint32, h uint8) uint32 {
- return (u * prime4bytes) >> ((32 - h) & 31)
+ return (u * prime4bytes) >> ((32 - h) & reg8SizeMask32)
}
type tableEntryPrev struct {
@@ -138,25 +138,25 @@ type tableEntryPrev struct {
// hash4x64 returns the hash of the lowest 4 bytes of u to fit in a hash table with h bits.
// Preferably h should be a constant and should always be <32.
func hash4x64(u uint64, h uint8) uint32 {
- return (uint32(u) * prime4bytes) >> ((32 - h) & 31)
+ return (uint32(u) * prime4bytes) >> ((32 - h) & reg8SizeMask32)
}
// hash7 returns the hash of the lowest 7 bytes of u to fit in a hash table with h bits.
// Preferably h should be a constant and should always be <64.
func hash7(u uint64, h uint8) uint32 {
- return uint32(((u << (64 - 56)) * prime7bytes) >> ((64 - h) & 63))
+ return uint32(((u << (64 - 56)) * prime7bytes) >> ((64 - h) & reg8SizeMask64))
}
// hash8 returns the hash of u to fit in a hash table with h bits.
// Preferably h should be a constant and should always be <64.
func hash8(u uint64, h uint8) uint32 {
- return uint32((u * prime8bytes) >> ((64 - h) & 63))
+ return uint32((u * prime8bytes) >> ((64 - h) & reg8SizeMask64))
}
// hash6 returns the hash of the lowest 6 bytes of u to fit in a hash table with h bits.
// Preferably h should be a constant and should always be <64.
func hash6(u uint64, h uint8) uint32 {
- return uint32(((u << (64 - 48)) * prime6bytes) >> ((64 - h) & 63))
+ return uint32(((u << (64 - 48)) * prime6bytes) >> ((64 - h) & reg8SizeMask64))
}
// matchlen will return the match length between offsets and t in src.
diff --git a/vendor/github.com/klauspost/compress/flate/gen_inflate.go b/vendor/github.com/klauspost/compress/flate/gen_inflate.go
index c74a95fe7..b26d19ec2 100644
--- a/vendor/github.com/klauspost/compress/flate/gen_inflate.go
+++ b/vendor/github.com/klauspost/compress/flate/gen_inflate.go
@@ -85,7 +85,7 @@ readLiteral:
return
}
f.roffset++
- b |= uint32(c) << (nb & 31)
+ b |= uint32(c) << (nb & regSizeMaskUint32)
nb += 8
}
chunk := f.hl.chunks[b&(huffmanNumChunks-1)]
@@ -104,7 +104,7 @@ readLiteral:
f.err = CorruptInputError(f.roffset)
return
}
- f.b = b >> (n & 31)
+ f.b = b >> (n & regSizeMaskUint32)
f.nb = nb - n
v = int(chunk >> huffmanValueShift)
break
@@ -167,15 +167,15 @@ readLiteral:
return
}
}
- length += int(f.b & uint32(1<<n-1))
- f.b >>= n
+ length += int(f.b & uint32(1<<(n&regSizeMaskUint32)-1))
+ f.b >>= n & regSizeMaskUint32
f.nb -= n
}
- var dist int
+ var dist uint32
if f.hd == nil {
for f.nb < 5 {
- if err = moreBits(); err != nil {
+ if err = f.moreBits(); err != nil {
if debugDecode {
fmt.Println("morebits f.nb<5:", err)
}
@@ -183,17 +183,19 @@ readLiteral:
return
}
}
- dist = int(bits.Reverse8(uint8(f.b & 0x1F << 3)))
+ dist = uint32(bits.Reverse8(uint8(f.b & 0x1F << 3)))
f.b >>= 5
f.nb -= 5
} else {
- if dist, err = f.huffSym(f.hd); err != nil {
+ sym, err := f.huffSym(f.hd)
+ if err != nil {
if debugDecode {
fmt.Println("huffsym:", err)
}
f.err = err
return
}
+ dist = uint32(sym)
}
switch {
@@ -202,9 +204,9 @@ readLiteral:
case dist < maxNumDist:
nb := uint(dist-2) >> 1
// have 1 bit in bottom of dist, need nb more.
- extra := (dist & 1) << nb
+ extra := (dist & 1) << (nb & regSizeMaskUint32)
for f.nb < nb {
- if err = moreBits(); err != nil {
+ if err = f.moreBits(); err != nil {
if debugDecode {
fmt.Println("morebits f.nb<nb:", err)
}
@@ -212,10 +214,10 @@ readLiteral:
return
}
}
- extra |= int(f.b & uint32(1<<nb-1))
- f.b >>= nb
+ extra |= f.b & uint32(1<<(nb&regSizeMaskUint32)-1)
+ f.b >>= nb & regSizeMaskUint32
f.nb -= nb
- dist = 1<<(nb+1) + 1 + extra
+ dist = 1<<((nb+1)&regSizeMaskUint32) + 1 + extra
default:
if debugDecode {
fmt.Println("dist too big:", dist, maxNumDist)
@@ -225,7 +227,7 @@ readLiteral:
}
// No check on length; encoding can be prescient.
- if dist > f.dict.histSize() {
+ if dist > uint32(f.dict.histSize()) {
if debugDecode {
fmt.Println("dist > f.dict.histSize():", dist, f.dict.histSize())
}
@@ -233,7 +235,7 @@ readLiteral:
return
}
- f.copyLen, f.copyDist = length, dist
+ f.copyLen, f.copyDist = length, int(dist)
goto copyHistory
}
diff --git a/vendor/github.com/klauspost/compress/flate/huffman_bit_writer.go b/vendor/github.com/klauspost/compress/flate/huffman_bit_writer.go
index 53fe1d06e..208d66711 100644
--- a/vendor/github.com/klauspost/compress/flate/huffman_bit_writer.go
+++ b/vendor/github.com/klauspost/compress/flate/huffman_bit_writer.go
@@ -206,7 +206,7 @@ func (w *huffmanBitWriter) write(b []byte) {
}
func (w *huffmanBitWriter) writeBits(b int32, nb uint16) {
- w.bits |= uint64(b) << (w.nbits & 63)
+ w.bits |= uint64(b) << (w.nbits & reg16SizeMask64)
w.nbits += nb
if w.nbits >= 48 {
w.writeOutBits()
@@ -759,7 +759,7 @@ func (w *huffmanBitWriter) writeTokens(tokens []token, leCodes, oeCodes []hcode)
} else {
// inlined
c := lengths[lengthCode&31]
- w.bits |= uint64(c.code) << (w.nbits & 63)
+ w.bits |= uint64(c.code) << (w.nbits & reg16SizeMask64)
w.nbits += c.len
if w.nbits >= 48 {
w.writeOutBits()
@@ -779,7 +779,7 @@ func (w *huffmanBitWriter) writeTokens(tokens []token, leCodes, oeCodes []hcode)
} else {
// inlined
c := offs[offsetCode&31]
- w.bits |= uint64(c.code) << (w.nbits & 63)
+ w.bits |= uint64(c.code) << (w.nbits & reg16SizeMask64)
w.nbits += c.len
if w.nbits >= 48 {
w.writeOutBits()
@@ -878,7 +878,7 @@ func (w *huffmanBitWriter) writeBlockHuff(eof bool, input []byte, sync bool) {
for _, t := range input {
// Bitwriting inlined, ~30% speedup
c := encoding[t]
- w.bits |= uint64(c.code) << ((w.nbits) & 63)
+ w.bits |= uint64(c.code) << ((w.nbits) & reg16SizeMask64)
w.nbits += c.len
if w.nbits >= 48 {
bits := w.bits
diff --git a/vendor/github.com/klauspost/compress/flate/inflate.go b/vendor/github.com/klauspost/compress/flate/inflate.go
index 3e4259f15..189e9fe0b 100644
--- a/vendor/github.com/klauspost/compress/flate/inflate.go
+++ b/vendor/github.com/klauspost/compress/flate/inflate.go
@@ -522,8 +522,8 @@ func (f *decompressor) readHuffman() error {
return err
}
}
- rep += int(f.b & uint32(1<<nb-1))
- f.b >>= nb
+ rep += int(f.b & uint32(1<<(nb&regSizeMaskUint32)-1))
+ f.b >>= nb & regSizeMaskUint32
f.nb -= nb
if i+rep > n {
if debugDecode {
@@ -603,7 +603,7 @@ readLiteral:
return
}
f.roffset++
- b |= uint32(c) << (nb & 31)
+ b |= uint32(c) << (nb & regSizeMaskUint32)
nb += 8
}
chunk := f.hl.chunks[b&(huffmanNumChunks-1)]
@@ -622,7 +622,7 @@ readLiteral:
f.err = CorruptInputError(f.roffset)
return
}
- f.b = b >> (n & 31)
+ f.b = b >> (n & regSizeMaskUint32)
f.nb = nb - n
v = int(chunk >> huffmanValueShift)
break
@@ -685,12 +685,12 @@ readLiteral:
return
}
}
- length += int(f.b & uint32(1<<n-1))
- f.b >>= n
+ length += int(f.b & uint32(1<<(n&regSizeMaskUint32)-1))
+ f.b >>= n & regSizeMaskUint32
f.nb -= n
}
- var dist int
+ var dist uint32
if f.hd == nil {
for f.nb < 5 {
if err = f.moreBits(); err != nil {
@@ -701,17 +701,19 @@ readLiteral:
return
}
}
- dist = int(bits.Reverse8(uint8(f.b & 0x1F << 3)))
+ dist = uint32(bits.Reverse8(uint8(f.b & 0x1F << 3)))
f.b >>= 5
f.nb -= 5
} else {
- if dist, err = f.huffSym(f.hd); err != nil {
+ sym, err := f.huffSym(f.hd)
+ if err != nil {
if debugDecode {
fmt.Println("huffsym:", err)
}
f.err = err
return
}
+ dist = uint32(sym)
}
switch {
@@ -720,7 +722,7 @@ readLiteral:
case dist < maxNumDist:
nb := uint(dist-2) >> 1
// have 1 bit in bottom of dist, need nb more.
- extra := (dist & 1) << nb
+ extra := (dist & 1) << (nb & regSizeMaskUint32)
for f.nb < nb {
if err = f.moreBits(); err != nil {
if debugDecode {
@@ -730,10 +732,10 @@ readLiteral:
return
}
}
- extra |= int(f.b & uint32(1<<nb-1))
- f.b >>= nb
+ extra |= f.b & uint32(1<<(nb&regSizeMaskUint32)-1)
+ f.b >>= nb & regSizeMaskUint32
f.nb -= nb
- dist = 1<<(nb+1) + 1 + extra
+ dist = 1<<((nb+1)&regSizeMaskUint32) + 1 + extra
default:
if debugDecode {
fmt.Println("dist too big:", dist, maxNumDist)
@@ -743,7 +745,7 @@ readLiteral:
}
// No check on length; encoding can be prescient.
- if dist > f.dict.histSize() {
+ if dist > uint32(f.dict.histSize()) {
if debugDecode {
fmt.Println("dist > f.dict.histSize():", dist, f.dict.histSize())
}
@@ -751,7 +753,7 @@ readLiteral:
return
}
- f.copyLen, f.copyDist = length, dist
+ f.copyLen, f.copyDist = length, int(dist)
goto copyHistory
}
@@ -869,7 +871,7 @@ func (f *decompressor) moreBits() error {
return noEOF(err)
}
f.roffset++
- f.b |= uint32(c) << f.nb
+ f.b |= uint32(c) << (f.nb & regSizeMaskUint32)
f.nb += 8
return nil
}
@@ -894,7 +896,7 @@ func (f *decompressor) huffSym(h *huffmanDecoder) (int, error) {
return 0, noEOF(err)
}
f.roffset++
- b |= uint32(c) << (nb & 31)
+ b |= uint32(c) << (nb & regSizeMaskUint32)
nb += 8
}
chunk := h.chunks[b&(huffmanNumChunks-1)]
@@ -913,7 +915,7 @@ func (f *decompressor) huffSym(h *huffmanDecoder) (int, error) {
f.err = CorruptInputError(f.roffset)
return 0, f.err
}
- f.b = b >> (n & 31)
+ f.b = b >> (n & regSizeMaskUint32)
f.nb = nb - n
return int(chunk >> huffmanValueShift), nil
}
diff --git a/vendor/github.com/klauspost/compress/flate/inflate_gen.go b/vendor/github.com/klauspost/compress/flate/inflate_gen.go
index 397dc1b1a..9a92a1b30 100644
--- a/vendor/github.com/klauspost/compress/flate/inflate_gen.go
+++ b/vendor/github.com/klauspost/compress/flate/inflate_gen.go
@@ -63,7 +63,7 @@ readLiteral:
return
}
f.roffset++
- b |= uint32(c) << (nb & 31)
+ b |= uint32(c) << (nb & regSizeMaskUint32)
nb += 8
}
chunk := f.hl.chunks[b&(huffmanNumChunks-1)]
@@ -82,7 +82,7 @@ readLiteral:
f.err = CorruptInputError(f.roffset)
return
}
- f.b = b >> (n & 31)
+ f.b = b >> (n & regSizeMaskUint32)
f.nb = nb - n
v = int(chunk >> huffmanValueShift)
break
@@ -145,15 +145,15 @@ readLiteral:
return
}
}
- length += int(f.b & uint32(1<<n-1))
- f.b >>= n
+ length += int(f.b & uint32(1<<(n&regSizeMaskUint32)-1))
+ f.b >>= n & regSizeMaskUint32
f.nb -= n
}
- var dist int
+ var dist uint32
if f.hd == nil {
for f.nb < 5 {
- if err = moreBits(); err != nil {
+ if err = f.moreBits(); err != nil {
if debugDecode {
fmt.Println("morebits f.nb<5:", err)
}
@@ -161,17 +161,19 @@ readLiteral:
return
}
}
- dist = int(bits.Reverse8(uint8(f.b & 0x1F << 3)))
+ dist = uint32(bits.Reverse8(uint8(f.b & 0x1F << 3)))
f.b >>= 5
f.nb -= 5
} else {
- if dist, err = f.huffSym(f.hd); err != nil {
+ sym, err := f.huffSym(f.hd)
+ if err != nil {
if debugDecode {
fmt.Println("huffsym:", err)
}
f.err = err
return
}
+ dist = uint32(sym)
}
switch {
@@ -180,9 +182,9 @@ readLiteral:
case dist < maxNumDist:
nb := uint(dist-2) >> 1
// have 1 bit in bottom of dist, need nb more.
- extra := (dist & 1) << nb
+ extra := (dist & 1) << (nb & regSizeMaskUint32)
for f.nb < nb {
- if err = moreBits(); err != nil {
+ if err = f.moreBits(); err != nil {
if debugDecode {
fmt.Println("morebits f.nb<nb:", err)
}
@@ -190,10 +192,10 @@ readLiteral:
return
}
}
- extra |= int(f.b & uint32(1<<nb-1))
- f.b >>= nb
+ extra |= f.b & uint32(1<<(nb&regSizeMaskUint32)-1)
+ f.b >>= nb & regSizeMaskUint32
f.nb -= nb
- dist = 1<<(nb+1) + 1 + extra
+ dist = 1<<((nb+1)&regSizeMaskUint32) + 1 + extra
default:
if debugDecode {
fmt.Println("dist too big:", dist, maxNumDist)
@@ -203,7 +205,7 @@ readLiteral:
}
// No check on length; encoding can be prescient.
- if dist > f.dict.histSize() {
+ if dist > uint32(f.dict.histSize()) {
if debugDecode {
fmt.Println("dist > f.dict.histSize():", dist, f.dict.histSize())
}
@@ -211,7 +213,7 @@ readLiteral:
return
}
- f.copyLen, f.copyDist = length, dist
+ f.copyLen, f.copyDist = length, int(dist)
goto copyHistory
}
@@ -287,7 +289,7 @@ readLiteral:
return
}
f.roffset++
- b |= uint32(c) << (nb & 31)
+ b |= uint32(c) << (nb & regSizeMaskUint32)
nb += 8
}
chunk := f.hl.chunks[b&(huffmanNumChunks-1)]
@@ -306,7 +308,7 @@ readLiteral:
f.err = CorruptInputError(f.roffset)
return
}
- f.b = b >> (n & 31)
+ f.b = b >> (n & regSizeMaskUint32)
f.nb = nb - n
v = int(chunk >> huffmanValueShift)
break
@@ -369,15 +371,15 @@ readLiteral:
return
}
}
- length += int(f.b & uint32(1<<n-1))
- f.b >>= n
+ length += int(f.b & uint32(1<<(n&regSizeMaskUint32)-1))
+ f.b >>= n & regSizeMaskUint32
f.nb -= n
}
- var dist int
+ var dist uint32
if f.hd == nil {
for f.nb < 5 {
- if err = moreBits(); err != nil {
+ if err = f.moreBits(); err != nil {
if debugDecode {
fmt.Println("morebits f.nb<5:", err)
}
@@ -385,17 +387,19 @@ readLiteral:
return
}
}
- dist = int(bits.Reverse8(uint8(f.b & 0x1F << 3)))
+ dist = uint32(bits.Reverse8(uint8(f.b & 0x1F << 3)))
f.b >>= 5
f.nb -= 5
} else {
- if dist, err = f.huffSym(f.hd); err != nil {
+ sym, err := f.huffSym(f.hd)
+ if err != nil {
if debugDecode {
fmt.Println("huffsym:", err)
}
f.err = err
return
}
+ dist = uint32(sym)
}
switch {
@@ -404,9 +408,9 @@ readLiteral:
case dist < maxNumDist:
nb := uint(dist-2) >> 1
// have 1 bit in bottom of dist, need nb more.
- extra := (dist & 1) << nb
+ extra := (dist & 1) << (nb & regSizeMaskUint32)
for f.nb < nb {
- if err = moreBits(); err != nil {
+ if err = f.moreBits(); err != nil {
if debugDecode {
fmt.Println("morebits f.nb<nb:", err)
}
@@ -414,10 +418,10 @@ readLiteral:
return
}
}
- extra |= int(f.b & uint32(1<<nb-1))
- f.b >>= nb
+ extra |= f.b & uint32(1<<(nb&regSizeMaskUint32)-1)
+ f.b >>= nb & regSizeMaskUint32
f.nb -= nb
- dist = 1<<(nb+1) + 1 + extra
+ dist = 1<<((nb+1)&regSizeMaskUint32) + 1 + extra
default:
if debugDecode {
fmt.Println("dist too big:", dist, maxNumDist)
@@ -427,7 +431,7 @@ readLiteral:
}
// No check on length; encoding can be prescient.
- if dist > f.dict.histSize() {
+ if dist > uint32(f.dict.histSize()) {
if debugDecode {
fmt.Println("dist > f.dict.histSize():", dist, f.dict.histSize())
}
@@ -435,7 +439,7 @@ readLiteral:
return
}
- f.copyLen, f.copyDist = length, dist
+ f.copyLen, f.copyDist = length, int(dist)
goto copyHistory
}
@@ -511,7 +515,7 @@ readLiteral:
return
}
f.roffset++
- b |= uint32(c) << (nb & 31)
+ b |= uint32(c) << (nb & regSizeMaskUint32)
nb += 8
}
chunk := f.hl.chunks[b&(huffmanNumChunks-1)]
@@ -530,7 +534,7 @@ readLiteral:
f.err = CorruptInputError(f.roffset)
return
}
- f.b = b >> (n & 31)
+ f.b = b >> (n & regSizeMaskUint32)
f.nb = nb - n
v = int(chunk >> huffmanValueShift)
break
@@ -593,15 +597,15 @@ readLiteral:
return
}
}
- length += int(f.b & uint32(1<<n-1))
- f.b >>= n
+ length += int(f.b & uint32(1<<(n&regSizeMaskUint32)-1))
+ f.b >>= n & regSizeMaskUint32
f.nb -= n
}
- var dist int
+ var dist uint32
if f.hd == nil {
for f.nb < 5 {
- if err = moreBits(); err != nil {
+ if err = f.moreBits(); err != nil {
if debugDecode {
fmt.Println("morebits f.nb<5:", err)
}
@@ -609,17 +613,19 @@ readLiteral:
return
}
}
- dist = int(bits.Reverse8(uint8(f.b & 0x1F << 3)))
+ dist = uint32(bits.Reverse8(uint8(f.b & 0x1F << 3)))
f.b >>= 5
f.nb -= 5
} else {
- if dist, err = f.huffSym(f.hd); err != nil {
+ sym, err := f.huffSym(f.hd)
+ if err != nil {
if debugDecode {
fmt.Println("huffsym:", err)
}
f.err = err
return
}
+ dist = uint32(sym)
}
switch {
@@ -628,9 +634,9 @@ readLiteral:
case dist < maxNumDist:
nb := uint(dist-2) >> 1
// have 1 bit in bottom of dist, need nb more.
- extra := (dist & 1) << nb
+ extra := (dist & 1) << (nb & regSizeMaskUint32)
for f.nb < nb {
- if err = moreBits(); err != nil {
+ if err = f.moreBits(); err != nil {
if debugDecode {
fmt.Println("morebits f.nb<nb:", err)
}
@@ -638,10 +644,10 @@ readLiteral:
return
}
}
- extra |= int(f.b & uint32(1<<nb-1))
- f.b >>= nb
+ extra |= f.b & uint32(1<<(nb&regSizeMaskUint32)-1)
+ f.b >>= nb & regSizeMaskUint32
f.nb -= nb
- dist = 1<<(nb+1) + 1 + extra
+ dist = 1<<((nb+1)&regSizeMaskUint32) + 1 + extra
default:
if debugDecode {
fmt.Println("dist too big:", dist, maxNumDist)
@@ -651,7 +657,7 @@ readLiteral:
}
// No check on length; encoding can be prescient.
- if dist > f.dict.histSize() {
+ if dist > uint32(f.dict.histSize()) {
if debugDecode {
fmt.Println("dist > f.dict.histSize():", dist, f.dict.histSize())
}
@@ -659,7 +665,7 @@ readLiteral:
return
}
- f.copyLen, f.copyDist = length, dist
+ f.copyLen, f.copyDist = length, int(dist)
goto copyHistory
}
@@ -735,7 +741,7 @@ readLiteral:
return
}
f.roffset++
- b |= uint32(c) << (nb & 31)
+ b |= uint32(c) << (nb & regSizeMaskUint32)
nb += 8
}
chunk := f.hl.chunks[b&(huffmanNumChunks-1)]
@@ -754,7 +760,7 @@ readLiteral:
f.err = CorruptInputError(f.roffset)
return
}
- f.b = b >> (n & 31)
+ f.b = b >> (n & regSizeMaskUint32)
f.nb = nb - n
v = int(chunk >> huffmanValueShift)
break
@@ -817,15 +823,15 @@ readLiteral:
return
}
}
- length += int(f.b & uint32(1<<n-1))
- f.b >>= n
+ length += int(f.b & uint32(1<<(n&regSizeMaskUint32)-1))
+ f.b >>= n & regSizeMaskUint32
f.nb -= n
}
- var dist int
+ var dist uint32
if f.hd == nil {
for f.nb < 5 {
- if err = moreBits(); err != nil {
+ if err = f.moreBits(); err != nil {
if debugDecode {
fmt.Println("morebits f.nb<5:", err)
}
@@ -833,17 +839,19 @@ readLiteral:
return
}
}
- dist = int(bits.Reverse8(uint8(f.b & 0x1F << 3)))
+ dist = uint32(bits.Reverse8(uint8(f.b & 0x1F << 3)))
f.b >>= 5
f.nb -= 5
} else {
- if dist, err = f.huffSym(f.hd); err != nil {
+ sym, err := f.huffSym(f.hd)
+ if err != nil {
if debugDecode {
fmt.Println("huffsym:", err)
}
f.err = err
return
}
+ dist = uint32(sym)
}
switch {
@@ -852,9 +860,9 @@ readLiteral:
case dist < maxNumDist:
nb := uint(dist-2) >> 1
// have 1 bit in bottom of dist, need nb more.
- extra := (dist & 1) << nb
+ extra := (dist & 1) << (nb & regSizeMaskUint32)
for f.nb < nb {
- if err = moreBits(); err != nil {
+ if err = f.moreBits(); err != nil {
if debugDecode {
fmt.Println("morebits f.nb<nb:", err)
}
@@ -862,10 +870,10 @@ readLiteral:
return
}
}
- extra |= int(f.b & uint32(1<<nb-1))
- f.b >>= nb
+ extra |= f.b & uint32(1<<(nb&regSizeMaskUint32)-1)
+ f.b >>= nb & regSizeMaskUint32
f.nb -= nb
- dist = 1<<(nb+1) + 1 + extra
+ dist = 1<<((nb+1)&regSizeMaskUint32) + 1 + extra
default:
if debugDecode {
fmt.Println("dist too big:", dist, maxNumDist)
@@ -875,7 +883,7 @@ readLiteral:
}
// No check on length; encoding can be prescient.
- if dist > f.dict.histSize() {
+ if dist > uint32(f.dict.histSize()) {
if debugDecode {
fmt.Println("dist > f.dict.histSize():", dist, f.dict.histSize())
}
@@ -883,7 +891,7 @@ readLiteral:
return
}
- f.copyLen, f.copyDist = length, dist
+ f.copyLen, f.copyDist = length, int(dist)
goto copyHistory
}
diff --git a/vendor/github.com/klauspost/compress/flate/regmask_amd64.go b/vendor/github.com/klauspost/compress/flate/regmask_amd64.go
new file mode 100644
index 000000000..6ed28061b
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/regmask_amd64.go
@@ -0,0 +1,37 @@
+package flate
+
+const (
+ // Masks for shifts with register sizes of the shift value.
+ // This can be used to work around the x86 design of shifting by mod register size.
+ // It can be used when a variable shift is always smaller than the register size.
+
+ // reg8SizeMaskX - shift value is 8 bits, shifted is X
+ reg8SizeMask8 = 7
+ reg8SizeMask16 = 15
+ reg8SizeMask32 = 31
+ reg8SizeMask64 = 63
+
+ // reg16SizeMaskX - shift value is 16 bits, shifted is X
+ reg16SizeMask8 = reg8SizeMask8
+ reg16SizeMask16 = reg8SizeMask16
+ reg16SizeMask32 = reg8SizeMask32
+ reg16SizeMask64 = reg8SizeMask64
+
+ // reg32SizeMaskX - shift value is 32 bits, shifted is X
+ reg32SizeMask8 = reg8SizeMask8
+ reg32SizeMask16 = reg8SizeMask16
+ reg32SizeMask32 = reg8SizeMask32
+ reg32SizeMask64 = reg8SizeMask64
+
+ // reg64SizeMaskX - shift value is 64 bits, shifted is X
+ reg64SizeMask8 = reg8SizeMask8
+ reg64SizeMask16 = reg8SizeMask16
+ reg64SizeMask32 = reg8SizeMask32
+ reg64SizeMask64 = reg8SizeMask64
+
+ // regSizeMaskUintX - shift value is uint, shifted is X
+ regSizeMaskUint8 = reg8SizeMask8
+ regSizeMaskUint16 = reg8SizeMask16
+ regSizeMaskUint32 = reg8SizeMask32
+ regSizeMaskUint64 = reg8SizeMask64
+)
diff --git a/vendor/github.com/klauspost/compress/flate/regmask_other.go b/vendor/github.com/klauspost/compress/flate/regmask_other.go
new file mode 100644
index 000000000..f477a5d6e
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/flate/regmask_other.go
@@ -0,0 +1,39 @@
+//+build !amd64
+
+package flate
+
+const (
+ // Masks for shifts with register sizes of the shift value.
+ // This can be used to work around the x86 design of shifting by mod register size.
+ // It can be used when a variable shift is always smaller than the register size.
+
+ // reg8SizeMaskX - shift value is 8 bits, shifted is X
+ reg8SizeMask8 = 0xff
+ reg8SizeMask16 = 0xff
+ reg8SizeMask32 = 0xff
+ reg8SizeMask64 = 0xff
+
+ // reg16SizeMaskX - shift value is 16 bits, shifted is X
+ reg16SizeMask8 = 0xffff
+ reg16SizeMask16 = 0xffff
+ reg16SizeMask32 = 0xffff
+ reg16SizeMask64 = 0xffff
+
+ // reg32SizeMaskX - shift value is 32 bits, shifted is X
+ reg32SizeMask8 = 0xffffffff
+ reg32SizeMask16 = 0xffffffff
+ reg32SizeMask32 = 0xffffffff
+ reg32SizeMask64 = 0xffffffff
+
+ // reg64SizeMaskX - shift value is 64 bits, shifted is X
+ reg64SizeMask8 = 0xffffffffffffffff
+ reg64SizeMask16 = 0xffffffffffffffff
+ reg64SizeMask32 = 0xffffffffffffffff
+ reg64SizeMask64 = 0xffffffffffffffff
+
+ // regSizeMaskUintX - shift value is uint, shifted is X
+ regSizeMaskUint8 = ^uint(0)
+ regSizeMaskUint16 = ^uint(0)
+ regSizeMaskUint32 = ^uint(0)
+ regSizeMaskUint64 = ^uint(0)
+)
diff --git a/vendor/github.com/klauspost/compress/huff0/huff0.go b/vendor/github.com/klauspost/compress/huff0/huff0.go
index 5dd66854b..7ec2022b6 100644
--- a/vendor/github.com/klauspost/compress/huff0/huff0.go
+++ b/vendor/github.com/klauspost/compress/huff0/huff0.go
@@ -119,6 +119,16 @@ type Scratch struct {
huffWeight [maxSymbolValue + 1]byte
}
+// TransferCTable will transfer the previously used compression table.
+func (s *Scratch) TransferCTable(src *Scratch) {
+ if cap(s.prevTable) < len(src.prevTable) {
+ s.prevTable = make(cTable, 0, maxSymbolValue+1)
+ }
+ s.prevTable = s.prevTable[:len(src.prevTable)]
+ copy(s.prevTable, src.prevTable)
+ s.prevTableLog = src.prevTableLog
+}
+
func (s *Scratch) prepare(in []byte) (*Scratch, error) {
if len(in) > BlockSizeMax {
return nil, ErrTooBig
diff --git a/vendor/github.com/klauspost/compress/zstd/README.md b/vendor/github.com/klauspost/compress/zstd/README.md
index ac3640dc9..ea3e51082 100644
--- a/vendor/github.com/klauspost/compress/zstd/README.md
+++ b/vendor/github.com/klauspost/compress/zstd/README.md
@@ -5,7 +5,6 @@ It offers a very wide range of compression / speed trade-off, while being backed
A high performance compression algorithm is implemented. For now focused on speed.
This package provides [compression](#Compressor) to and [decompression](#Decompressor) of Zstandard content.
-Note that custom dictionaries are only supported for decompression.
This package is pure Go and without use of "unsafe".
@@ -232,41 +231,6 @@ nyc-taxi-data-10M.csv gzstd 1 3325605752 928656485 23876 132.83
nyc-taxi-data-10M.csv gzkp 1 3325605752 924718719 16388 193.53
```
-### Converters
-
-As part of the development process a *Snappy* -> *Zstandard* converter was also built.
-
-This can convert a *framed* [Snappy Stream](https://godoc.org/github.com/golang/snappy#Writer) to a zstd stream.
-Note that a single block is not framed.
-
-Conversion is done by converting the stream directly from Snappy without intermediate full decoding.
-Therefore the compression ratio is much less than what can be done by a full decompression
-and compression, and a faulty Snappy stream may lead to a faulty Zstandard stream without
-any errors being generated.
-No CRC value is being generated and not all CRC values of the Snappy stream are checked.
-However, it provides really fast re-compression of Snappy streams.
-
-
-```
-BenchmarkSnappy_ConvertSilesia-8 1 1156001600 ns/op 183.35 MB/s
-Snappy len 103008711 -> zstd len 82687318
-
-BenchmarkSnappy_Enwik9-8 1 6472998400 ns/op 154.49 MB/s
-Snappy len 508028601 -> zstd len 390921079
-```
-
-
-```Go
- s := zstd.SnappyConverter{}
- n, err = s.Convert(input, output)
- if err != nil {
- fmt.Println("Re-compressed stream to", n, "bytes")
- }
-```
-
-The converter `s` can be reused to avoid allocations, even after errors.
-
-
## Decompressor
Staus: STABLE - there may still be subtle bugs, but a wide variety of content has been tested.
@@ -337,6 +301,21 @@ A re-used Decoder will still contain the dictionaries registered.
When registering multiple dictionaries with the same ID, the last one will be used.
+It is possible to use dictionaries when compressing data.
+
+To enable a dictionary use `WithEncoderDict(dict []byte)`. Here only one dictionary will be used
+and it will likely be used even if it doesn't improve compression.
+
+The used dictionary must be used to decompress the content.
+
+For any real gains, the dictionary should be built with similar data.
+If an unsuitable dictionary is used the output may be slightly larger than using no dictionary.
+Use the [zstd commandline tool](https://github.com/facebook/zstd/releases) to build a dictionary from sample data.
+For information see [zstd dictionary information](https://github.com/facebook/zstd#the-case-for-small-data-compression).
+
+For now there is a fixed startup performance penalty for compressing content with dictionaries.
+This will likely be improved over time. Just be aware to test performance when implementing.
+
### Allocation-less operation
The decoder has been designed to operate without allocations after a warmup.
diff --git a/vendor/github.com/klauspost/compress/zstd/blockdec.go b/vendor/github.com/klauspost/compress/zstd/blockdec.go
index c8ec6e331..4733ea876 100644
--- a/vendor/github.com/klauspost/compress/zstd/blockdec.go
+++ b/vendor/github.com/klauspost/compress/zstd/blockdec.go
@@ -646,7 +646,7 @@ func (b *blockDec) decodeCompressed(hist *history) error {
}
} else {
if hist.huffTree != nil && huff != nil {
- if hist.dict == nil || hist.dict.litDec != hist.huffTree {
+ if hist.dict == nil || hist.dict.litEnc != hist.huffTree {
huffDecoderPool.Put(hist.huffTree)
}
hist.huffTree = nil
diff --git a/vendor/github.com/klauspost/compress/zstd/blockenc.go b/vendor/github.com/klauspost/compress/zstd/blockenc.go
index be718afd4..083fbb502 100644
--- a/vendor/github.com/klauspost/compress/zstd/blockenc.go
+++ b/vendor/github.com/klauspost/compress/zstd/blockenc.go
@@ -14,12 +14,13 @@ import (
)
type blockEnc struct {
- size int
- literals []byte
- sequences []seq
- coders seqCoders
- litEnc *huff0.Scratch
- wr bitWriter
+ size int
+ literals []byte
+ sequences []seq
+ coders seqCoders
+ litEnc *huff0.Scratch
+ dictLitEnc *huff0.Scratch
+ wr bitWriter
extraLits int
last bool
@@ -314,19 +315,19 @@ func (b *blockEnc) encodeRawTo(dst, src []byte) []byte {
}
// encodeLits can be used if the block is only litLen.
-func (b *blockEnc) encodeLits(raw bool) error {
+func (b *blockEnc) encodeLits(lits []byte, raw bool) error {
var bh blockHeader
bh.setLast(b.last)
- bh.setSize(uint32(len(b.literals)))
+ bh.setSize(uint32(len(lits)))
// Don't compress extremely small blocks
- if len(b.literals) < 32 || raw {
+ if len(lits) < 8 || (len(lits) < 32 && b.dictLitEnc == nil) || raw {
if debug {
- println("Adding RAW block, length", len(b.literals), "last:", b.last)
+ println("Adding RAW block, length", len(lits), "last:", b.last)
}
bh.setType(blockTypeRaw)
b.output = bh.appendTo(b.output)
- b.output = append(b.output, b.literals...)
+ b.output = append(b.output, lits...)
return nil
}
@@ -335,13 +336,18 @@ func (b *blockEnc) encodeLits(raw bool) error {
reUsed, single bool
err error
)
- if len(b.literals) >= 1024 {
+ if b.dictLitEnc != nil {
+ b.litEnc.TransferCTable(b.dictLitEnc)
+ b.litEnc.Reuse = huff0.ReusePolicyAllow
+ b.dictLitEnc = nil
+ }
+ if len(lits) >= 1024 {
// Use 4 Streams.
- out, reUsed, err = huff0.Compress4X(b.literals, b.litEnc)
- } else if len(b.literals) > 32 {
+ out, reUsed, err = huff0.Compress4X(lits, b.litEnc)
+ } else if len(lits) > 32 {
// Use 1 stream
single = true
- out, reUsed, err = huff0.Compress1X(b.literals, b.litEnc)
+ out, reUsed, err = huff0.Compress1X(lits, b.litEnc)
} else {
err = huff0.ErrIncompressible
}
@@ -349,19 +355,19 @@ func (b *blockEnc) encodeLits(raw bool) error {
switch err {
case huff0.ErrIncompressible:
if debug {
- println("Adding RAW block, length", len(b.literals), "last:", b.last)
+ println("Adding RAW block, length", len(lits), "last:", b.last)
}
bh.setType(blockTypeRaw)
b.output = bh.appendTo(b.output)
- b.output = append(b.output, b.literals...)
+ b.output = append(b.output, lits...)
return nil
case huff0.ErrUseRLE:
if debug {
- println("Adding RLE block, length", len(b.literals))
+ println("Adding RLE block, length", len(lits))
}
bh.setType(blockTypeRLE)
b.output = bh.appendTo(b.output)
- b.output = append(b.output, b.literals[0])
+ b.output = append(b.output, lits[0])
return nil
default:
return err
@@ -384,7 +390,7 @@ func (b *blockEnc) encodeLits(raw bool) error {
lh.setType(literalsBlockCompressed)
}
// Set sizes
- lh.setSizes(len(out), len(b.literals), single)
+ lh.setSizes(len(out), len(lits), single)
bh.setSize(uint32(len(out) + lh.size() + 1))
// Write block headers.
@@ -444,13 +450,19 @@ func fuzzFseEncoder(data []byte) int {
}
// encode will encode the block and append the output in b.output.
-func (b *blockEnc) encode(raw, rawAllLits bool) error {
+// Previous offset codes must be pushed if more blocks are expected.
+func (b *blockEnc) encode(org []byte, raw, rawAllLits bool) error {
if len(b.sequences) == 0 {
- return b.encodeLits(rawAllLits)
+ return b.encodeLits(b.literals, rawAllLits)
}
- // We want some difference
- if len(b.literals) > (b.size - (b.size >> 5)) {
- return errIncompressible
+ // We want some difference to at least account for the headers.
+ saved := b.size - len(b.literals) - (b.size >> 5)
+ if saved < 16 {
+ if org == nil {
+ return errIncompressible
+ }
+ b.popOffsets()
+ return b.encodeLits(org, rawAllLits)
}
var bh blockHeader
@@ -466,6 +478,11 @@ func (b *blockEnc) encode(raw, rawAllLits bool) error {
reUsed, single bool
err error
)
+ if b.dictLitEnc != nil {
+ b.litEnc.TransferCTable(b.dictLitEnc)
+ b.litEnc.Reuse = huff0.ReusePolicyAllow
+ b.dictLitEnc = nil
+ }
if len(b.literals) >= 1024 && !raw {
// Use 4 Streams.
out, reUsed, err = huff0.Compress4X(b.literals, b.litEnc)
diff --git a/vendor/github.com/klauspost/compress/zstd/decoder.go b/vendor/github.com/klauspost/compress/zstd/decoder.go
index 66b51bf2d..d78be6d42 100644
--- a/vendor/github.com/klauspost/compress/zstd/decoder.go
+++ b/vendor/github.com/klauspost/compress/zstd/decoder.go
@@ -187,7 +187,7 @@ func (d *Decoder) Reset(r io.Reader) error {
d.current.err = err
d.current.flushed = true
if debug {
- println("sync decode to ", len(dst), "bytes, err:", err)
+ println("sync decode to", len(dst), "bytes, err:", err)
}
return nil
}
@@ -303,6 +303,9 @@ func (d *Decoder) DecodeAll(input, dst []byte) ([]byte, error) {
frame.history.reset()
err := frame.reset(&frame.bBuf)
if err == io.EOF {
+ if debug {
+ println("frame reset return EOF")
+ }
return dst, nil
}
if frame.DictionaryID != nil {
@@ -341,6 +344,9 @@ func (d *Decoder) DecodeAll(input, dst []byte) ([]byte, error) {
return dst, err
}
if len(frame.bBuf) == 0 {
+ if debug {
+ println("frame dbuf empty")
+ }
break
}
}
diff --git a/vendor/github.com/klauspost/compress/zstd/dict.go b/vendor/github.com/klauspost/compress/zstd/dict.go
index 8eb6f6ba3..fa25a18d8 100644
--- a/vendor/github.com/klauspost/compress/zstd/dict.go
+++ b/vendor/github.com/klauspost/compress/zstd/dict.go
@@ -13,14 +13,31 @@ import (
type dict struct {
id uint32
- litDec *huff0.Scratch
+ litEnc *huff0.Scratch
llDec, ofDec, mlDec sequenceDec
- offsets [3]int
- content []byte
+ //llEnc, ofEnc, mlEnc []*fseEncoder
+ offsets [3]int
+ content []byte
}
var dictMagic = [4]byte{0x37, 0xa4, 0x30, 0xec}
+// ID returns the dictionary id or 0 if d is nil.
+func (d *dict) ID() uint32 {
+ if d == nil {
+ return 0
+ }
+ return d.id
+}
+
+// DictContentSize returns the dictionary content size or 0 if d is nil.
+func (d *dict) DictContentSize() int {
+ if d == nil {
+ return 0
+ }
+ return len(d.content)
+}
+
// Load a dictionary as described in
// https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
func loadDict(b []byte) (*dict, error) {
@@ -43,10 +60,11 @@ func loadDict(b []byte) (*dict, error) {
// Read literal table
var err error
- d.litDec, b, err = huff0.ReadTable(b[8:], nil)
+ d.litEnc, b, err = huff0.ReadTable(b[8:], nil)
if err != nil {
return nil, err
}
+ d.litEnc.Reuse = huff0.ReusePolicyMust
br := byteReader{
b: b,
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_base.go b/vendor/github.com/klauspost/compress/zstd/enc_base.go
new file mode 100644
index 000000000..b1b7c6e6a
--- /dev/null
+++ b/vendor/github.com/klauspost/compress/zstd/enc_base.go
@@ -0,0 +1,155 @@
+package zstd
+
+import (
+ "fmt"
+ "math/bits"
+
+ "github.com/klauspost/compress/zstd/internal/xxhash"
+)
+
+type fastBase struct {
+ // cur is the offset at the start of hist
+ cur int32
+ // maximum offset. Should be at least 2x block size.
+ maxMatchOff int32
+ hist []byte
+ crc *xxhash.Digest
+ tmp [8]byte
+ blk *blockEnc
+ lastDictID uint32
+}
+
+// CRC returns the underlying CRC writer.
+func (e *fastBase) CRC() *xxhash.Digest {
+ return e.crc
+}
+
+// AppendCRC will append the CRC to the destination slice and return it.
+func (e *fastBase) AppendCRC(dst []byte) []byte {
+ crc := e.crc.Sum(e.tmp[:0])
+ dst = append(dst, crc[7], crc[6], crc[5], crc[4])
+ return dst
+}
+
+// WindowSize returns the window size of the encoder,
+// or a window size small enough to contain the input size, if > 0.
+func (e *fastBase) WindowSize(size int) int32 {
+ if size > 0 && size < int(e.maxMatchOff) {
+ b := int32(1) << uint(bits.Len(uint(size)))
+ // Keep minimum window.
+ if b < 1024 {
+ b = 1024
+ }
+ return b
+ }
+ return e.maxMatchOff
+}
+
+// Block returns the current block.
+func (e *fastBase) Block() *blockEnc {
+ return e.blk
+}
+
+func (e *fastBase) addBlock(src []byte) int32 {
+ if debugAsserts && e.cur > bufferReset {
+ panic(fmt.Sprintf("ecur (%d) > buffer reset (%d)", e.cur, bufferReset))
+ }
+ // check if we have space already
+ if len(e.hist)+len(src) > cap(e.hist) {
+ if cap(e.hist) == 0 {
+ l := e.maxMatchOff * 2
+ // Make it at least 1MB.
+ if l < 1<<20 {
+ l = 1 << 20
+ }
+ e.hist = make([]byte, 0, l)
+ } else {
+ if cap(e.hist) < int(e.maxMatchOff*2) {
+ panic("unexpected buffer size")
+ }
+ // Move down
+ offset := int32(len(e.hist)) - e.maxMatchOff
+ copy(e.hist[0:e.maxMatchOff], e.hist[offset:])
+ e.cur += offset
+ e.hist = e.hist[:e.maxMatchOff]
+ }
+ }
+ s := int32(len(e.hist))
+ e.hist = append(e.hist, src...)
+ return s
+}
+
+// useBlock will replace the block with the provided one,
+// but transfer recent offsets from the previous.
+func (e *fastBase) UseBlock(enc *blockEnc) {
+ enc.reset(e.blk)
+ e.blk = enc
+}
+
+func (e *fastBase) matchlenNoHist(s, t int32, src []byte) int32 {
+ // Extend the match to be as long as possible.
+ return int32(matchLen(src[s:], src[t:]))
+}
+
+func (e *fastBase) matchlen(s, t int32, src []byte) int32 {
+ if debugAsserts {
+ if s < 0 {
+ err := fmt.Sprintf("s (%d) < 0", s)
+ panic(err)
+ }
+ if t < 0 {
+ err := fmt.Sprintf("s (%d) < 0", s)
+ panic(err)
+ }
+ if s-t > e.maxMatchOff {
+ err := fmt.Sprintf("s (%d) - t (%d) > maxMatchOff (%d)", s, t, e.maxMatchOff)
+ panic(err)
+ }
+ if len(src)-int(s) > maxCompressedBlockSize {
+ panic(fmt.Sprintf("len(src)-s (%d) > maxCompressedBlockSize (%d)", len(src)-int(s), maxCompressedBlockSize))
+ }
+ }
+
+ // Extend the match to be as long as possible.
+ return int32(matchLen(src[s:], src[t:]))
+}
+
+// Reset the encoding table.
+func (e *fastBase) resetBase(d *dict, singleBlock bool) {
+ if e.blk == nil {
+ e.blk = &blockEnc{}
+ e.blk.init()
+ } else {
+ e.blk.reset(nil)
+ }
+ e.blk.initNewEncode()
+ if e.crc == nil {
+ e.crc = xxhash.New()
+ } else {
+ e.crc.Reset()
+ }
+ if (!singleBlock || d.DictContentSize() > 0) && cap(e.hist) < int(e.maxMatchOff*2)+d.DictContentSize() {
+ l := e.maxMatchOff*2 + int32(d.DictContentSize())
+ // Make it at least 1MB.
+ if l < 1<<20 {
+ l = 1 << 20
+ }
+ e.hist = make([]byte, 0, l)
+ }
+ // We offset current position so everything will be out of reach.
+ // If above reset line, history will be purged.
+ if e.cur < bufferReset {
+ e.cur += e.maxMatchOff + int32(len(e.hist))
+ }
+ e.hist = e.hist[:0]
+ if d != nil {
+ // Set offsets (currently not used)
+ for i, off := range d.offsets {
+ e.blk.recentOffsets[i] = uint32(off)
+ e.blk.prevRecentOffsets[i] = e.blk.recentOffsets[i]
+ }
+ // Transfer litenc.
+ e.blk.dictLitEnc = d.litEnc
+ e.hist = append(e.hist, d.content...)
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_better.go b/vendor/github.com/klauspost/compress/zstd/enc_better.go
index c120d9054..94a5343d0 100644
--- a/vendor/github.com/klauspost/compress/zstd/enc_better.go
+++ b/vendor/github.com/klauspost/compress/zstd/enc_better.go
@@ -31,8 +31,10 @@ type prevEntry struct {
// and that it is longer (lazy matching).
type betterFastEncoder struct {
fastBase
- table [betterShortTableSize]tableEntry
- longTable [betterLongTableSize]prevEntry
+ table [betterShortTableSize]tableEntry
+ longTable [betterLongTableSize]prevEntry
+ dictTable []tableEntry
+ dictLongTable []prevEntry
}
// Encode improves compression...
@@ -516,3 +518,78 @@ encodeLoop:
func (e *betterFastEncoder) EncodeNoHist(blk *blockEnc, src []byte) {
e.Encode(blk, src)
}
+
+// ResetDict will reset and set a dictionary if not nil
+func (e *betterFastEncoder) Reset(d *dict, singleBlock bool) {
+ e.resetBase(d, singleBlock)
+ if d == nil {
+ return
+ }
+ // Init or copy dict table
+ if len(e.dictTable) != len(e.table) || d.id != e.lastDictID {
+ if len(e.dictTable) != len(e.table) {
+ e.dictTable = make([]tableEntry, len(e.table))
+ }
+ end := int32(len(d.content)) - 8 + e.maxMatchOff
+ for i := e.maxMatchOff; i < end; i += 4 {
+ const hashLog = betterShortTableBits
+
+ cv := load6432(d.content, i-e.maxMatchOff)
+ nextHash := hash5(cv, hashLog) // 0 -> 4
+ nextHash1 := hash5(cv>>8, hashLog) // 1 -> 5
+ nextHash2 := hash5(cv>>16, hashLog) // 2 -> 6
+ nextHash3 := hash5(cv>>24, hashLog) // 3 -> 7
+ e.dictTable[nextHash] = tableEntry{
+ val: uint32(cv),
+ offset: i,
+ }
+ e.dictTable[nextHash1] = tableEntry{
+ val: uint32(cv >> 8),
+ offset: i + 1,
+ }
+ e.dictTable[nextHash2] = tableEntry{
+ val: uint32(cv >> 16),
+ offset: i + 2,
+ }
+ e.dictTable[nextHash3] = tableEntry{
+ val: uint32(cv >> 24),
+ offset: i + 3,
+ }
+ }
+ e.lastDictID = d.id
+ }
+
+ // Init or copy dict table
+ if len(e.dictLongTable) != len(e.longTable) || d.id != e.lastDictID {
+ if len(e.dictLongTable) != len(e.longTable) {
+ e.dictLongTable = make([]prevEntry, len(e.longTable))
+ }
+ if len(d.content) >= 8 {
+ cv := load6432(d.content, 0)
+ h := hash8(cv, betterLongTableBits)
+ e.dictLongTable[h] = prevEntry{
+ offset: e.maxMatchOff,
+ prev: e.dictLongTable[h].offset,
+ }
+
+ end := int32(len(d.content)) - 8 + e.maxMatchOff
+ off := 8 // First to read
+ for i := e.maxMatchOff + 1; i < end; i++ {
+ cv = cv>>8 | (uint64(d.content[off]) << 56)
+ h := hash8(cv, betterLongTableBits)
+ e.dictLongTable[h] = prevEntry{
+ offset: i,
+ prev: e.dictLongTable[h].offset,
+ }
+ off++
+ }
+ }
+ e.lastDictID = d.id
+ }
+ // Reset table to initial state
+ copy(e.longTable[:], e.dictLongTable)
+
+ e.cur = e.maxMatchOff
+ // Reset table to initial state
+ copy(e.table[:], e.dictTable)
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_dfast.go b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go
index 50276bcde..19eebf66e 100644
--- a/vendor/github.com/klauspost/compress/zstd/enc_dfast.go
+++ b/vendor/github.com/klauspost/compress/zstd/enc_dfast.go
@@ -18,7 +18,8 @@ const (
type doubleFastEncoder struct {
fastEncoder
- longTable [dFastLongTableSize]tableEntry
+ longTable [dFastLongTableSize]tableEntry
+ dictLongTable []tableEntry
}
// Encode mimmics functionality in zstd_dfast.c
@@ -494,7 +495,7 @@ encodeLoop:
// but the likelihood of both the first 4 bytes and the hash matching should be enough.
t = candidateL.offset - e.cur
if debugAsserts && s <= t {
- panic(fmt.Sprintf("s (%d) <= t (%d)", s, t))
+ panic(fmt.Sprintf("s (%d) <= t (%d). cur: %d", s, t, e.cur))
}
if debugAsserts && s-t > e.maxMatchOff {
panic("s - t >e.maxMatchOff")
@@ -676,3 +677,37 @@ encodeLoop:
e.cur += int32(len(src))
}
}
+
+// ResetDict will reset and set a dictionary if not nil
+func (e *doubleFastEncoder) Reset(d *dict, singleBlock bool) {
+ e.fastEncoder.Reset(d, singleBlock)
+ if d == nil {
+ return
+ }
+
+ // Init or copy dict table
+ if len(e.dictLongTable) != len(e.longTable) || d.id != e.lastDictID {
+ if len(e.dictLongTable) != len(e.longTable) {
+ e.dictLongTable = make([]tableEntry, len(e.longTable))
+ }
+ if len(d.content) >= 8 {
+ cv := load6432(d.content, 0)
+ e.dictLongTable[hash8(cv, dFastLongTableBits)] = tableEntry{
+ val: uint32(cv),
+ offset: e.maxMatchOff,
+ }
+ end := int32(len(d.content)) - 8 + e.maxMatchOff
+ for i := e.maxMatchOff + 1; i < end; i++ {
+ cv = cv>>8 | (uint64(d.content[i-e.maxMatchOff+7]) << 56)
+ e.dictLongTable[hash8(cv, dFastLongTableBits)] = tableEntry{
+ val: uint32(cv),
+ offset: i,
+ }
+ }
+ }
+ e.lastDictID = d.id
+ }
+ // Reset table to initial state
+ e.cur = e.maxMatchOff
+ copy(e.longTable[:], e.dictLongTable)
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_fast.go b/vendor/github.com/klauspost/compress/zstd/enc_fast.go
index 4104b456c..0b301df43 100644
--- a/vendor/github.com/klauspost/compress/zstd/enc_fast.go
+++ b/vendor/github.com/klauspost/compress/zstd/enc_fast.go
@@ -8,8 +8,6 @@ import (
"fmt"
"math"
"math/bits"
-
- "github.com/klauspost/compress/zstd/internal/xxhash"
)
const (
@@ -24,51 +22,10 @@ type tableEntry struct {
offset int32
}
-type fastBase struct {
- // cur is the offset at the start of hist
- cur int32
- // maximum offset. Should be at least 2x block size.
- maxMatchOff int32
- hist []byte
- crc *xxhash.Digest
- tmp [8]byte
- blk *blockEnc
-}
-
type fastEncoder struct {
fastBase
- table [tableSize]tableEntry
-}
-
-// CRC returns the underlying CRC writer.
-func (e *fastBase) CRC() *xxhash.Digest {
- return e.crc
-}
-
-// AppendCRC will append the CRC to the destination slice and return it.
-func (e *fastBase) AppendCRC(dst []byte) []byte {
- crc := e.crc.Sum(e.tmp[:0])
- dst = append(dst, crc[7], crc[6], crc[5], crc[4])
- return dst
-}
-
-// WindowSize returns the window size of the encoder,
-// or a window size small enough to contain the input size, if > 0.
-func (e *fastBase) WindowSize(size int) int32 {
- if size > 0 && size < int(e.maxMatchOff) {
- b := int32(1) << uint(bits.Len(uint(size)))
- // Keep minimum window.
- if b < 1024 {
- b = 1024
- }
- return b
- }
- return e.maxMatchOff
-}
-
-// Block returns the current block.
-func (e *fastBase) Block() *blockEnc {
- return e.blk
+ table [tableSize]tableEntry
+ dictTable []tableEntry
}
// Encode mimmics functionality in zstd_fast.c
@@ -660,96 +617,45 @@ encodeLoop:
}
}
-func (e *fastBase) addBlock(src []byte) int32 {
- if debugAsserts && e.cur > bufferReset {
- panic(fmt.Sprintf("ecur (%d) > buffer reset (%d)", e.cur, bufferReset))
- }
- // check if we have space already
- if len(e.hist)+len(src) > cap(e.hist) {
- if cap(e.hist) == 0 {
- l := e.maxMatchOff * 2
- // Make it at least 1MB.
- if l < 1<<20 {
- l = 1 << 20
- }
- e.hist = make([]byte, 0, l)
- } else {
- if cap(e.hist) < int(e.maxMatchOff*2) {
- panic("unexpected buffer size")
- }
- // Move down
- offset := int32(len(e.hist)) - e.maxMatchOff
- copy(e.hist[0:e.maxMatchOff], e.hist[offset:])
- e.cur += offset
- e.hist = e.hist[:e.maxMatchOff]
- }
+// ResetDict will reset and set a dictionary if not nil
+func (e *fastEncoder) Reset(d *dict, singleBlock bool) {
+ e.resetBase(d, singleBlock)
+ if d == nil {
+ return
}
- s := int32(len(e.hist))
- e.hist = append(e.hist, src...)
- return s
-}
-// useBlock will replace the block with the provided one,
-// but transfer recent offsets from the previous.
-func (e *fastBase) UseBlock(enc *blockEnc) {
- enc.reset(e.blk)
- e.blk = enc
-}
-
-func (e *fastBase) matchlenNoHist(s, t int32, src []byte) int32 {
- // Extend the match to be as long as possible.
- return int32(matchLen(src[s:], src[t:]))
-}
-
-func (e *fastBase) matchlen(s, t int32, src []byte) int32 {
- if debugAsserts {
- if s < 0 {
- err := fmt.Sprintf("s (%d) < 0", s)
- panic(err)
- }
- if t < 0 {
- err := fmt.Sprintf("s (%d) < 0", s)
- panic(err)
- }
- if s-t > e.maxMatchOff {
- err := fmt.Sprintf("s (%d) - t (%d) > maxMatchOff (%d)", s, t, e.maxMatchOff)
- panic(err)
- }
- if len(src)-int(s) > maxCompressedBlockSize {
- panic(fmt.Sprintf("len(src)-s (%d) > maxCompressedBlockSize (%d)", len(src)-int(s), maxCompressedBlockSize))
+ // Init or copy dict table
+ if len(e.dictTable) != len(e.table) || d.id != e.lastDictID {
+ if len(e.dictTable) != len(e.table) {
+ e.dictTable = make([]tableEntry, len(e.table))
+ }
+ if true {
+ end := e.maxMatchOff + int32(len(d.content)) - 8
+ for i := e.maxMatchOff; i < end; i += 3 {
+ const hashLog = tableBits
+
+ cv := load6432(d.content, i-e.maxMatchOff)
+ nextHash := hash6(cv, hashLog) // 0 -> 5
+ nextHash1 := hash6(cv>>8, hashLog) // 1 -> 6
+ nextHash2 := hash6(cv>>16, hashLog) // 2 -> 7
+ e.dictTable[nextHash] = tableEntry{
+ val: uint32(cv),
+ offset: i,
+ }
+ e.dictTable[nextHash1] = tableEntry{
+ val: uint32(cv >> 8),
+ offset: i + 1,
+ }
+ e.dictTable[nextHash2] = tableEntry{
+ val: uint32(cv >> 16),
+ offset: i + 2,
+ }
+ }
}
+ e.lastDictID = d.id
}
- // Extend the match to be as long as possible.
- return int32(matchLen(src[s:], src[t:]))
-}
-
-// Reset the encoding table.
-func (e *fastBase) Reset(singleBlock bool) {
- if e.blk == nil {
- e.blk = &blockEnc{}
- e.blk.init()
- } else {
- e.blk.reset(nil)
- }
- e.blk.initNewEncode()
- if e.crc == nil {
- e.crc = xxhash.New()
- } else {
- e.crc.Reset()
- }
- if !singleBlock && cap(e.hist) < int(e.maxMatchOff*2) {
- l := e.maxMatchOff * 2
- // Make it at least 1MB.
- if l < 1<<20 {
- l = 1 << 20
- }
- e.hist = make([]byte, 0, l)
- }
- // We offset current position so everything will be out of reach.
- // If above reset line, history will be purged.
- if e.cur < bufferReset {
- e.cur += e.maxMatchOff + int32(len(e.hist))
- }
- e.hist = e.hist[:0]
+ e.cur = e.maxMatchOff
+ // Reset table to initial state
+ copy(e.table[:], e.dictTable)
}
diff --git a/vendor/github.com/klauspost/compress/zstd/enc_params.go b/vendor/github.com/klauspost/compress/zstd/enc_params.go
deleted file mode 100644
index d874116f7..000000000
--- a/vendor/github.com/klauspost/compress/zstd/enc_params.go
+++ /dev/null
@@ -1,157 +0,0 @@
-// Copyright 2019+ Klaus Post. All rights reserved.
-// License information can be found in the LICENSE file.
-// Based on work by Yann Collet, released under BSD License.
-
-package zstd
-
-/*
-// encParams are not really used, just here for reference.
-type encParams struct {
- // largest match distance : larger == more compression, more memory needed during decompression
- windowLog uint8
-
- // fully searched segment : larger == more compression, slower, more memory (useless for fast)
- chainLog uint8
-
- // dispatch table : larger == faster, more memory
- hashLog uint8
-
- // < nb of searches : larger == more compression, slower
- searchLog uint8
-
- // < match length searched : larger == faster decompression, sometimes less compression
- minMatch uint8
-
- // acceptable match size for optimal parser (only) : larger == more compression, slower
- targetLength uint32
-
- // see ZSTD_strategy definition above
- strategy strategy
-}
-
-// strategy defines the algorithm to use when generating sequences.
-type strategy uint8
-
-const (
- // Compression strategies, listed from fastest to strongest
- strategyFast strategy = iota + 1
- strategyDfast
- strategyGreedy
- strategyLazy
- strategyLazy2
- strategyBtlazy2
- strategyBtopt
- strategyBtultra
- strategyBtultra2
- // note : new strategies _might_ be added in the future.
- // Only the order (from fast to strong) is guaranteed
-
-)
-
-var defEncParams = [4][]encParams{
- { // "default" - for any srcSize > 256 KB
- // W, C, H, S, L, TL, strat
- {19, 12, 13, 1, 6, 1, strategyFast}, // base for negative levels
- {19, 13, 14, 1, 7, 0, strategyFast}, // level 1
- {20, 15, 16, 1, 6, 0, strategyFast}, // level 2
- {21, 16, 17, 1, 5, 1, strategyDfast}, // level 3
- {21, 18, 18, 1, 5, 1, strategyDfast}, // level 4
- {21, 18, 19, 2, 5, 2, strategyGreedy}, // level 5
- {21, 19, 19, 3, 5, 4, strategyGreedy}, // level 6
- {21, 19, 19, 3, 5, 8, strategyLazy}, // level 7
- {21, 19, 19, 3, 5, 16, strategyLazy2}, // level 8
- {21, 19, 20, 4, 5, 16, strategyLazy2}, // level 9
- {22, 20, 21, 4, 5, 16, strategyLazy2}, // level 10
- {22, 21, 22, 4, 5, 16, strategyLazy2}, // level 11
- {22, 21, 22, 5, 5, 16, strategyLazy2}, // level 12
- {22, 21, 22, 5, 5, 32, strategyBtlazy2}, // level 13
- {22, 22, 23, 5, 5, 32, strategyBtlazy2}, // level 14
- {22, 23, 23, 6, 5, 32, strategyBtlazy2}, // level 15
- {22, 22, 22, 5, 5, 48, strategyBtopt}, // level 16
- {23, 23, 22, 5, 4, 64, strategyBtopt}, // level 17
- {23, 23, 22, 6, 3, 64, strategyBtultra}, // level 18
- {23, 24, 22, 7, 3, 256, strategyBtultra2}, // level 19
- {25, 25, 23, 7, 3, 256, strategyBtultra2}, // level 20
- {26, 26, 24, 7, 3, 512, strategyBtultra2}, // level 21
- {27, 27, 25, 9, 3, 999, strategyBtultra2}, // level 22
- },
- { // for srcSize <= 256 KB
- // W, C, H, S, L, T, strat
- {18, 12, 13, 1, 5, 1, strategyFast}, // base for negative levels
- {18, 13, 14, 1, 6, 0, strategyFast}, // level 1
- {18, 14, 14, 1, 5, 1, strategyDfast}, // level 2
- {18, 16, 16, 1, 4, 1, strategyDfast}, // level 3
- {18, 16, 17, 2, 5, 2, strategyGreedy}, // level 4.
- {18, 18, 18, 3, 5, 2, strategyGreedy}, // level 5.
- {18, 18, 19, 3, 5, 4, strategyLazy}, // level 6.
- {18, 18, 19, 4, 4, 4, strategyLazy}, // level 7
- {18, 18, 19, 4, 4, 8, strategyLazy2}, // level 8
- {18, 18, 19, 5, 4, 8, strategyLazy2}, // level 9
- {18, 18, 19, 6, 4, 8, strategyLazy2}, // level 10
- {18, 18, 19, 5, 4, 12, strategyBtlazy2}, // level 11.
- {18, 19, 19, 7, 4, 12, strategyBtlazy2}, // level 12.
- {18, 18, 19, 4, 4, 16, strategyBtopt}, // level 13
- {18, 18, 19, 4, 3, 32, strategyBtopt}, // level 14.
- {18, 18, 19, 6, 3, 128, strategyBtopt}, // level 15.
- {18, 19, 19, 6, 3, 128, strategyBtultra}, // level 16.
- {18, 19, 19, 8, 3, 256, strategyBtultra}, // level 17.
- {18, 19, 19, 6, 3, 128, strategyBtultra2}, // level 18.
- {18, 19, 19, 8, 3, 256, strategyBtultra2}, // level 19.
- {18, 19, 19, 10, 3, 512, strategyBtultra2}, // level 20.
- {18, 19, 19, 12, 3, 512, strategyBtultra2}, // level 21.
- {18, 19, 19, 13, 3, 999, strategyBtultra2}, // level 22.
- },
- { // for srcSize <= 128 KB
- // W, C, H, S, L, T, strat
- {17, 12, 12, 1, 5, 1, strategyFast}, // base for negative levels
- {17, 12, 13, 1, 6, 0, strategyFast}, // level 1
- {17, 13, 15, 1, 5, 0, strategyFast}, // level 2
- {17, 15, 16, 2, 5, 1, strategyDfast}, // level 3
- {17, 17, 17, 2, 4, 1, strategyDfast}, // level 4
- {17, 16, 17, 3, 4, 2, strategyGreedy}, // level 5
- {17, 17, 17, 3, 4, 4, strategyLazy}, // level 6
- {17, 17, 17, 3, 4, 8, strategyLazy2}, // level 7
- {17, 17, 17, 4, 4, 8, strategyLazy2}, // level 8
- {17, 17, 17, 5, 4, 8, strategyLazy2}, // level 9
- {17, 17, 17, 6, 4, 8, strategyLazy2}, // level 10
- {17, 17, 17, 5, 4, 8, strategyBtlazy2}, // level 11
- {17, 18, 17, 7, 4, 12, strategyBtlazy2}, // level 12
- {17, 18, 17, 3, 4, 12, strategyBtopt}, // level 13.
- {17, 18, 17, 4, 3, 32, strategyBtopt}, // level 14.
- {17, 18, 17, 6, 3, 256, strategyBtopt}, // level 15.
- {17, 18, 17, 6, 3, 128, strategyBtultra}, // level 16.
- {17, 18, 17, 8, 3, 256, strategyBtultra}, // level 17.
- {17, 18, 17, 10, 3, 512, strategyBtultra}, // level 18.
- {17, 18, 17, 5, 3, 256, strategyBtultra2}, // level 19.
- {17, 18, 17, 7, 3, 512, strategyBtultra2}, // level 20.
- {17, 18, 17, 9, 3, 512, strategyBtultra2}, // level 21.
- {17, 18, 17, 11, 3, 999, strategyBtultra2}, // level 22.
- },
- { // for srcSize <= 16 KB
- // W, C, H, S, L, T, strat
- {14, 12, 13, 1, 5, 1, strategyFast}, // base for negative levels
- {14, 14, 15, 1, 5, 0, strategyFast}, // level 1
- {14, 14, 15, 1, 4, 0, strategyFast}, // level 2
- {14, 14, 15, 2, 4, 1, strategyDfast}, // level 3
- {14, 14, 14, 4, 4, 2, strategyGreedy}, // level 4
- {14, 14, 14, 3, 4, 4, strategyLazy}, // level 5.
- {14, 14, 14, 4, 4, 8, strategyLazy2}, // level 6
- {14, 14, 14, 6, 4, 8, strategyLazy2}, // level 7
- {14, 14, 14, 8, 4, 8, strategyLazy2}, // level 8.
- {14, 15, 14, 5, 4, 8, strategyBtlazy2}, // level 9.
- {14, 15, 14, 9, 4, 8, strategyBtlazy2}, // level 10.
- {14, 15, 14, 3, 4, 12, strategyBtopt}, // level 11.
- {14, 15, 14, 4, 3, 24, strategyBtopt}, // level 12.
- {14, 15, 14, 5, 3, 32, strategyBtultra}, // level 13.
- {14, 15, 15, 6, 3, 64, strategyBtultra}, // level 14.
- {14, 15, 15, 7, 3, 256, strategyBtultra}, // level 15.
- {14, 15, 15, 5, 3, 48, strategyBtultra2}, // level 16.
- {14, 15, 15, 6, 3, 128, strategyBtultra2}, // level 17.
- {14, 15, 15, 7, 3, 256, strategyBtultra2}, // level 18.
- {14, 15, 15, 8, 3, 256, strategyBtultra2}, // level 19.
- {14, 15, 15, 8, 3, 512, strategyBtultra2}, // level 20.
- {14, 15, 15, 9, 3, 512, strategyBtultra2}, // level 21.
- {14, 15, 15, 10, 3, 999, strategyBtultra2}, // level 22.
- },
-}
-*/
diff --git a/vendor/github.com/klauspost/compress/zstd/encoder.go b/vendor/github.com/klauspost/compress/zstd/encoder.go
index 95ebc3d84..f5759211d 100644
--- a/vendor/github.com/klauspost/compress/zstd/encoder.go
+++ b/vendor/github.com/klauspost/compress/zstd/encoder.go
@@ -35,7 +35,7 @@ type encoder interface {
AppendCRC([]byte) []byte
WindowSize(size int) int32
UseBlock(*blockEnc)
- Reset(singleBlock bool)
+ Reset(d *dict, singleBlock bool)
}
type encoderState struct {
@@ -83,8 +83,6 @@ func (e *Encoder) initialize() {
e.encoders = make(chan encoder, e.o.concurrent)
for i := 0; i < e.o.concurrent; i++ {
enc := e.o.encoder()
- // If not single block, history will be allocated on first use.
- enc.Reset(true)
e.encoders <- enc
}
}
@@ -115,7 +113,7 @@ func (e *Encoder) Reset(w io.Writer) {
s.filling = s.filling[:0]
s.current = s.current[:0]
s.previous = s.previous[:0]
- s.encoder.Reset(false)
+ s.encoder.Reset(e.o.dict, false)
s.headerWritten = false
s.eofWritten = false
s.fullFrameWritten = false
@@ -200,8 +198,9 @@ func (e *Encoder) nextBlock(final bool) error {
WindowSize: uint32(s.encoder.WindowSize(0)),
SingleSegment: false,
Checksum: e.o.crc,
- DictID: 0,
+ DictID: e.o.dict.ID(),
}
+
dst, err := fh.appendTo(tmp[:0])
if err != nil {
return err
@@ -281,7 +280,7 @@ func (e *Encoder) nextBlock(final bool) error {
// If we got the exact same number of literals as input,
// assume the literals cannot be compressed.
if len(src) != len(blk.literals) || len(src) != e.o.blockSize {
- err = blk.encode(e.o.noEntropy, !e.o.allLitEntropy)
+ err = blk.encode(src, e.o.noEntropy, !e.o.allLitEntropy)
}
switch err {
case errIncompressible:
@@ -311,7 +310,13 @@ func (e *Encoder) ReadFrom(r io.Reader) (n int64, err error) {
if debug {
println("Using ReadFrom")
}
- // Maybe handle stuff queued?
+
+ // Flush any current writes.
+ if len(e.state.filling) > 0 {
+ if err := e.nextBlock(false); err != nil {
+ return 0, err
+ }
+ }
e.state.filling = e.state.filling[:e.o.blockSize]
src := e.state.filling
for {
@@ -328,7 +333,7 @@ func (e *Encoder) ReadFrom(r io.Reader) (n int64, err error) {
if debug {
println("ReadFrom: got EOF final block:", len(e.state.filling))
}
- return n, e.nextBlock(true)
+ return n, nil
default:
if debug {
println("ReadFrom: got error:", err)
@@ -450,7 +455,6 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
defer func() {
// Release encoder reference to last block.
// If a non-single block is needed the encoder will reset again.
- enc.Reset(true)
e.encoders <- enc
}()
// Use single segments when above minimum window and below 1MB.
@@ -463,7 +467,7 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
WindowSize: uint32(enc.WindowSize(len(src))),
SingleSegment: single,
Checksum: e.o.crc,
- DictID: 0,
+ DictID: e.o.dict.ID(),
}
// If less than 1MB, allocate a buffer up front.
@@ -477,13 +481,18 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
// If we can do everything in one block, prefer that.
if len(src) <= maxCompressedBlockSize {
+ enc.Reset(e.o.dict, true)
// Slightly faster with no history and everything in one block.
if e.o.crc {
_, _ = enc.CRC().Write(src)
}
blk := enc.Block()
blk.last = true
- enc.EncodeNoHist(blk, src)
+ if e.o.dict == nil {
+ enc.EncodeNoHist(blk, src)
+ } else {
+ enc.Encode(blk, src)
+ }
// If we got the exact same number of literals as input,
// assume the literals cannot be compressed.
@@ -492,7 +501,7 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
if len(blk.literals) != len(src) || len(src) != e.o.blockSize {
// Output directly to dst
blk.output = dst
- err = blk.encode(e.o.noEntropy, !e.o.allLitEntropy)
+ err = blk.encode(src, e.o.noEntropy, !e.o.allLitEntropy)
}
switch err {
@@ -508,7 +517,7 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
}
blk.output = oldout
} else {
- enc.Reset(false)
+ enc.Reset(e.o.dict, false)
blk := enc.Block()
for len(src) > 0 {
todo := src
@@ -519,7 +528,6 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
if e.o.crc {
_, _ = enc.CRC().Write(todo)
}
- blk.reset(nil)
blk.pushOffsets()
enc.Encode(blk, todo)
if len(src) == 0 {
@@ -529,7 +537,7 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
// If we got the exact same number of literals as input,
// assume the literals cannot be compressed.
if len(blk.literals) != len(todo) || len(todo) != e.o.blockSize {
- err = blk.encode(e.o.noEntropy, !e.o.allLitEntropy)
+ err = blk.encode(todo, e.o.noEntropy, !e.o.allLitEntropy)
}
switch err {
@@ -544,6 +552,7 @@ func (e *Encoder) EncodeAll(src, dst []byte) []byte {
default:
panic(err)
}
+ blk.reset(nil)
}
}
if e.o.crc {
diff --git a/vendor/github.com/klauspost/compress/zstd/encoder_options.go b/vendor/github.com/klauspost/compress/zstd/encoder_options.go
index dfac14ddd..579206163 100644
--- a/vendor/github.com/klauspost/compress/zstd/encoder_options.go
+++ b/vendor/github.com/klauspost/compress/zstd/encoder_options.go
@@ -24,6 +24,7 @@ type encoderOptions struct {
allLitEntropy bool
customWindow bool
customALEntropy bool
+ dict *dict
}
func (o *encoderOptions) setDefault() {
@@ -265,3 +266,16 @@ func WithSingleSegment(b bool) EOption {
return nil
}
}
+
+// WithEncoderDict allows to register a dictionary that will be used for the encode.
+// The encoder *may* choose to use no dictionary instead for certain payloads.
+func WithEncoderDict(dict []byte) EOption {
+ return func(o *encoderOptions) error {
+ d, err := loadDict(dict)
+ if err != nil {
+ return err
+ }
+ o.dict = d
+ return nil
+ }
+}
diff --git a/vendor/github.com/klauspost/compress/zstd/frameenc.go b/vendor/github.com/klauspost/compress/zstd/frameenc.go
index 4479cfe18..4ef7f5a3e 100644
--- a/vendor/github.com/klauspost/compress/zstd/frameenc.go
+++ b/vendor/github.com/klauspost/compress/zstd/frameenc.go
@@ -5,6 +5,7 @@
package zstd
import (
+ "encoding/binary"
"fmt"
"io"
"math"
@@ -16,7 +17,7 @@ type frameHeader struct {
WindowSize uint32
SingleSegment bool
Checksum bool
- DictID uint32 // Not stored.
+ DictID uint32
}
const maxHeaderSize = 14
@@ -30,6 +31,24 @@ func (f frameHeader) appendTo(dst []byte) ([]byte, error) {
if f.SingleSegment {
fhd |= 1 << 5
}
+
+ var dictIDContent []byte
+ if f.DictID > 0 {
+ var tmp [4]byte
+ if f.DictID < 256 {
+ fhd |= 1
+ tmp[0] = uint8(f.DictID)
+ dictIDContent = tmp[:1]
+ } else if f.DictID < 1<<16 {
+ fhd |= 2
+ binary.LittleEndian.PutUint16(tmp[:2], uint16(f.DictID))
+ dictIDContent = tmp[:2]
+ } else {
+ fhd |= 3
+ binary.LittleEndian.PutUint32(tmp[:4], f.DictID)
+ dictIDContent = tmp[:4]
+ }
+ }
var fcs uint8
if f.ContentSize >= 256 {
fcs++
@@ -40,6 +59,7 @@ func (f frameHeader) appendTo(dst []byte) ([]byte, error) {
if f.ContentSize >= 0xffffffff {
fcs++
}
+
fhd |= fcs << 6
dst = append(dst, fhd)
@@ -48,7 +68,9 @@ func (f frameHeader) appendTo(dst []byte) ([]byte, error) {
windowLog := (bits.Len32(f.WindowSize-1) - winLogMin) << 3
dst = append(dst, uint8(windowLog))
}
-
+ if f.DictID > 0 {
+ dst = append(dst, dictIDContent...)
+ }
switch fcs {
case 0:
if f.SingleSegment {
diff --git a/vendor/github.com/klauspost/compress/zstd/history.go b/vendor/github.com/klauspost/compress/zstd/history.go
index f418f50fc..f783e32d2 100644
--- a/vendor/github.com/klauspost/compress/zstd/history.go
+++ b/vendor/github.com/klauspost/compress/zstd/history.go
@@ -37,7 +37,7 @@ func (h *history) reset() {
}
h.decoders = sequenceDecs{}
if h.huffTree != nil {
- if h.dict == nil || h.dict.litDec != h.huffTree {
+ if h.dict == nil || h.dict.litEnc != h.huffTree {
huffDecoderPool.Put(h.huffTree)
}
}
@@ -55,7 +55,7 @@ func (h *history) setDict(dict *dict) {
h.decoders.offsets = dict.ofDec
h.decoders.matchLengths = dict.mlDec
h.recentOffsets = dict.offsets
- h.huffTree = dict.litDec
+ h.huffTree = dict.litEnc
}
// append bytes to history.
diff --git a/vendor/github.com/klauspost/compress/zstd/seqdec.go b/vendor/github.com/klauspost/compress/zstd/seqdec.go
index 7ff870400..b5c8ef133 100644
--- a/vendor/github.com/klauspost/compress/zstd/seqdec.go
+++ b/vendor/github.com/klauspost/compress/zstd/seqdec.go
@@ -196,6 +196,10 @@ func (s *sequenceDecs) decode(seqs int, br *bitReader, hist []byte) error {
s.literals = s.literals[ll:]
out := s.out
+ if mo == 0 && ml > 0 {
+ return fmt.Errorf("zero matchoff and matchlen (%d) > 0", ml)
+ }
+
if mo > len(s.out)+len(hist) || mo > s.windowSize {
if len(s.dict) == 0 {
return fmt.Errorf("match offset (%d) bigger than current history (%d)", mo, len(s.out)+len(hist))
@@ -218,10 +222,6 @@ func (s *sequenceDecs) decode(seqs int, br *bitReader, hist []byte) error {
}
}
- if mo == 0 && ml > 0 {
- return fmt.Errorf("zero matchoff and matchlen (%d) > 0", ml)
- }
-
// Copy from history.
// TODO: Blocks without history could be made to ignore this completely.
if v := mo - len(s.out); v > 0 {
diff --git a/vendor/github.com/klauspost/compress/zstd/snappy.go b/vendor/github.com/klauspost/compress/zstd/snappy.go
index 690428cd2..841fd95ac 100644
--- a/vendor/github.com/klauspost/compress/zstd/snappy.go
+++ b/vendor/github.com/klauspost/compress/zstd/snappy.go
@@ -111,7 +111,7 @@ func (r *SnappyConverter) Convert(in io.Reader, w io.Writer) (int64, error) {
// Add empty last block
r.block.reset(nil)
r.block.last = true
- err := r.block.encodeLits(false)
+ err := r.block.encodeLits(r.block.literals, false)
if err != nil {
return written, err
}
@@ -178,7 +178,7 @@ func (r *SnappyConverter) Convert(in io.Reader, w io.Writer) (int64, error) {
r.err = ErrSnappyCorrupt
return written, r.err
}
- err = r.block.encode(false, false)
+ err = r.block.encode(nil, false, false)
switch err {
case errIncompressible:
r.block.popOffsets()
@@ -188,7 +188,7 @@ func (r *SnappyConverter) Convert(in io.Reader, w io.Writer) (int64, error) {
println("snappy.Decode:", err)
return written, err
}
- err = r.block.encodeLits(false)
+ err = r.block.encodeLits(r.block.literals, false)
if err != nil {
return written, err
}
@@ -235,7 +235,7 @@ func (r *SnappyConverter) Convert(in io.Reader, w io.Writer) (int64, error) {
r.err = ErrSnappyCorrupt
return written, r.err
}
- err := r.block.encodeLits(false)
+ err := r.block.encodeLits(r.block.literals, false)
if err != nil {
return written, err
}
diff --git a/vendor/github.com/klauspost/pgzip/.travis.yml b/vendor/github.com/klauspost/pgzip/.travis.yml
index 6e9fca0ba..acfec4bb0 100644
--- a/vendor/github.com/klauspost/pgzip/.travis.yml
+++ b/vendor/github.com/klauspost/pgzip/.travis.yml
@@ -1,19 +1,22 @@
language: go
-sudo: false
-
os:
- linux
- osx
go:
- - 1.9.x
- - 1.10.x
+ - 1.13.x
+ - 1.14.x
+ - 1.15.x
- master
-script:
- - go test -v -cpu=1,2,4 .
- - go test -v -cpu=2 -race -short .
+env:
+ - GO111MODULE=off
+
+script:
+ - diff <(gofmt -d .) <(printf "")
+ - go test -v -cpu=1,2,4 .
+ - go test -v -cpu=2 -race -short .
matrix:
allow_failures:
diff --git a/vendor/github.com/klauspost/pgzip/gunzip.go b/vendor/github.com/klauspost/pgzip/gunzip.go
index 93efec714..d1ae730b2 100644
--- a/vendor/github.com/klauspost/pgzip/gunzip.go
+++ b/vendor/github.com/klauspost/pgzip/gunzip.go
@@ -331,6 +331,16 @@ func (z *Reader) killReadAhead() error {
// Wait for decompressor to be closed and return error, if any.
e, ok := <-z.closeErr
z.activeRA = false
+
+ for blk := range z.readAhead {
+ if blk.b != nil {
+ z.blockPool <- blk.b
+ }
+ }
+ if cap(z.current) > 0 {
+ z.blockPool <- z.current
+ z.current = nil
+ }
if !ok {
// Channel is closed, so if there was any error it has already been returned.
return nil
@@ -418,6 +428,7 @@ func (z *Reader) doReadAhead() {
case z.readAhead <- read{b: buf, err: err}:
case <-closeReader:
// Sent on close, we don't care about the next results
+ z.blockPool <- buf
return
}
if err != nil {
diff --git a/vendor/github.com/mattn/go-isatty/.travis.yml b/vendor/github.com/mattn/go-isatty/.travis.yml
deleted file mode 100644
index 604314dd4..000000000
--- a/vendor/github.com/mattn/go-isatty/.travis.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-language: go
-sudo: false
-go:
- - 1.13.x
- - tip
-
-before_install:
- - go get -t -v ./...
-
-script:
- - ./go.test.sh
-
-after_success:
- - bash <(curl -s https://codecov.io/bash)
diff --git a/vendor/github.com/mattn/go-isatty/LICENSE b/vendor/github.com/mattn/go-isatty/LICENSE
deleted file mode 100644
index 65dc692b6..000000000
--- a/vendor/github.com/mattn/go-isatty/LICENSE
+++ /dev/null
@@ -1,9 +0,0 @@
-Copyright (c) Yasuhiro MATSUMOTO <mattn.jp@gmail.com>
-
-MIT License (Expat)
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/mattn/go-isatty/README.md b/vendor/github.com/mattn/go-isatty/README.md
deleted file mode 100644
index 38418353e..000000000
--- a/vendor/github.com/mattn/go-isatty/README.md
+++ /dev/null
@@ -1,50 +0,0 @@
-# go-isatty
-
-[![Godoc Reference](https://godoc.org/github.com/mattn/go-isatty?status.svg)](http://godoc.org/github.com/mattn/go-isatty)
-[![Codecov](https://codecov.io/gh/mattn/go-isatty/branch/master/graph/badge.svg)](https://codecov.io/gh/mattn/go-isatty)
-[![Coverage Status](https://coveralls.io/repos/github/mattn/go-isatty/badge.svg?branch=master)](https://coveralls.io/github/mattn/go-isatty?branch=master)
-[![Go Report Card](https://goreportcard.com/badge/mattn/go-isatty)](https://goreportcard.com/report/mattn/go-isatty)
-
-isatty for golang
-
-## Usage
-
-```go
-package main
-
-import (
- "fmt"
- "github.com/mattn/go-isatty"
- "os"
-)
-
-func main() {
- if isatty.IsTerminal(os.Stdout.Fd()) {
- fmt.Println("Is Terminal")
- } else if isatty.IsCygwinTerminal(os.Stdout.Fd()) {
- fmt.Println("Is Cygwin/MSYS2 Terminal")
- } else {
- fmt.Println("Is Not Terminal")
- }
-}
-```
-
-## Installation
-
-```
-$ go get github.com/mattn/go-isatty
-```
-
-## License
-
-MIT
-
-## Author
-
-Yasuhiro Matsumoto (a.k.a mattn)
-
-## Thanks
-
-* k-takata: base idea for IsCygwinTerminal
-
- https://github.com/k-takata/go-iscygpty
diff --git a/vendor/github.com/mattn/go-isatty/doc.go b/vendor/github.com/mattn/go-isatty/doc.go
deleted file mode 100644
index 17d4f90eb..000000000
--- a/vendor/github.com/mattn/go-isatty/doc.go
+++ /dev/null
@@ -1,2 +0,0 @@
-// Package isatty implements interface to isatty
-package isatty
diff --git a/vendor/github.com/mattn/go-isatty/go.mod b/vendor/github.com/mattn/go-isatty/go.mod
deleted file mode 100644
index 605c4c221..000000000
--- a/vendor/github.com/mattn/go-isatty/go.mod
+++ /dev/null
@@ -1,5 +0,0 @@
-module github.com/mattn/go-isatty
-
-go 1.12
-
-require golang.org/x/sys v0.0.0-20200116001909-b77594299b42
diff --git a/vendor/github.com/mattn/go-isatty/go.sum b/vendor/github.com/mattn/go-isatty/go.sum
deleted file mode 100644
index 912e29cbc..000000000
--- a/vendor/github.com/mattn/go-isatty/go.sum
+++ /dev/null
@@ -1,2 +0,0 @@
-golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
-golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/vendor/github.com/mattn/go-isatty/go.test.sh b/vendor/github.com/mattn/go-isatty/go.test.sh
deleted file mode 100644
index 012162b07..000000000
--- a/vendor/github.com/mattn/go-isatty/go.test.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-echo "" > coverage.txt
-
-for d in $(go list ./... | grep -v vendor); do
- go test -race -coverprofile=profile.out -covermode=atomic "$d"
- if [ -f profile.out ]; then
- cat profile.out >> coverage.txt
- rm profile.out
- fi
-done
diff --git a/vendor/github.com/mattn/go-isatty/isatty_bsd.go b/vendor/github.com/mattn/go-isatty/isatty_bsd.go
deleted file mode 100644
index 711f28808..000000000
--- a/vendor/github.com/mattn/go-isatty/isatty_bsd.go
+++ /dev/null
@@ -1,18 +0,0 @@
-// +build darwin freebsd openbsd netbsd dragonfly
-// +build !appengine
-
-package isatty
-
-import "golang.org/x/sys/unix"
-
-// IsTerminal return true if the file descriptor is terminal.
-func IsTerminal(fd uintptr) bool {
- _, err := unix.IoctlGetTermios(int(fd), unix.TIOCGETA)
- return err == nil
-}
-
-// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
-// terminal. This is also always false on this environment.
-func IsCygwinTerminal(fd uintptr) bool {
- return false
-}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_others.go b/vendor/github.com/mattn/go-isatty/isatty_others.go
deleted file mode 100644
index ff714a376..000000000
--- a/vendor/github.com/mattn/go-isatty/isatty_others.go
+++ /dev/null
@@ -1,15 +0,0 @@
-// +build appengine js nacl
-
-package isatty
-
-// IsTerminal returns true if the file descriptor is terminal which
-// is always false on js and appengine classic which is a sandboxed PaaS.
-func IsTerminal(fd uintptr) bool {
- return false
-}
-
-// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
-// terminal. This is also always false on this environment.
-func IsCygwinTerminal(fd uintptr) bool {
- return false
-}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_plan9.go b/vendor/github.com/mattn/go-isatty/isatty_plan9.go
deleted file mode 100644
index c5b6e0c08..000000000
--- a/vendor/github.com/mattn/go-isatty/isatty_plan9.go
+++ /dev/null
@@ -1,22 +0,0 @@
-// +build plan9
-
-package isatty
-
-import (
- "syscall"
-)
-
-// IsTerminal returns true if the given file descriptor is a terminal.
-func IsTerminal(fd uintptr) bool {
- path, err := syscall.Fd2path(int(fd))
- if err != nil {
- return false
- }
- return path == "/dev/cons" || path == "/mnt/term/dev/cons"
-}
-
-// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
-// terminal. This is also always false on this environment.
-func IsCygwinTerminal(fd uintptr) bool {
- return false
-}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_solaris.go b/vendor/github.com/mattn/go-isatty/isatty_solaris.go
deleted file mode 100644
index bdd5c79a0..000000000
--- a/vendor/github.com/mattn/go-isatty/isatty_solaris.go
+++ /dev/null
@@ -1,22 +0,0 @@
-// +build solaris
-// +build !appengine
-
-package isatty
-
-import (
- "golang.org/x/sys/unix"
-)
-
-// IsTerminal returns true if the given file descriptor is a terminal.
-// see: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c
-func IsTerminal(fd uintptr) bool {
- var termio unix.Termio
- err := unix.IoctlSetTermio(int(fd), unix.TCGETA, &termio)
- return err == nil
-}
-
-// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
-// terminal. This is also always false on this environment.
-func IsCygwinTerminal(fd uintptr) bool {
- return false
-}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_tcgets.go b/vendor/github.com/mattn/go-isatty/isatty_tcgets.go
deleted file mode 100644
index 31a1ca973..000000000
--- a/vendor/github.com/mattn/go-isatty/isatty_tcgets.go
+++ /dev/null
@@ -1,18 +0,0 @@
-// +build linux aix
-// +build !appengine
-
-package isatty
-
-import "golang.org/x/sys/unix"
-
-// IsTerminal return true if the file descriptor is terminal.
-func IsTerminal(fd uintptr) bool {
- _, err := unix.IoctlGetTermios(int(fd), unix.TCGETS)
- return err == nil
-}
-
-// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
-// terminal. This is also always false on this environment.
-func IsCygwinTerminal(fd uintptr) bool {
- return false
-}
diff --git a/vendor/github.com/mattn/go-isatty/isatty_windows.go b/vendor/github.com/mattn/go-isatty/isatty_windows.go
deleted file mode 100644
index 1fa869154..000000000
--- a/vendor/github.com/mattn/go-isatty/isatty_windows.go
+++ /dev/null
@@ -1,125 +0,0 @@
-// +build windows
-// +build !appengine
-
-package isatty
-
-import (
- "errors"
- "strings"
- "syscall"
- "unicode/utf16"
- "unsafe"
-)
-
-const (
- objectNameInfo uintptr = 1
- fileNameInfo = 2
- fileTypePipe = 3
-)
-
-var (
- kernel32 = syscall.NewLazyDLL("kernel32.dll")
- ntdll = syscall.NewLazyDLL("ntdll.dll")
- procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
- procGetFileInformationByHandleEx = kernel32.NewProc("GetFileInformationByHandleEx")
- procGetFileType = kernel32.NewProc("GetFileType")
- procNtQueryObject = ntdll.NewProc("NtQueryObject")
-)
-
-func init() {
- // Check if GetFileInformationByHandleEx is available.
- if procGetFileInformationByHandleEx.Find() != nil {
- procGetFileInformationByHandleEx = nil
- }
-}
-
-// IsTerminal return true if the file descriptor is terminal.
-func IsTerminal(fd uintptr) bool {
- var st uint32
- r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
- return r != 0 && e == 0
-}
-
-// Check pipe name is used for cygwin/msys2 pty.
-// Cygwin/MSYS2 PTY has a name like:
-// \{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master
-func isCygwinPipeName(name string) bool {
- token := strings.Split(name, "-")
- if len(token) < 5 {
- return false
- }
-
- if token[0] != `\msys` &&
- token[0] != `\cygwin` &&
- token[0] != `\Device\NamedPipe\msys` &&
- token[0] != `\Device\NamedPipe\cygwin` {
- return false
- }
-
- if token[1] == "" {
- return false
- }
-
- if !strings.HasPrefix(token[2], "pty") {
- return false
- }
-
- if token[3] != `from` && token[3] != `to` {
- return false
- }
-
- if token[4] != "master" {
- return false
- }
-
- return true
-}
-
-// getFileNameByHandle use the undocomented ntdll NtQueryObject to get file full name from file handler
-// since GetFileInformationByHandleEx is not avilable under windows Vista and still some old fashion
-// guys are using Windows XP, this is a workaround for those guys, it will also work on system from
-// Windows vista to 10
-// see https://stackoverflow.com/a/18792477 for details
-func getFileNameByHandle(fd uintptr) (string, error) {
- if procNtQueryObject == nil {
- return "", errors.New("ntdll.dll: NtQueryObject not supported")
- }
-
- var buf [4 + syscall.MAX_PATH]uint16
- var result int
- r, _, e := syscall.Syscall6(procNtQueryObject.Addr(), 5,
- fd, objectNameInfo, uintptr(unsafe.Pointer(&buf)), uintptr(2*len(buf)), uintptr(unsafe.Pointer(&result)), 0)
- if r != 0 {
- return "", e
- }
- return string(utf16.Decode(buf[4 : 4+buf[0]/2])), nil
-}
-
-// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
-// terminal.
-func IsCygwinTerminal(fd uintptr) bool {
- if procGetFileInformationByHandleEx == nil {
- name, err := getFileNameByHandle(fd)
- if err != nil {
- return false
- }
- return isCygwinPipeName(name)
- }
-
- // Cygwin/msys's pty is a pipe.
- ft, _, e := syscall.Syscall(procGetFileType.Addr(), 1, fd, 0, 0)
- if ft != fileTypePipe || e != 0 {
- return false
- }
-
- var buf [2 + syscall.MAX_PATH]uint16
- r, _, e := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(),
- 4, fd, fileNameInfo, uintptr(unsafe.Pointer(&buf)),
- uintptr(len(buf)*2), 0, 0)
- if r == 0 || e != 0 {
- return false
- }
-
- l := *(*uint32)(unsafe.Pointer(&buf))
- return isCygwinPipeName(string(utf16.Decode(buf[2 : 2+l/2])))
-}
diff --git a/vendor/github.com/mattn/go-isatty/renovate.json b/vendor/github.com/mattn/go-isatty/renovate.json
deleted file mode 100644
index 5ae9d96b7..000000000
--- a/vendor/github.com/mattn/go-isatty/renovate.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "extends": [
- "config:base"
- ],
- "postUpdateOptions": [
- "gomodTidy"
- ]
-}
diff --git a/vendor/github.com/moby/sys/mountinfo/LICENSE b/vendor/github.com/moby/sys/mountinfo/LICENSE
new file mode 100644
index 000000000..d64569567
--- /dev/null
+++ b/vendor/github.com/moby/sys/mountinfo/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/moby/sys/mountinfo/go.mod b/vendor/github.com/moby/sys/mountinfo/go.mod
new file mode 100644
index 000000000..10d9a15a6
--- /dev/null
+++ b/vendor/github.com/moby/sys/mountinfo/go.mod
@@ -0,0 +1,3 @@
+module github.com/moby/sys/mountinfo
+
+go 1.14
diff --git a/vendor/github.com/moby/sys/mountinfo/mountinfo.go b/vendor/github.com/moby/sys/mountinfo/mountinfo.go
new file mode 100644
index 000000000..136b14167
--- /dev/null
+++ b/vendor/github.com/moby/sys/mountinfo/mountinfo.go
@@ -0,0 +1,67 @@
+package mountinfo
+
+import "io"
+
+// GetMounts retrieves a list of mounts for the current running process,
+// with an optional filter applied (use nil for no filter).
+func GetMounts(f FilterFunc) ([]*Info, error) {
+ return parseMountTable(f)
+}
+
+// GetMountsFromReader retrieves a list of mounts from the
+// reader provided, with an optional filter applied (use nil
+// for no filter). This can be useful in tests or benchmarks
+// that provide a fake mountinfo data.
+func GetMountsFromReader(reader io.Reader, f FilterFunc) ([]*Info, error) {
+ return parseInfoFile(reader, f)
+}
+
+// Mounted determines if a specified mountpoint has been mounted.
+// On Linux it looks at /proc/self/mountinfo.
+func Mounted(mountpoint string) (bool, error) {
+ entries, err := GetMounts(SingleEntryFilter(mountpoint))
+ if err != nil {
+ return false, err
+ }
+
+ return len(entries) > 0, nil
+}
+
+// Info reveals information about a particular mounted filesystem. This
+// struct is populated from the content in the /proc/<pid>/mountinfo file.
+type Info struct {
+ // ID is a unique identifier of the mount (may be reused after umount).
+ ID int
+
+ // Parent indicates the ID of the mount parent (or of self for the top of the
+ // mount tree).
+ Parent int
+
+ // Major indicates one half of the device ID which identifies the device class.
+ Major int
+
+ // Minor indicates one half of the device ID which identifies a specific
+ // instance of device.
+ Minor int
+
+ // Root of the mount within the filesystem.
+ Root string
+
+ // Mountpoint indicates the mount point relative to the process's root.
+ Mountpoint string
+
+ // Opts represents mount-specific options.
+ Opts string
+
+ // Optional represents optional fields.
+ Optional string
+
+ // Fstype indicates the type of filesystem, such as EXT3.
+ Fstype string
+
+ // Source indicates filesystem specific information or "none".
+ Source string
+
+ // VfsOpts represents per super block options.
+ VfsOpts string
+}
diff --git a/vendor/github.com/moby/sys/mountinfo/mountinfo_filters.go b/vendor/github.com/moby/sys/mountinfo/mountinfo_filters.go
new file mode 100644
index 000000000..795026465
--- /dev/null
+++ b/vendor/github.com/moby/sys/mountinfo/mountinfo_filters.go
@@ -0,0 +1,58 @@
+package mountinfo
+
+import "strings"
+
+// FilterFunc is a type defining a callback function for GetMount(),
+// used to filter out mountinfo entries we're not interested in,
+// and/or stop further processing if we found what we wanted.
+//
+// It takes a pointer to the Info struct (not fully populated,
+// currently only Mountpoint, Fstype, Source, and (on Linux)
+// VfsOpts are filled in), and returns two booleans:
+//
+// - skip: true if the entry should be skipped
+// - stop: true if parsing should be stopped after the entry
+type FilterFunc func(*Info) (skip, stop bool)
+
+// PrefixFilter discards all entries whose mount points
+// do not start with a specific prefix
+func PrefixFilter(prefix string) FilterFunc {
+ return func(m *Info) (bool, bool) {
+ skip := !strings.HasPrefix(m.Mountpoint, prefix)
+ return skip, false
+ }
+}
+
+// SingleEntryFilter looks for a specific entry
+func SingleEntryFilter(mp string) FilterFunc {
+ return func(m *Info) (bool, bool) {
+ if m.Mountpoint == mp {
+ return false, true // don't skip, stop now
+ }
+ return true, false // skip, keep going
+ }
+}
+
+// ParentsFilter returns all entries whose mount points
+// can be parents of a path specified, discarding others.
+//
+// For example, given `/var/lib/docker/something`, entries
+// like `/var/lib/docker`, `/var` and `/` are returned.
+func ParentsFilter(path string) FilterFunc {
+ return func(m *Info) (bool, bool) {
+ skip := !strings.HasPrefix(path, m.Mountpoint)
+ return skip, false
+ }
+}
+
+// FstypeFilter returns all entries that match provided fstype(s).
+func FstypeFilter(fstype ...string) FilterFunc {
+ return func(m *Info) (bool, bool) {
+ for _, t := range fstype {
+ if m.Fstype == t {
+ return false, false // don't skeep, keep going
+ }
+ }
+ return true, false // skip, keep going
+ }
+}
diff --git a/vendor/github.com/containers/storage/pkg/mount/mountinfo_freebsd.go b/vendor/github.com/moby/sys/mountinfo/mountinfo_freebsd.go
index 4f32edcd9..a7dbb1b46 100644
--- a/vendor/github.com/containers/storage/pkg/mount/mountinfo_freebsd.go
+++ b/vendor/github.com/moby/sys/mountinfo/mountinfo_freebsd.go
@@ -1,4 +1,4 @@
-package mount
+package mountinfo
/*
#include <sys/param.h>
@@ -13,9 +13,8 @@ import (
"unsafe"
)
-// Parse /proc/self/mountinfo because comparing Dev and ino does not work from
-// bind mounts.
-func parseMountTable() ([]*Info, error) {
+// parseMountTable returns information about mounted filesystems
+func parseMountTable(filter FilterFunc) ([]*Info, error) {
var rawEntries *C.struct_statfs
count := int(C.getmntinfo(&rawEntries, C.MNT_WAIT))
@@ -32,10 +31,23 @@ func parseMountTable() ([]*Info, error) {
var out []*Info
for _, entry := range entries {
var mountinfo Info
+ var skip, stop bool
mountinfo.Mountpoint = C.GoString(&entry.f_mntonname[0])
- mountinfo.Source = C.GoString(&entry.f_mntfromname[0])
mountinfo.Fstype = C.GoString(&entry.f_fstypename[0])
+ mountinfo.Source = C.GoString(&entry.f_mntfromname[0])
+
+ if filter != nil {
+ // filter out entries we're not interested in
+ skip, stop = filter(&mountinfo)
+ if skip {
+ continue
+ }
+ }
+
out = append(out, &mountinfo)
+ if stop {
+ break
+ }
}
return out, nil
}
diff --git a/vendor/github.com/moby/sys/mountinfo/mountinfo_linux.go b/vendor/github.com/moby/sys/mountinfo/mountinfo_linux.go
new file mode 100644
index 000000000..2d630c8dc
--- /dev/null
+++ b/vendor/github.com/moby/sys/mountinfo/mountinfo_linux.go
@@ -0,0 +1,152 @@
+// +build go1.13
+
+package mountinfo
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "os"
+ "strconv"
+ "strings"
+)
+
+func parseInfoFile(r io.Reader, filter FilterFunc) ([]*Info, error) {
+ s := bufio.NewScanner(r)
+ out := []*Info{}
+ var err error
+ for s.Scan() {
+ if err = s.Err(); err != nil {
+ return nil, err
+ }
+ /*
+ See http://man7.org/linux/man-pages/man5/proc.5.html
+
+ 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
+ (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
+
+ (1) mount ID: unique identifier of the mount (may be reused after umount)
+ (2) parent ID: ID of parent (or of self for the top of the mount tree)
+ (3) major:minor: value of st_dev for files on filesystem
+ (4) root: root of the mount within the filesystem
+ (5) mount point: mount point relative to the process's root
+ (6) mount options: per mount options
+ (7) optional fields: zero or more fields of the form "tag[:value]"
+ (8) separator: marks the end of the optional fields
+ (9) filesystem type: name of filesystem of the form "type[.subtype]"
+ (10) mount source: filesystem specific information or "none"
+ (11) super options: per super block options
+
+ In other words, we have:
+ * 6 mandatory fields (1)..(6)
+ * 0 or more optional fields (7)
+ * a separator field (8)
+ * 3 mandatory fields (9)..(11)
+ */
+
+ text := s.Text()
+ fields := strings.Split(text, " ")
+ numFields := len(fields)
+ if numFields < 10 {
+ // should be at least 10 fields
+ return nil, fmt.Errorf("Parsing '%s' failed: not enough fields (%d)", text, numFields)
+ }
+
+ // separator field
+ sepIdx := numFields - 4
+ // In Linux <= 3.9 mounting a cifs with spaces in a share
+ // name (like "//srv/My Docs") _may_ end up having a space
+ // in the last field of mountinfo (like "unc=//serv/My Docs").
+ // Since kernel 3.10-rc1, cifs option "unc=" is ignored,
+ // so spaces should not appear.
+ //
+ // Check for a separator, and work around the spaces bug
+ for fields[sepIdx] != "-" {
+ sepIdx--
+ if sepIdx == 5 {
+ return nil, fmt.Errorf("Parsing '%s' failed: missing - separator", text)
+ }
+ }
+
+ p := &Info{}
+
+ // Fill in the fields that a filter might check
+ p.Mountpoint, err = strconv.Unquote(`"` + fields[4] + `"`)
+ if err != nil {
+ return nil, fmt.Errorf("Parsing '%s' failed: unable to unquote mount point field: %w", fields[4], err)
+ }
+ p.Fstype = fields[sepIdx+1]
+ p.Source = fields[sepIdx+2]
+ p.VfsOpts = fields[sepIdx+3]
+
+ // Run a filter soon so we can skip parsing/adding entries
+ // the caller is not interested in
+ var skip, stop bool
+ if filter != nil {
+ skip, stop = filter(p)
+ if skip {
+ continue
+ }
+ }
+
+ // Fill in the rest of the fields
+
+ // ignore any numbers parsing errors, as there should not be any
+ p.ID, _ = strconv.Atoi(fields[0])
+ p.Parent, _ = strconv.Atoi(fields[1])
+ mm := strings.Split(fields[2], ":")
+ if len(mm) != 2 {
+ return nil, fmt.Errorf("Parsing '%s' failed: unexpected minor:major pair %s", text, mm)
+ }
+ p.Major, _ = strconv.Atoi(mm[0])
+ p.Minor, _ = strconv.Atoi(mm[1])
+
+ p.Root, err = strconv.Unquote(`"` + fields[3] + `"`)
+ if err != nil {
+ return nil, fmt.Errorf("Parsing '%s' failed: unable to unquote root field: %w", fields[3], err)
+ }
+
+ p.Opts = fields[5]
+
+ // zero or more optional fields
+ switch {
+ case sepIdx == 6:
+ // zero, do nothing
+ case sepIdx == 7:
+ p.Optional = fields[6]
+ default:
+ p.Optional = strings.Join(fields[6:sepIdx-1], " ")
+ }
+
+ out = append(out, p)
+ if stop {
+ break
+ }
+ }
+ return out, nil
+}
+
+// Parse /proc/self/mountinfo because comparing Dev and ino does not work from
+// bind mounts
+func parseMountTable(filter FilterFunc) ([]*Info, error) {
+ f, err := os.Open("/proc/self/mountinfo")
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ return parseInfoFile(f, filter)
+}
+
+// PidMountInfo collects the mounts for a specific process ID. If the process
+// ID is unknown, it is better to use `GetMounts` which will inspect
+// "/proc/self/mountinfo" instead.
+func PidMountInfo(pid int) ([]*Info, error) {
+ f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid))
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ return parseInfoFile(f, nil)
+}
diff --git a/vendor/github.com/moby/sys/mountinfo/mountinfo_unsupported.go b/vendor/github.com/moby/sys/mountinfo/mountinfo_unsupported.go
new file mode 100644
index 000000000..dc1869211
--- /dev/null
+++ b/vendor/github.com/moby/sys/mountinfo/mountinfo_unsupported.go
@@ -0,0 +1,17 @@
+// +build !windows,!linux,!freebsd freebsd,!cgo
+
+package mountinfo
+
+import (
+ "fmt"
+ "io"
+ "runtime"
+)
+
+func parseMountTable(_ FilterFunc) ([]*Info, error) {
+ return nil, fmt.Errorf("mount.parseMountTable is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+}
+
+func parseInfoFile(_ io.Reader, f FilterFunc) ([]*Info, error) {
+ return parseMountTable(f)
+}
diff --git a/vendor/github.com/moby/sys/mountinfo/mountinfo_windows.go b/vendor/github.com/moby/sys/mountinfo/mountinfo_windows.go
new file mode 100644
index 000000000..69ffdc52b
--- /dev/null
+++ b/vendor/github.com/moby/sys/mountinfo/mountinfo_windows.go
@@ -0,0 +1,12 @@
+package mountinfo
+
+import "io"
+
+func parseMountTable(_ FilterFunc) ([]*Info, error) {
+ // Do NOT return an error!
+ return nil, nil
+}
+
+func parseInfoFile(_ io.Reader, f FilterFunc) ([]*Info, error) {
+ return parseMountTable(f)
+}
diff --git a/vendor/github.com/onsi/ginkgo/CHANGELOG.md b/vendor/github.com/onsi/ginkgo/CHANGELOG.md
index bdf18327e..6092fcb63 100644
--- a/vendor/github.com/onsi/ginkgo/CHANGELOG.md
+++ b/vendor/github.com/onsi/ginkgo/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 1.14.1
+
+### Fixes
+- Discard exported method declaration when running ginkgo bootstrap (#558) [f4b0240]
+
## 1.14.0
### Features
diff --git a/vendor/github.com/onsi/ginkgo/README.md b/vendor/github.com/onsi/ginkgo/README.md
index fab114580..475e04994 100644
--- a/vendor/github.com/onsi/ginkgo/README.md
+++ b/vendor/github.com/onsi/ginkgo/README.md
@@ -80,10 +80,11 @@ Agouti allows you run WebDriver integration tests. Learn more about Agouti [her
You'll need the Go command-line tools. Follow the [installation instructions](https://golang.org/doc/install) if you don't have it installed.
### Global installation
-To install the Ginkgo command line interface into the `$PATH` (actually to `$GOBIN`):
+To install the Ginkgo command line interface:
```bash
go get -u github.com/onsi/ginkgo/ginkgo
```
+Note that this will install it to `$GOBIN`, which will need to be in the `$PATH` (or equivalent). Run `go help install` for more information.
### Go module ["tools package"](https://github.com/golang/go/issues/25922):
Create (or update) a file called `tools/tools.go` with the following contents:
@@ -93,7 +94,7 @@ Create (or update) a file called `tools/tools.go` with the following contents:
package tools
import (
- _ "github.com/onsi/ginkgo"
+ _ "github.com/onsi/ginkgo/ginkgo"
)
// This file imports packages that are used when running go generate, or used
diff --git a/vendor/github.com/onsi/ginkgo/config/config.go b/vendor/github.com/onsi/ginkgo/config/config.go
index 2ae48b804..feef2bcd6 100644
--- a/vendor/github.com/onsi/ginkgo/config/config.go
+++ b/vendor/github.com/onsi/ginkgo/config/config.go
@@ -20,7 +20,7 @@ import (
"fmt"
)
-const VERSION = "1.14.0"
+const VERSION = "1.14.1"
type GinkgoConfigType struct {
RandomSeed int64
diff --git a/vendor/github.com/onsi/ginkgo/ginkgo/nodot/nodot.go b/vendor/github.com/onsi/ginkgo/ginkgo/nodot/nodot.go
index 3f7237c60..c87b72165 100644
--- a/vendor/github.com/onsi/ginkgo/ginkgo/nodot/nodot.go
+++ b/vendor/github.com/onsi/ginkgo/ginkgo/nodot/nodot.go
@@ -186,7 +186,9 @@ func getExportedDeclarationsForFile(path string) ([]string, error) {
declarations = append(declarations, s.Names[0].Name)
}
case *ast.FuncDecl:
- declarations = append(declarations, x.Name.Name)
+ if x.Recv == nil {
+ declarations = append(declarations, x.Name.Name)
+ }
}
}
diff --git a/vendor/github.com/onsi/gomega/CHANGELOG.md b/vendor/github.com/onsi/gomega/CHANGELOG.md
index 3aafdbcfc..0b6c2fb61 100644
--- a/vendor/github.com/onsi/gomega/CHANGELOG.md
+++ b/vendor/github.com/onsi/gomega/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 1.10.2
+
+### Fixes
+- Add ExpectWithOffset, EventuallyWithOffset and ConsistentlyWithOffset to WithT (#391) [990941a]
+
## 1.10.1
### Fixes
diff --git a/vendor/github.com/onsi/gomega/gomega_dsl.go b/vendor/github.com/onsi/gomega/gomega_dsl.go
index 8ff9611d5..b416d20cc 100644
--- a/vendor/github.com/onsi/gomega/gomega_dsl.go
+++ b/vendor/github.com/onsi/gomega/gomega_dsl.go
@@ -24,7 +24,7 @@ import (
"github.com/onsi/gomega/types"
)
-const GOMEGA_VERSION = "1.10.1"
+const GOMEGA_VERSION = "1.10.2"
const nilFailHandlerPanic = `You are trying to make an assertion, but Gomega's fail handler is nil.
If you're using Ginkgo then you probably forgot to put your assertion in an It().
@@ -376,13 +376,13 @@ func NewGomegaWithT(t types.GomegaTestingT) *GomegaWithT {
return NewWithT(t)
}
-// Expect is used to make assertions. See documentation for Expect.
-func (g *WithT) Expect(actual interface{}, extra ...interface{}) Assertion {
- return assertion.New(actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), 0, extra...)
+// ExpectWithOffset is used to make assertions. See documentation for ExpectWithOffset.
+func (g *WithT) ExpectWithOffset(offset int, actual interface{}, extra ...interface{}) Assertion {
+ return assertion.New(actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), offset, extra...)
}
-// Eventually is used to make asynchronous assertions. See documentation for Eventually.
-func (g *WithT) Eventually(actual interface{}, intervals ...interface{}) AsyncAssertion {
+// EventuallyWithOffset is used to make asynchronous assertions. See documentation for EventuallyWithOffset.
+func (g *WithT) EventuallyWithOffset(offset int, actual interface{}, intervals ...interface{}) AsyncAssertion {
timeoutInterval := defaultEventuallyTimeout
pollingInterval := defaultEventuallyPollingInterval
if len(intervals) > 0 {
@@ -391,11 +391,11 @@ func (g *WithT) Eventually(actual interface{}, intervals ...interface{}) AsyncAs
if len(intervals) > 1 {
pollingInterval = toDuration(intervals[1])
}
- return asyncassertion.New(asyncassertion.AsyncAssertionTypeEventually, actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), timeoutInterval, pollingInterval, 0)
+ return asyncassertion.New(asyncassertion.AsyncAssertionTypeEventually, actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), timeoutInterval, pollingInterval, offset)
}
-// Consistently is used to make asynchronous assertions. See documentation for Consistently.
-func (g *WithT) Consistently(actual interface{}, intervals ...interface{}) AsyncAssertion {
+// ConsistentlyWithOffset is used to make asynchronous assertions. See documentation for ConsistentlyWithOffset.
+func (g *WithT) ConsistentlyWithOffset(offset int, actual interface{}, intervals ...interface{}) AsyncAssertion {
timeoutInterval := defaultConsistentlyDuration
pollingInterval := defaultConsistentlyPollingInterval
if len(intervals) > 0 {
@@ -404,7 +404,22 @@ func (g *WithT) Consistently(actual interface{}, intervals ...interface{}) Async
if len(intervals) > 1 {
pollingInterval = toDuration(intervals[1])
}
- return asyncassertion.New(asyncassertion.AsyncAssertionTypeConsistently, actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), timeoutInterval, pollingInterval, 0)
+ return asyncassertion.New(asyncassertion.AsyncAssertionTypeConsistently, actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), timeoutInterval, pollingInterval, offset)
+}
+
+// Expect is used to make assertions. See documentation for Expect.
+func (g *WithT) Expect(actual interface{}, extra ...interface{}) Assertion {
+ return g.ExpectWithOffset(0, actual, extra...)
+}
+
+// Eventually is used to make asynchronous assertions. See documentation for Eventually.
+func (g *WithT) Eventually(actual interface{}, intervals ...interface{}) AsyncAssertion {
+ return g.EventuallyWithOffset(0, actual, intervals...)
+}
+
+// Consistently is used to make asynchronous assertions. See documentation for Consistently.
+func (g *WithT) Consistently(actual interface{}, intervals ...interface{}) AsyncAssertion {
+ return g.ConsistentlyWithOffset(0, actual, intervals...)
}
func toDuration(input interface{}) time.Duration {
diff --git a/vendor/github.com/ulikunitz/xz/TODO.md b/vendor/github.com/ulikunitz/xz/TODO.md
index a4224ce14..84bd5dcbd 100644
--- a/vendor/github.com/ulikunitz/xz/TODO.md
+++ b/vendor/github.com/ulikunitz/xz/TODO.md
@@ -90,6 +90,11 @@
## Log
+## 2020-08-19
+
+Release v0.5.8 fixes issue
+[issue #35](https://github.com/ulikunitz/xz/issues/35).
+
### 2020-02-24
Release v0.5.7 supports the check-ID None and fixes
diff --git a/vendor/github.com/ulikunitz/xz/bits.go b/vendor/github.com/ulikunitz/xz/bits.go
index 364213dd9..dc8f32860 100644
--- a/vendor/github.com/ulikunitz/xz/bits.go
+++ b/vendor/github.com/ulikunitz/xz/bits.go
@@ -54,6 +54,8 @@ var errOverflowU64 = errors.New("xz: uvarint overflows 64-bit unsigned integer")
// readUvarint reads a uvarint from the given byte reader.
func readUvarint(r io.ByteReader) (x uint64, n int, err error) {
+ const maxUvarintLen = 10
+
var s uint
i := 0
for {
@@ -62,8 +64,11 @@ func readUvarint(r io.ByteReader) (x uint64, n int, err error) {
return x, i, err
}
i++
+ if i > maxUvarintLen {
+ return x, i, errOverflowU64
+ }
if b < 0x80 {
- if i > 10 || i == 10 && b > 1 {
+ if i == maxUvarintLen && b > 1 {
return x, i, errOverflowU64
}
return x | uint64(b)<<s, i, nil
diff --git a/vendor/github.com/vbauerster/mpb/v5/bar.go b/vendor/github.com/vbauerster/mpb/v5/bar.go
index 9c28a07a8..358cb048d 100644
--- a/vendor/github.com/vbauerster/mpb/v5/bar.go
+++ b/vendor/github.com/vbauerster/mpb/v5/bar.go
@@ -86,7 +86,7 @@ func newBar(container *Progress, bs *bState) *Bar {
noPop: bs.noPop,
operateState: make(chan func(*bState)),
frameCh: make(chan io.Reader, 1),
- syncTableCh: make(chan [][]chan int),
+ syncTableCh: make(chan [][]chan int, 1),
completed: make(chan bool, 1),
done: make(chan struct{}),
cancel: cancel,
@@ -132,14 +132,18 @@ func (b *Bar) Current() int64 {
// Given default bar style is "[=>-]<+", refill rune is '+'.
// To set bar style use mpb.BarStyle(string) BarOption.
func (b *Bar) SetRefill(amount int64) {
- b.operateState <- func(s *bState) {
+ select {
+ case b.operateState <- func(s *bState) {
s.refill = amount
+ }:
+ case <-b.done:
}
}
// TraverseDecorators traverses all available decorators and calls cb func on each.
func (b *Bar) TraverseDecorators(cb func(decor.Decorator)) {
- b.operateState <- func(s *bState) {
+ select {
+ case b.operateState <- func(s *bState) {
for _, decorators := range [...][]decor.Decorator{
s.pDecorators,
s.aDecorators,
@@ -148,6 +152,8 @@ func (b *Bar) TraverseDecorators(cb func(decor.Decorator)) {
cb(extractBaseDecorator(d))
}
}
+ }:
+ case <-b.done:
}
}
@@ -174,6 +180,7 @@ func (b *Bar) SetTotal(total int64, complete bool) {
}
// SetCurrent sets progress' current to an arbitrary value.
+// Setting a negative value will cause a panic.
func (b *Bar) SetCurrent(current int64) {
select {
case b.operateState <- func(s *bState) {
@@ -305,11 +312,13 @@ func (b *Bar) render(tw int) {
defer func() {
// recovering if user defined decorator panics for example
if p := recover(); p != nil {
- s.extender = makePanicExtender(p)
+ if b.recoveredPanic == nil {
+ s.extender = makePanicExtender(p)
+ b.toShutdown = !b.toShutdown
+ b.recoveredPanic = p
+ }
frame, lines := s.extender(nil, s.reqWidth, stat)
b.extendedLines = lines
- b.toShutdown = !b.toShutdown
- b.recoveredPanic = p
b.frameCh <- frame
b.dlogger.Println(p)
}
@@ -348,12 +357,15 @@ func (b *Bar) subscribeDecorators() {
shutdownListeners = append(shutdownListeners, d)
}
})
- b.operateState <- func(s *bState) {
+ select {
+ case b.operateState <- func(s *bState) {
s.averageDecorators = averageDecorators
s.ewmaDecorators = ewmaDecorators
s.shutdownListeners = shutdownListeners
+ }:
+ b.hasEwmaDecorators = len(ewmaDecorators) != 0
+ case <-b.done:
}
- b.hasEwmaDecorators = len(ewmaDecorators) != 0
}
func (b *Bar) refreshTillShutdown() {
diff --git a/vendor/github.com/vbauerster/mpb/v5/cwriter/util_bsd.go b/vendor/github.com/vbauerster/mpb/v5/cwriter/util_bsd.go
new file mode 100644
index 000000000..4e3564ece
--- /dev/null
+++ b/vendor/github.com/vbauerster/mpb/v5/cwriter/util_bsd.go
@@ -0,0 +1,7 @@
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package cwriter
+
+import "golang.org/x/sys/unix"
+
+const ioctlReadTermios = unix.TIOCGETA
diff --git a/vendor/github.com/vbauerster/mpb/v5/cwriter/util_linux.go b/vendor/github.com/vbauerster/mpb/v5/cwriter/util_linux.go
new file mode 100644
index 000000000..253f12dd2
--- /dev/null
+++ b/vendor/github.com/vbauerster/mpb/v5/cwriter/util_linux.go
@@ -0,0 +1,7 @@
+// +build aix linux
+
+package cwriter
+
+import "golang.org/x/sys/unix"
+
+const ioctlReadTermios = unix.TCGETS
diff --git a/vendor/github.com/vbauerster/mpb/v5/cwriter/util_solaris.go b/vendor/github.com/vbauerster/mpb/v5/cwriter/util_solaris.go
new file mode 100644
index 000000000..4b29ff5c0
--- /dev/null
+++ b/vendor/github.com/vbauerster/mpb/v5/cwriter/util_solaris.go
@@ -0,0 +1,7 @@
+// +build solaris
+
+package cwriter
+
+import "golang.org/x/sys/unix"
+
+const ioctlReadTermios = unix.TCGETA
diff --git a/vendor/github.com/vbauerster/mpb/v5/cwriter/writer.go b/vendor/github.com/vbauerster/mpb/v5/cwriter/writer.go
index bb503360d..6f57875c6 100644
--- a/vendor/github.com/vbauerster/mpb/v5/cwriter/writer.go
+++ b/vendor/github.com/vbauerster/mpb/v5/cwriter/writer.go
@@ -3,17 +3,19 @@ package cwriter
import (
"bytes"
"errors"
- "fmt"
"io"
"os"
-
- "github.com/mattn/go-isatty"
+ "strconv"
)
// NotATTY not a TeleTYpewriter error.
var NotATTY = errors.New("not a terminal")
-var cuuAndEd = fmt.Sprintf("%c[%%dA%[1]c[J", 27)
+// http://ascii-table.com/ansi-escape-sequences.php
+const (
+ escOpen = "\x1b["
+ cuuAndEd = "A\x1b[J"
+)
// Writer is a buffered the writer that updates the terminal. The
// contents of writer will be flushed when Flush is called.
@@ -21,7 +23,7 @@ type Writer struct {
out io.Writer
buf bytes.Buffer
lineCount int
- fd uintptr
+ fd int
isTerminal bool
}
@@ -29,8 +31,8 @@ type Writer struct {
func New(out io.Writer) *Writer {
w := &Writer{out: out}
if f, ok := out.(*os.File); ok {
- w.fd = f.Fd()
- w.isTerminal = isatty.IsTerminal(w.fd)
+ w.fd = int(f.Fd())
+ w.isTerminal = IsTerminal(w.fd)
}
return w
}
@@ -39,7 +41,10 @@ func New(out io.Writer) *Writer {
func (w *Writer) Flush(lineCount int) (err error) {
// some terminals interpret clear 0 lines as clear 1
if w.lineCount > 0 {
- w.clearLines()
+ err = w.clearLines()
+ if err != nil {
+ return
+ }
}
w.lineCount = lineCount
_, err = w.buf.WriteTo(w.out)
@@ -70,3 +75,10 @@ func (w *Writer) GetWidth() (int, error) {
tw, _, err := GetSize(w.fd)
return tw, err
}
+
+func (w *Writer) ansiCuuAndEd() (err error) {
+ buf := make([]byte, 8)
+ buf = strconv.AppendInt(buf[:copy(buf, escOpen)], int64(w.lineCount), 10)
+ _, err = w.out.Write(append(buf, cuuAndEd...))
+ return
+}
diff --git a/vendor/github.com/vbauerster/mpb/v5/cwriter/writer_posix.go b/vendor/github.com/vbauerster/mpb/v5/cwriter/writer_posix.go
index e836cec3a..f54a5d06b 100644
--- a/vendor/github.com/vbauerster/mpb/v5/cwriter/writer_posix.go
+++ b/vendor/github.com/vbauerster/mpb/v5/cwriter/writer_posix.go
@@ -3,20 +3,24 @@
package cwriter
import (
- "fmt"
-
"golang.org/x/sys/unix"
)
-func (w *Writer) clearLines() {
- fmt.Fprintf(w.out, cuuAndEd, w.lineCount)
+func (w *Writer) clearLines() error {
+ return w.ansiCuuAndEd()
}
// GetSize returns the dimensions of the given terminal.
-func GetSize(fd uintptr) (width, height int, err error) {
- ws, err := unix.IoctlGetWinsize(int(fd), unix.TIOCGWINSZ)
+func GetSize(fd int) (width, height int, err error) {
+ ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
if err != nil {
return -1, -1, err
}
return int(ws.Col), int(ws.Row), nil
}
+
+// IsTerminal returns whether the given file descriptor is a terminal.
+func IsTerminal(fd int) bool {
+ _, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
+ return err == nil
+}
diff --git a/vendor/github.com/vbauerster/mpb/v5/cwriter/writer_windows.go b/vendor/github.com/vbauerster/mpb/v5/cwriter/writer_windows.go
index 7a3ed5bcc..1a69c81ac 100644
--- a/vendor/github.com/vbauerster/mpb/v5/cwriter/writer_windows.go
+++ b/vendor/github.com/vbauerster/mpb/v5/cwriter/writer_windows.go
@@ -3,67 +3,71 @@
package cwriter
import (
- "fmt"
- "syscall"
"unsafe"
+
+ "golang.org/x/sys/windows"
)
-var kernel32 = syscall.NewLazyDLL("kernel32.dll")
+var kernel32 = windows.NewLazySystemDLL("kernel32.dll")
var (
- procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition")
procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
)
-type coord struct {
- x int16
- y int16
-}
-
-type smallRect struct {
- left int16
- top int16
- right int16
- bottom int16
-}
-
-type consoleScreenBufferInfo struct {
- size coord
- cursorPosition coord
- attributes uint16
- window smallRect
- maximumWindowSize coord
-}
-
-func (w *Writer) clearLines() {
+func (w *Writer) clearLines() error {
if !w.isTerminal {
- fmt.Fprintf(w.out, cuuAndEd, w.lineCount)
+ // hope it's cygwin or similar
+ return w.ansiCuuAndEd()
}
- info := new(consoleScreenBufferInfo)
- procGetConsoleScreenBufferInfo.Call(w.fd, uintptr(unsafe.Pointer(info)))
+ var info windows.ConsoleScreenBufferInfo
+ if err := windows.GetConsoleScreenBufferInfo(windows.Handle(w.fd), &info); err != nil {
+ return err
+ }
- info.cursorPosition.y -= int16(w.lineCount)
- if info.cursorPosition.y < 0 {
- info.cursorPosition.y = 0
+ info.CursorPosition.Y -= int16(w.lineCount)
+ if info.CursorPosition.Y < 0 {
+ info.CursorPosition.Y = 0
}
- procSetConsoleCursorPosition.Call(w.fd, uintptr(uint32(uint16(info.cursorPosition.y))<<16|uint32(uint16(info.cursorPosition.x))))
+ _, _, _ = procSetConsoleCursorPosition.Call(
+ uintptr(w.fd),
+ uintptr(uint32(uint16(info.CursorPosition.Y))<<16|uint32(uint16(info.CursorPosition.X))),
+ )
// clear the lines
- cursor := &coord{
- x: info.window.left,
- y: info.cursorPosition.y,
+ cursor := &windows.Coord{
+ X: info.Window.Left,
+ Y: info.CursorPosition.Y,
}
- count := uint32(info.size.x) * uint32(w.lineCount)
- procFillConsoleOutputCharacter.Call(w.fd, uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(cursor)), uintptr(unsafe.Pointer(new(uint32))))
+ count := uint32(info.Size.X) * uint32(w.lineCount)
+ _, _, _ = procFillConsoleOutputCharacter.Call(
+ uintptr(w.fd),
+ uintptr(' '),
+ uintptr(count),
+ *(*uintptr)(unsafe.Pointer(cursor)),
+ uintptr(unsafe.Pointer(new(uint32))),
+ )
+ return nil
}
// GetSize returns the visible dimensions of the given terminal.
//
// These dimensions don't include any scrollback buffer height.
-func GetSize(fd uintptr) (width, height int, err error) {
- info := new(consoleScreenBufferInfo)
- procGetConsoleScreenBufferInfo.Call(fd, uintptr(unsafe.Pointer(info)))
- return int(info.window.right - info.window.left), int(info.window.bottom - info.window.top), nil
+func GetSize(fd int) (width, height int, err error) {
+ var info windows.ConsoleScreenBufferInfo
+ if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil {
+ return 0, 0, err
+ }
+ // terminal.GetSize from crypto/ssh adds "+ 1" to both width and height:
+ // https://go.googlesource.com/crypto/+/refs/heads/release-branch.go1.14/ssh/terminal/util_windows.go#75
+ // but looks like this is a root cause of issue #66, so removing both "+ 1" have fixed it.
+ return int(info.Window.Right - info.Window.Left), int(info.Window.Bottom - info.Window.Top), nil
+}
+
+// IsTerminal returns whether the given file descriptor is a terminal.
+func IsTerminal(fd int) bool {
+ var st uint32
+ err := windows.GetConsoleMode(windows.Handle(fd), &st)
+ return err == nil
}
diff --git a/vendor/github.com/vbauerster/mpb/v5/decor/counters.go b/vendor/github.com/vbauerster/mpb/v5/decor/counters.go
index 010ec371a..4a5343d41 100644
--- a/vendor/github.com/vbauerster/mpb/v5/decor/counters.go
+++ b/vendor/github.com/vbauerster/mpb/v5/decor/counters.go
@@ -2,6 +2,7 @@ package decor
import (
"fmt"
+ "strings"
)
const (
@@ -31,7 +32,7 @@ func CountersKiloByte(pairFmt string, wcc ...WC) Decorator {
//
// `unit` one of [0|UnitKiB|UnitKB] zero for no unit
//
-// `pairFmt` printf compatible verbs for current and total, like "%f" or "%d"
+// `pairFmt` printf compatible verbs for current and total pair
//
// `wcc` optional WC config
//
@@ -43,25 +44,200 @@ func CountersKiloByte(pairFmt string, wcc ...WC) Decorator {
// pairFmt="% d / % d" output: "1 MB / 12 MB"
//
func Counters(unit int, pairFmt string, wcc ...WC) Decorator {
- return Any(chooseSizeProducer(unit, pairFmt), wcc...)
+ producer := func(unit int, pairFmt string) DecorFunc {
+ if pairFmt == "" {
+ pairFmt = "%d / %d"
+ } else if strings.Count(pairFmt, "%") != 2 {
+ panic("expected pairFmt with exactly 2 verbs")
+ }
+ switch unit {
+ case UnitKiB:
+ return func(s Statistics) string {
+ return fmt.Sprintf(pairFmt, SizeB1024(s.Current), SizeB1024(s.Total))
+ }
+ case UnitKB:
+ return func(s Statistics) string {
+ return fmt.Sprintf(pairFmt, SizeB1000(s.Current), SizeB1000(s.Total))
+ }
+ default:
+ return func(s Statistics) string {
+ return fmt.Sprintf(pairFmt, s.Current, s.Total)
+ }
+ }
+ }
+ return Any(producer(unit, pairFmt), wcc...)
+}
+
+// TotalNoUnit is a wrapper around Total with no unit param.
+func TotalNoUnit(format string, wcc ...WC) Decorator {
+ return Total(0, format, wcc...)
+}
+
+// TotalKibiByte is a wrapper around Total with predefined unit
+// UnitKiB (bytes/1024).
+func TotalKibiByte(format string, wcc ...WC) Decorator {
+ return Total(UnitKiB, format, wcc...)
}
-func chooseSizeProducer(unit int, format string) DecorFunc {
- if format == "" {
- format = "%d / %d"
+// TotalKiloByte is a wrapper around Total with predefined unit
+// UnitKB (bytes/1000).
+func TotalKiloByte(format string, wcc ...WC) Decorator {
+ return Total(UnitKB, format, wcc...)
+}
+
+// Total decorator with dynamic unit measure adjustment.
+//
+// `unit` one of [0|UnitKiB|UnitKB] zero for no unit
+//
+// `format` printf compatible verb for Total
+//
+// `wcc` optional WC config
+//
+// format example if unit=UnitKiB:
+//
+// format="%.1f" output: "12.0MiB"
+// format="% .1f" output: "12.0 MiB"
+// format="%d" output: "12MiB"
+// format="% d" output: "12 MiB"
+//
+func Total(unit int, format string, wcc ...WC) Decorator {
+ producer := func(unit int, format string) DecorFunc {
+ if format == "" {
+ format = "%d"
+ } else if strings.Count(format, "%") != 1 {
+ panic("expected format with exactly 1 verb")
+ }
+
+ switch unit {
+ case UnitKiB:
+ return func(s Statistics) string {
+ return fmt.Sprintf(format, SizeB1024(s.Total))
+ }
+ case UnitKB:
+ return func(s Statistics) string {
+ return fmt.Sprintf(format, SizeB1000(s.Total))
+ }
+ default:
+ return func(s Statistics) string {
+ return fmt.Sprintf(format, s.Total)
+ }
+ }
}
- switch unit {
- case UnitKiB:
- return func(s Statistics) string {
- return fmt.Sprintf(format, SizeB1024(s.Current), SizeB1024(s.Total))
+ return Any(producer(unit, format), wcc...)
+}
+
+// CurrentNoUnit is a wrapper around Current with no unit param.
+func CurrentNoUnit(format string, wcc ...WC) Decorator {
+ return Current(0, format, wcc...)
+}
+
+// CurrentKibiByte is a wrapper around Current with predefined unit
+// UnitKiB (bytes/1024).
+func CurrentKibiByte(format string, wcc ...WC) Decorator {
+ return Current(UnitKiB, format, wcc...)
+}
+
+// CurrentKiloByte is a wrapper around Current with predefined unit
+// UnitKB (bytes/1000).
+func CurrentKiloByte(format string, wcc ...WC) Decorator {
+ return Current(UnitKB, format, wcc...)
+}
+
+// Current decorator with dynamic unit measure adjustment.
+//
+// `unit` one of [0|UnitKiB|UnitKB] zero for no unit
+//
+// `format` printf compatible verb for Current
+//
+// `wcc` optional WC config
+//
+// format example if unit=UnitKiB:
+//
+// format="%.1f" output: "12.0MiB"
+// format="% .1f" output: "12.0 MiB"
+// format="%d" output: "12MiB"
+// format="% d" output: "12 MiB"
+//
+func Current(unit int, format string, wcc ...WC) Decorator {
+ producer := func(unit int, format string) DecorFunc {
+ if format == "" {
+ format = "%d"
+ } else if strings.Count(format, "%") != 1 {
+ panic("expected format with exactly 1 verb")
}
- case UnitKB:
- return func(s Statistics) string {
- return fmt.Sprintf(format, SizeB1000(s.Current), SizeB1000(s.Total))
+
+ switch unit {
+ case UnitKiB:
+ return func(s Statistics) string {
+ return fmt.Sprintf(format, SizeB1024(s.Current))
+ }
+ case UnitKB:
+ return func(s Statistics) string {
+ return fmt.Sprintf(format, SizeB1000(s.Current))
+ }
+ default:
+ return func(s Statistics) string {
+ return fmt.Sprintf(format, s.Current)
+ }
}
- default:
- return func(s Statistics) string {
- return fmt.Sprintf(format, s.Current, s.Total)
+ }
+ return Any(producer(unit, format), wcc...)
+}
+
+// InvertedCurrentNoUnit is a wrapper around InvertedCurrent with no unit param.
+func InvertedCurrentNoUnit(format string, wcc ...WC) Decorator {
+ return InvertedCurrent(0, format, wcc...)
+}
+
+// InvertedCurrentKibiByte is a wrapper around InvertedCurrent with predefined unit
+// UnitKiB (bytes/1024).
+func InvertedCurrentKibiByte(format string, wcc ...WC) Decorator {
+ return InvertedCurrent(UnitKiB, format, wcc...)
+}
+
+// InvertedCurrentKiloByte is a wrapper around InvertedCurrent with predefined unit
+// UnitKB (bytes/1000).
+func InvertedCurrentKiloByte(format string, wcc ...WC) Decorator {
+ return InvertedCurrent(UnitKB, format, wcc...)
+}
+
+// InvertedCurrent decorator with dynamic unit measure adjustment.
+//
+// `unit` one of [0|UnitKiB|UnitKB] zero for no unit
+//
+// `format` printf compatible verb for InvertedCurrent
+//
+// `wcc` optional WC config
+//
+// format example if unit=UnitKiB:
+//
+// format="%.1f" output: "12.0MiB"
+// format="% .1f" output: "12.0 MiB"
+// format="%d" output: "12MiB"
+// format="% d" output: "12 MiB"
+//
+func InvertedCurrent(unit int, format string, wcc ...WC) Decorator {
+ producer := func(unit int, format string) DecorFunc {
+ if format == "" {
+ format = "%d"
+ } else if strings.Count(format, "%") != 1 {
+ panic("expected format with exactly 1 verb")
+ }
+
+ switch unit {
+ case UnitKiB:
+ return func(s Statistics) string {
+ return fmt.Sprintf(format, SizeB1024(s.Total-s.Current))
+ }
+ case UnitKB:
+ return func(s Statistics) string {
+ return fmt.Sprintf(format, SizeB1000(s.Total-s.Current))
+ }
+ default:
+ return func(s Statistics) string {
+ return fmt.Sprintf(format, s.Total-s.Current)
+ }
}
}
+ return Any(producer(unit, format), wcc...)
}
diff --git a/vendor/github.com/vbauerster/mpb/v5/go.mod b/vendor/github.com/vbauerster/mpb/v5/go.mod
index 389a19d54..642bf0a5a 100644
--- a/vendor/github.com/vbauerster/mpb/v5/go.mod
+++ b/vendor/github.com/vbauerster/mpb/v5/go.mod
@@ -3,9 +3,8 @@ module github.com/vbauerster/mpb/v5
require (
github.com/VividCortex/ewma v1.1.1
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
- github.com/mattn/go-isatty v0.0.12
github.com/mattn/go-runewidth v0.0.9
- golang.org/x/sys v0.0.0-20200519105757-fe76b779f299
+ golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed
)
go 1.14
diff --git a/vendor/github.com/vbauerster/mpb/v5/go.sum b/vendor/github.com/vbauerster/mpb/v5/go.sum
index dcaa8c553..7ad08f141 100644
--- a/vendor/github.com/vbauerster/mpb/v5/go.sum
+++ b/vendor/github.com/vbauerster/mpb/v5/go.sum
@@ -2,10 +2,7 @@ github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdc
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
-github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
-github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
-golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
-golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed h1:WBkVNH1zd9jg/dK4HCM4lNANnmd12EHC9z+LmcCG4ns=
+golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=