summaryrefslogtreecommitdiff
path: root/vendor/github.com
diff options
context:
space:
mode:
authorMatthew Heon <mheon@redhat.com>2021-12-06 13:55:54 -0500
committerMatthew Heon <mheon@redhat.com>2021-12-06 13:55:54 -0500
commit8dc94f1be5fd410461f08992c9a176e95ef36169 (patch)
tree9a94ac3938e4353cc2ad78014e5e029d7cc95d67 /vendor/github.com
parent274a76e06864d33470152cad42b81f8501f56b8c (diff)
downloadpodman-8dc94f1be5fd410461f08992c9a176e95ef36169.tar.gz
podman-8dc94f1be5fd410461f08992c9a176e95ef36169.tar.bz2
podman-8dc94f1be5fd410461f08992c9a176e95ef36169.zip
Bump to containers/image v5.17.0
This resolves CVE-2021-41190 Signed-off-by: Matthew Heon <mheon@redhat.com>
Diffstat (limited to 'vendor/github.com')
-rw-r--r--vendor/github.com/bits-and-blooms/bitset/.gitignore26
-rw-r--r--vendor/github.com/bits-and-blooms/bitset/.travis.yml37
-rw-r--r--vendor/github.com/bits-and-blooms/bitset/LICENSE27
-rw-r--r--vendor/github.com/bits-and-blooms/bitset/README.md93
-rw-r--r--vendor/github.com/bits-and-blooms/bitset/azure-pipelines.yml39
-rw-r--r--vendor/github.com/bits-and-blooms/bitset/bitset.go952
-rw-r--r--vendor/github.com/bits-and-blooms/bitset/go.mod3
-rw-r--r--vendor/github.com/bits-and-blooms/bitset/go.sum0
-rw-r--r--vendor/github.com/bits-and-blooms/bitset/popcnt.go53
-rw-r--r--vendor/github.com/bits-and-blooms/bitset/popcnt_19.go45
-rw-r--r--vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go68
-rw-r--r--vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.s104
-rw-r--r--vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go24
-rw-r--r--vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go14
-rw-r--r--vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go9
-rw-r--r--vendor/github.com/containerd/stargz-snapshotter/estargz/estargz.go131
-rw-r--r--vendor/github.com/containerd/stargz-snapshotter/estargz/go.mod3
-rw-r--r--vendor/github.com/containerd/stargz-snapshotter/estargz/go.sum18
-rw-r--r--vendor/github.com/containerd/stargz-snapshotter/estargz/gzip.go30
-rw-r--r--vendor/github.com/containerd/stargz-snapshotter/estargz/testutil.go496
-rw-r--r--vendor/github.com/containerd/stargz-snapshotter/estargz/types.go6
-rw-r--r--vendor/github.com/containers/image/v5/docker/docker_image_dest.go50
-rw-r--r--vendor/github.com/containers/image/v5/docker/docker_image_src.go37
-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.go23
-rw-r--r--vendor/github.com/containers/image/v5/internal/streamdigest/stream_digest.go41
-rw-r--r--vendor/github.com/containers/image/v5/manifest/common.go67
-rw-r--r--vendor/github.com/containers/image/v5/manifest/docker_schema1.go4
-rw-r--r--vendor/github.com/containers/image/v5/manifest/docker_schema2.go4
-rw-r--r--vendor/github.com/containers/image/v5/manifest/docker_schema2_list.go4
-rw-r--r--vendor/github.com/containers/image/v5/manifest/oci.go4
-rw-r--r--vendor/github.com/containers/image/v5/manifest/oci_index.go4
-rw-r--r--vendor/github.com/containers/image/v5/oci/layout/oci_src.go30
-rw-r--r--vendor/github.com/containers/image/v5/pkg/docker/config/config.go23
-rw-r--r--vendor/github.com/containers/image/v5/pkg/sysregistriesv2/system_registries_v2.go8
-rw-r--r--vendor/github.com/containers/image/v5/storage/storage_transport.go2
-rw-r--r--vendor/github.com/containers/image/v5/types/types.go4
-rw-r--r--vendor/github.com/containers/image/v5/version/version.go2
-rw-r--r--vendor/github.com/containers/storage/.cirrus.yml15
-rw-r--r--vendor/github.com/containers/storage/VERSION2
-rw-r--r--vendor/github.com/containers/storage/drivers/aufs/aufs.go6
-rw-r--r--vendor/github.com/containers/storage/drivers/driver_linux.go34
-rw-r--r--vendor/github.com/containers/storage/drivers/fsdiff.go2
-rw-r--r--vendor/github.com/containers/storage/drivers/overlay/overlay.go124
-rw-r--r--vendor/github.com/containers/storage/drivers/overlay/randomid.go2
-rw-r--r--vendor/github.com/containers/storage/drivers/template.go4
-rw-r--r--vendor/github.com/containers/storage/go.mod7
-rw-r--r--vendor/github.com/containers/storage/go.sum17
-rw-r--r--vendor/github.com/containers/storage/layers.go2
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/archive.go2
-rw-r--r--vendor/github.com/containers/storage/pkg/chunked/storage_linux.go86
-rw-r--r--vendor/github.com/containers/storage/pkg/fileutils/fileutils_unix.go2
-rw-r--r--vendor/github.com/containers/storage/pkg/lockfile/lockfile_unix.go2
-rw-r--r--vendor/github.com/containers/storage/pkg/loopback/attach_loopback.go10
-rw-r--r--vendor/github.com/containers/storage/pkg/loopback/loopback.go4
-rw-r--r--vendor/github.com/containers/storage/pkg/parsers/kernel/kernel_unix.go2
-rw-r--r--vendor/github.com/containers/storage/pkg/system/syscall_unix.go12
-rw-r--r--vendor/github.com/containers/storage/pkg/system/syscall_windows.go5
-rw-r--r--vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go2
-rw-r--r--vendor/github.com/containers/storage/pkg/unshare/unshare_linux.go30
-rw-r--r--vendor/github.com/containers/storage/store.go15
-rw-r--r--vendor/github.com/containers/storage/types/utils.go2
-rw-r--r--vendor/github.com/containers/storage/userns.go2
-rw-r--r--vendor/github.com/json-iterator/go/README.md2
-rw-r--r--vendor/github.com/json-iterator/go/go.mod2
-rw-r--r--vendor/github.com/json-iterator/go/go.sum5
-rw-r--r--vendor/github.com/juju/ansiterm/LICENSE191
-rw-r--r--vendor/github.com/juju/ansiterm/Makefile14
-rw-r--r--vendor/github.com/juju/ansiterm/README.md323
-rw-r--r--vendor/github.com/juju/ansiterm/attribute.go50
-rw-r--r--vendor/github.com/juju/ansiterm/color.go119
-rw-r--r--vendor/github.com/juju/ansiterm/context.go95
-rw-r--r--vendor/github.com/juju/ansiterm/doc.go6
-rw-r--r--vendor/github.com/juju/ansiterm/style.go72
-rw-r--r--vendor/github.com/juju/ansiterm/tabwriter.go64
-rw-r--r--vendor/github.com/juju/ansiterm/tabwriter/LICENSE27
-rw-r--r--vendor/github.com/juju/ansiterm/tabwriter/tabwriter.go587
-rw-r--r--vendor/github.com/juju/ansiterm/terminal.go32
-rw-r--r--vendor/github.com/juju/ansiterm/writer.go74
-rw-r--r--vendor/github.com/klauspost/compress/LICENSE12
-rw-r--r--vendor/github.com/klauspost/compress/README.md12
-rw-r--r--vendor/github.com/klauspost/compress/flate/fast_encoder.go25
-rw-r--r--vendor/github.com/klauspost/compress/huff0/decompress.go275
-rw-r--r--vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash.go1
-rw-r--r--vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.go2
-rw-r--r--vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.s66
-rw-r--r--vendor/github.com/lunixbochs/vtclean/.travis.yml9
-rw-r--r--vendor/github.com/lunixbochs/vtclean/LICENSE19
-rw-r--r--vendor/github.com/lunixbochs/vtclean/README.md46
-rw-r--r--vendor/github.com/lunixbochs/vtclean/io.go93
-rw-r--r--vendor/github.com/lunixbochs/vtclean/line.go113
-rw-r--r--vendor/github.com/lunixbochs/vtclean/vtclean.go95
-rw-r--r--vendor/github.com/manifoldco/promptui/CHANGELOG.md7
-rw-r--r--vendor/github.com/manifoldco/promptui/go.mod6
-rw-r--r--vendor/github.com/manifoldco/promptui/go.sum15
-rw-r--r--vendor/github.com/manifoldco/promptui/select.go5
-rw-r--r--vendor/github.com/mattn/go-colorable/.travis.yml15
-rw-r--r--vendor/github.com/mattn/go-colorable/LICENSE21
-rw-r--r--vendor/github.com/mattn/go-colorable/README.md48
-rw-r--r--vendor/github.com/mattn/go-colorable/colorable_appengine.go37
-rw-r--r--vendor/github.com/mattn/go-colorable/colorable_others.go38
-rw-r--r--vendor/github.com/mattn/go-colorable/colorable_windows.go1043
-rw-r--r--vendor/github.com/mattn/go-colorable/go.mod8
-rw-r--r--vendor/github.com/mattn/go-colorable/go.sum5
-rw-r--r--vendor/github.com/mattn/go-colorable/go.test.sh12
-rw-r--r--vendor/github.com/mattn/go-colorable/noncolorable.go55
-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/modern-go/reflect2/.travis.yml2
-rw-r--r--vendor/github.com/modern-go/reflect2/Gopkg.lock8
-rw-r--r--vendor/github.com/modern-go/reflect2/Gopkg.toml4
-rw-r--r--vendor/github.com/modern-go/reflect2/go.mod3
-rw-r--r--vendor/github.com/modern-go/reflect2/go_above_118.go23
-rw-r--r--vendor/github.com/modern-go/reflect2/go_above_17.go8
-rw-r--r--vendor/github.com/modern-go/reflect2/go_above_19.go3
-rw-r--r--vendor/github.com/modern-go/reflect2/go_below_118.go21
-rw-r--r--vendor/github.com/modern-go/reflect2/go_below_17.go9
-rw-r--r--vendor/github.com/modern-go/reflect2/go_below_19.go14
-rw-r--r--vendor/github.com/modern-go/reflect2/reflect2.go20
-rw-r--r--vendor/github.com/modern-go/reflect2/test.sh12
-rw-r--r--vendor/github.com/modern-go/reflect2/type_map.go51
-rw-r--r--vendor/github.com/modern-go/reflect2/unsafe_link.go26
-rw-r--r--vendor/github.com/modern-go/reflect2/unsafe_map.go8
-rw-r--r--vendor/github.com/opencontainers/selinux/go-selinux/label/label_linux.go4
-rw-r--r--vendor/github.com/opencontainers/selinux/go-selinux/selinux.go2
-rw-r--r--vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go68
-rw-r--r--vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go12
-rw-r--r--vendor/github.com/opencontainers/selinux/pkg/pwalkdir/pwalkdir.go13
-rw-r--r--vendor/github.com/vbauerster/mpb/v7/bar.go25
-rw-r--r--vendor/github.com/vbauerster/mpb/v7/go.mod2
-rw-r--r--vendor/github.com/vbauerster/mpb/v7/go.sum4
143 files changed, 1425 insertions, 5875 deletions
diff --git a/vendor/github.com/bits-and-blooms/bitset/.gitignore b/vendor/github.com/bits-and-blooms/bitset/.gitignore
deleted file mode 100644
index 5c204d28b..000000000
--- a/vendor/github.com/bits-and-blooms/bitset/.gitignore
+++ /dev/null
@@ -1,26 +0,0 @@
-# Compiled Object files, Static and Dynamic libs (Shared Objects)
-*.o
-*.a
-*.so
-
-# Folders
-_obj
-_test
-
-# Architecture specific extensions/prefixes
-*.[568vq]
-[568vq].out
-
-*.cgo1.go
-*.cgo2.c
-_cgo_defun.c
-_cgo_gotypes.go
-_cgo_export.*
-
-_testmain.go
-
-*.exe
-*.test
-*.prof
-
-target
diff --git a/vendor/github.com/bits-and-blooms/bitset/.travis.yml b/vendor/github.com/bits-and-blooms/bitset/.travis.yml
deleted file mode 100644
index 094aa5ce0..000000000
--- a/vendor/github.com/bits-and-blooms/bitset/.travis.yml
+++ /dev/null
@@ -1,37 +0,0 @@
-language: go
-
-sudo: false
-
-branches:
- except:
- - release
-
-branches:
- only:
- - master
- - travis
-
-go:
- - "1.11.x"
- - tip
-
-matrix:
- allow_failures:
- - go: tip
-
-before_install:
- - if [ -n "$GH_USER" ]; then git config --global github.user ${GH_USER}; fi;
- - if [ -n "$GH_TOKEN" ]; then git config --global github.token ${GH_TOKEN}; fi;
- - go get github.com/mattn/goveralls
-
-before_script:
- - make deps
-
-script:
- - make qa
-
-after_failure:
- - cat ./target/test/report.xml
-
-after_success:
- - if [ "$TRAVIS_GO_VERSION" = "1.11.1" ]; then $HOME/gopath/bin/goveralls -covermode=count -coverprofile=target/report/coverage.out -service=travis-ci; fi;
diff --git a/vendor/github.com/bits-and-blooms/bitset/LICENSE b/vendor/github.com/bits-and-blooms/bitset/LICENSE
deleted file mode 100644
index 59cab8a93..000000000
--- a/vendor/github.com/bits-and-blooms/bitset/LICENSE
+++ /dev/null
@@ -1,27 +0,0 @@
-Copyright (c) 2014 Will Fitzgerald. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/bits-and-blooms/bitset/README.md b/vendor/github.com/bits-and-blooms/bitset/README.md
deleted file mode 100644
index 97e83071e..000000000
--- a/vendor/github.com/bits-and-blooms/bitset/README.md
+++ /dev/null
@@ -1,93 +0,0 @@
-# bitset
-
-*Go language library to map between non-negative integers and boolean values*
-
-[![Test](https://github.com/bits-and-blooms/bitset/workflows/Test/badge.svg)](https://github.com/willf/bitset/actions?query=workflow%3ATest)
-[![Go Report Card](https://goreportcard.com/badge/github.com/willf/bitset)](https://goreportcard.com/report/github.com/willf/bitset)
-[![PkgGoDev](https://pkg.go.dev/badge/github.com/bits-and-blooms/bitset?tab=doc)](https://pkg.go.dev/github.com/bits-and-blooms/bitset?tab=doc)
-
-
-## Description
-
-Package bitset implements bitsets, a mapping between non-negative integers and boolean values.
-It should be more efficient than map[uint] bool.
-
-It provides methods for setting, clearing, flipping, and testing individual integers.
-
-But it also provides set intersection, union, difference, complement, and symmetric operations, as well as tests to check whether any, all, or no bits are set, and querying a bitset's current length and number of positive bits.
-
-BitSets are expanded to the size of the largest set bit; the memory allocation is approximately Max bits, where Max is the largest set bit. BitSets are never shrunk. On creation, a hint can be given for the number of bits that will be used.
-
-Many of the methods, including Set, Clear, and Flip, return a BitSet pointer, which allows for chaining.
-
-### Example use:
-
-```go
-package main
-
-import (
- "fmt"
- "math/rand"
-
- "github.com/bits-and-blooms/bitset"
-)
-
-func main() {
- fmt.Printf("Hello from BitSet!\n")
- var b bitset.BitSet
- // play some Go Fish
- for i := 0; i < 100; i++ {
- card1 := uint(rand.Intn(52))
- card2 := uint(rand.Intn(52))
- b.Set(card1)
- if b.Test(card2) {
- fmt.Println("Go Fish!")
- }
- b.Clear(card1)
- }
-
- // Chaining
- b.Set(10).Set(11)
-
- for i, e := b.NextSet(0); e; i, e = b.NextSet(i + 1) {
- fmt.Println("The following bit is set:", i)
- }
- if b.Intersection(bitset.New(100).Set(10)).Count() == 1 {
- fmt.Println("Intersection works.")
- } else {
- fmt.Println("Intersection doesn't work???")
- }
-}
-```
-
-As an alternative to BitSets, one should check out the 'big' package, which provides a (less set-theoretical) view of bitsets.
-
-Package documentation is at: https://pkg.go.dev/github.com/bits-and-blooms/bitset?tab=doc
-
-## Memory Usage
-
-The memory usage of a bitset using N bits is at least N/8 bytes. The number of bits in a bitset is at least as large as one plus the greatest bit index you have accessed. Thus it is possible to run out of memory while using a bitset. If you have lots of bits, you might prefer compressed bitsets, like the [Roaring bitmaps](http://roaringbitmap.org) and its [Go implementation](https://github.com/RoaringBitmap/roaring).
-
-## Implementation Note
-
-Go 1.9 introduced a native `math/bits` library. We provide backward compatibility to Go 1.7, which might be removed.
-
-It is possible that a later version will match the `math/bits` return signature for counts (which is `int`, rather than our library's `unit64`). If so, the version will be bumped.
-
-## Installation
-
-```bash
-go get github.com/bits-and-blooms/bitset
-```
-
-## Contributing
-
-If you wish to contribute to this project, please branch and issue a pull request against master ("[GitHub Flow](https://guides.github.com/introduction/flow/)")
-
-## Running all tests
-
-Before committing the code, please check if it passes tests, has adequate coverage, etc.
-```bash
-go test
-go test -cover
-```
diff --git a/vendor/github.com/bits-and-blooms/bitset/azure-pipelines.yml b/vendor/github.com/bits-and-blooms/bitset/azure-pipelines.yml
deleted file mode 100644
index f9b295918..000000000
--- a/vendor/github.com/bits-and-blooms/bitset/azure-pipelines.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-# Go
-# Build your Go project.
-# Add steps that test, save build artifacts, deploy, and more:
-# https://docs.microsoft.com/azure/devops/pipelines/languages/go
-
-trigger:
-- master
-
-pool:
- vmImage: 'Ubuntu-16.04'
-
-variables:
- GOBIN: '$(GOPATH)/bin' # Go binaries path
- GOROOT: '/usr/local/go1.11' # Go installation path
- GOPATH: '$(system.defaultWorkingDirectory)/gopath' # Go workspace path
- modulePath: '$(GOPATH)/src/github.com/$(build.repository.name)' # Path to the module's code
-
-steps:
-- script: |
- mkdir -p '$(GOBIN)'
- mkdir -p '$(GOPATH)/pkg'
- mkdir -p '$(modulePath)'
- shopt -s extglob
- shopt -s dotglob
- mv !(gopath) '$(modulePath)'
- echo '##vso[task.prependpath]$(GOBIN)'
- echo '##vso[task.prependpath]$(GOROOT)/bin'
- displayName: 'Set up the Go workspace'
-
-- script: |
- go version
- go get -v -t -d ./...
- if [ -f Gopkg.toml ]; then
- curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
- dep ensure
- fi
- go build -v .
- workingDirectory: '$(modulePath)'
- displayName: 'Get dependencies, then build'
diff --git a/vendor/github.com/bits-and-blooms/bitset/bitset.go b/vendor/github.com/bits-and-blooms/bitset/bitset.go
deleted file mode 100644
index d688806a5..000000000
--- a/vendor/github.com/bits-and-blooms/bitset/bitset.go
+++ /dev/null
@@ -1,952 +0,0 @@
-/*
-Package bitset implements bitsets, a mapping
-between non-negative integers and boolean values. It should be more
-efficient than map[uint] bool.
-
-It provides methods for setting, clearing, flipping, and testing
-individual integers.
-
-But it also provides set intersection, union, difference,
-complement, and symmetric operations, as well as tests to
-check whether any, all, or no bits are set, and querying a
-bitset's current length and number of positive bits.
-
-BitSets are expanded to the size of the largest set bit; the
-memory allocation is approximately Max bits, where Max is
-the largest set bit. BitSets are never shrunk. On creation,
-a hint can be given for the number of bits that will be used.
-
-Many of the methods, including Set,Clear, and Flip, return
-a BitSet pointer, which allows for chaining.
-
-Example use:
-
- import "bitset"
- var b BitSet
- b.Set(10).Set(11)
- if b.Test(1000) {
- b.Clear(1000)
- }
- if B.Intersection(bitset.New(100).Set(10)).Count() > 1 {
- fmt.Println("Intersection works.")
- }
-
-As an alternative to BitSets, one should check out the 'big' package,
-which provides a (less set-theoretical) view of bitsets.
-
-*/
-package bitset
-
-import (
- "bufio"
- "bytes"
- "encoding/base64"
- "encoding/binary"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "strconv"
-)
-
-// the wordSize of a bit set
-const wordSize = uint(64)
-
-// log2WordSize is lg(wordSize)
-const log2WordSize = uint(6)
-
-// allBits has every bit set
-const allBits uint64 = 0xffffffffffffffff
-
-// default binary BigEndian
-var binaryOrder binary.ByteOrder = binary.BigEndian
-
-// default json encoding base64.URLEncoding
-var base64Encoding = base64.URLEncoding
-
-// Base64StdEncoding Marshal/Unmarshal BitSet with base64.StdEncoding(Default: base64.URLEncoding)
-func Base64StdEncoding() { base64Encoding = base64.StdEncoding }
-
-// LittleEndian Marshal/Unmarshal Binary as Little Endian(Default: binary.BigEndian)
-func LittleEndian() { binaryOrder = binary.LittleEndian }
-
-// A BitSet is a set of bits. The zero value of a BitSet is an empty set of length 0.
-type BitSet struct {
- length uint
- set []uint64
-}
-
-// Error is used to distinguish errors (panics) generated in this package.
-type Error string
-
-// safeSet will fixup b.set to be non-nil and return the field value
-func (b *BitSet) safeSet() []uint64 {
- if b.set == nil {
- b.set = make([]uint64, wordsNeeded(0))
- }
- return b.set
-}
-
-// From is a constructor used to create a BitSet from an array of integers
-func From(buf []uint64) *BitSet {
- return &BitSet{uint(len(buf)) * 64, buf}
-}
-
-// Bytes returns the bitset as array of integers
-func (b *BitSet) Bytes() []uint64 {
- return b.set
-}
-
-// wordsNeeded calculates the number of words needed for i bits
-func wordsNeeded(i uint) int {
- if i > (Cap() - wordSize + 1) {
- return int(Cap() >> log2WordSize)
- }
- return int((i + (wordSize - 1)) >> log2WordSize)
-}
-
-// New creates a new BitSet with a hint that length bits will be required
-func New(length uint) (bset *BitSet) {
- defer func() {
- if r := recover(); r != nil {
- bset = &BitSet{
- 0,
- make([]uint64, 0),
- }
- }
- }()
-
- bset = &BitSet{
- length,
- make([]uint64, wordsNeeded(length)),
- }
-
- return bset
-}
-
-// Cap returns the total possible capacity, or number of bits
-func Cap() uint {
- return ^uint(0)
-}
-
-// Len returns the number of bits in the BitSet.
-// Note the difference to method Count, see example.
-func (b *BitSet) Len() uint {
- return b.length
-}
-
-// extendSetMaybe adds additional words to incorporate new bits if needed
-func (b *BitSet) extendSetMaybe(i uint) {
- if i >= b.length { // if we need more bits, make 'em
- if i >= Cap() {
- panic("You are exceeding the capacity")
- }
- nsize := wordsNeeded(i + 1)
- if b.set == nil {
- b.set = make([]uint64, nsize)
- } else if cap(b.set) >= nsize {
- b.set = b.set[:nsize] // fast resize
- } else if len(b.set) < nsize {
- newset := make([]uint64, nsize, 2*nsize) // increase capacity 2x
- copy(newset, b.set)
- b.set = newset
- }
- b.length = i + 1
- }
-}
-
-// Test whether bit i is set.
-func (b *BitSet) Test(i uint) bool {
- if i >= b.length {
- return false
- }
- return b.set[i>>log2WordSize]&(1<<(i&(wordSize-1))) != 0
-}
-
-// Set bit i to 1, the capacity of the bitset is automatically
-// increased accordingly.
-// If i>= Cap(), this function will panic.
-// Warning: using a very large value for 'i'
-// may lead to a memory shortage and a panic: the caller is responsible
-// for providing sensible parameters in line with their memory capacity.
-func (b *BitSet) Set(i uint) *BitSet {
- b.extendSetMaybe(i)
- b.set[i>>log2WordSize] |= 1 << (i & (wordSize - 1))
- return b
-}
-
-// Clear bit i to 0
-func (b *BitSet) Clear(i uint) *BitSet {
- if i >= b.length {
- return b
- }
- b.set[i>>log2WordSize] &^= 1 << (i & (wordSize - 1))
- return b
-}
-
-// SetTo sets bit i to value.
-// If i>= Cap(), this function will panic.
-// Warning: using a very large value for 'i'
-// may lead to a memory shortage and a panic: the caller is responsible
-// for providing sensible parameters in line with their memory capacity.
-func (b *BitSet) SetTo(i uint, value bool) *BitSet {
- if value {
- return b.Set(i)
- }
- return b.Clear(i)
-}
-
-// Flip bit at i.
-// If i>= Cap(), this function will panic.
-// Warning: using a very large value for 'i'
-// may lead to a memory shortage and a panic: the caller is responsible
-// for providing sensible parameters in line with their memory capacity.
-func (b *BitSet) Flip(i uint) *BitSet {
- if i >= b.length {
- return b.Set(i)
- }
- b.set[i>>log2WordSize] ^= 1 << (i & (wordSize - 1))
- return b
-}
-
-// FlipRange bit in [start, end).
-// If end>= Cap(), this function will panic.
-// Warning: using a very large value for 'end'
-// may lead to a memory shortage and a panic: the caller is responsible
-// for providing sensible parameters in line with their memory capacity.
-func (b *BitSet) FlipRange(start, end uint) *BitSet {
- if start >= end {
- return b
- }
-
- b.extendSetMaybe(end - 1)
- var startWord uint = start >> log2WordSize
- var endWord uint = end >> log2WordSize
- b.set[startWord] ^= ^(^uint64(0) << (start & (wordSize - 1)))
- for i := startWord; i < endWord; i++ {
- b.set[i] = ^b.set[i]
- }
- b.set[endWord] ^= ^uint64(0) >> (-end & (wordSize - 1))
- return b
-}
-
-// Shrink shrinks BitSet so that the provided value is the last possible
-// set value. It clears all bits > the provided index and reduces the size
-// and length of the set.
-//
-// Note that the parameter value is not the new length in bits: it is the
-// maximal value that can be stored in the bitset after the function call.
-// The new length in bits is the parameter value + 1. Thus it is not possible
-// to use this function to set the length to 0, the minimal value of the length
-// after this function call is 1.
-//
-// A new slice is allocated to store the new bits, so you may see an increase in
-// memory usage until the GC runs. Normally this should not be a problem, but if you
-// have an extremely large BitSet its important to understand that the old BitSet will
-// remain in memory until the GC frees it.
-func (b *BitSet) Shrink(lastbitindex uint) *BitSet {
- length := lastbitindex + 1
- idx := wordsNeeded(length)
- if idx > len(b.set) {
- return b
- }
- shrunk := make([]uint64, idx)
- copy(shrunk, b.set[:idx])
- b.set = shrunk
- b.length = length
- b.set[idx-1] &= (allBits >> (uint64(64) - uint64(length&(wordSize-1))))
- return b
-}
-
-// Compact shrinks BitSet to so that we preserve all set bits, while minimizing
-// memory usage. Compact calls Shrink.
-func (b *BitSet) Compact() *BitSet {
- idx := len(b.set) - 1
- for ; idx >= 0 && b.set[idx] == 0; idx-- {
- }
- newlength := uint((idx + 1) << log2WordSize)
- if newlength >= b.length {
- return b // nothing to do
- }
- if newlength > 0 {
- return b.Shrink(newlength - 1)
- }
- // We preserve one word
- return b.Shrink(63)
-}
-
-// InsertAt takes an index which indicates where a bit should be
-// inserted. Then it shifts all the bits in the set to the left by 1, starting
-// from the given index position, and sets the index position to 0.
-//
-// Depending on the size of your BitSet, and where you are inserting the new entry,
-// this method could be extremely slow and in some cases might cause the entire BitSet
-// to be recopied.
-func (b *BitSet) InsertAt(idx uint) *BitSet {
- insertAtElement := (idx >> log2WordSize)
-
- // if length of set is a multiple of wordSize we need to allocate more space first
- if b.isLenExactMultiple() {
- b.set = append(b.set, uint64(0))
- }
-
- var i uint
- for i = uint(len(b.set) - 1); i > insertAtElement; i-- {
- // all elements above the position where we want to insert can simply by shifted
- b.set[i] <<= 1
-
- // we take the most significant bit of the previous element and set it as
- // the least significant bit of the current element
- b.set[i] |= (b.set[i-1] & 0x8000000000000000) >> 63
- }
-
- // generate a mask to extract the data that we need to shift left
- // within the element where we insert a bit
- dataMask := ^(uint64(1)<<uint64(idx&(wordSize-1)) - 1)
-
- // extract that data that we'll shift
- data := b.set[i] & dataMask
-
- // set the positions of the data mask to 0 in the element where we insert
- b.set[i] &= ^dataMask
-
- // shift data mask to the left and insert its data to the slice element
- b.set[i] |= data << 1
-
- // add 1 to length of BitSet
- b.length++
-
- return b
-}
-
-// String creates a string representation of the Bitmap
-func (b *BitSet) String() string {
- // follows code from https://github.com/RoaringBitmap/roaring
- var buffer bytes.Buffer
- start := []byte("{")
- buffer.Write(start)
- counter := 0
- i, e := b.NextSet(0)
- for e {
- counter = counter + 1
- // to avoid exhausting the memory
- if counter > 0x40000 {
- buffer.WriteString("...")
- break
- }
- buffer.WriteString(strconv.FormatInt(int64(i), 10))
- i, e = b.NextSet(i + 1)
- if e {
- buffer.WriteString(",")
- }
- }
- buffer.WriteString("}")
- return buffer.String()
-}
-
-// DeleteAt deletes the bit at the given index position from
-// within the bitset
-// All the bits residing on the left of the deleted bit get
-// shifted right by 1
-// The running time of this operation may potentially be
-// relatively slow, O(length)
-func (b *BitSet) DeleteAt(i uint) *BitSet {
- // the index of the slice element where we'll delete a bit
- deleteAtElement := i >> log2WordSize
-
- // generate a mask for the data that needs to be shifted right
- // within that slice element that gets modified
- dataMask := ^((uint64(1) << (i & (wordSize - 1))) - 1)
-
- // extract the data that we'll shift right from the slice element
- data := b.set[deleteAtElement] & dataMask
-
- // set the masked area to 0 while leaving the rest as it is
- b.set[deleteAtElement] &= ^dataMask
-
- // shift the previously extracted data to the right and then
- // set it in the previously masked area
- b.set[deleteAtElement] |= (data >> 1) & dataMask
-
- // loop over all the consecutive slice elements to copy each
- // lowest bit into the highest position of the previous element,
- // then shift the entire content to the right by 1
- for i := int(deleteAtElement) + 1; i < len(b.set); i++ {
- b.set[i-1] |= (b.set[i] & 1) << 63
- b.set[i] >>= 1
- }
-
- b.length = b.length - 1
-
- return b
-}
-
-// NextSet returns the next bit set from the specified index,
-// including possibly the current index
-// along with an error code (true = valid, false = no set bit found)
-// for i,e := v.NextSet(0); e; i,e = v.NextSet(i + 1) {...}
-//
-// Users concerned with performance may want to use NextSetMany to
-// retrieve several values at once.
-func (b *BitSet) NextSet(i uint) (uint, bool) {
- x := int(i >> log2WordSize)
- if x >= len(b.set) {
- return 0, false
- }
- w := b.set[x]
- w = w >> (i & (wordSize - 1))
- if w != 0 {
- return i + trailingZeroes64(w), true
- }
- x = x + 1
- for x < len(b.set) {
- if b.set[x] != 0 {
- return uint(x)*wordSize + trailingZeroes64(b.set[x]), true
- }
- x = x + 1
-
- }
- return 0, false
-}
-
-// NextSetMany returns many next bit sets from the specified index,
-// including possibly the current index and up to cap(buffer).
-// If the returned slice has len zero, then no more set bits were found
-//
-// buffer := make([]uint, 256) // this should be reused
-// j := uint(0)
-// j, buffer = bitmap.NextSetMany(j, buffer)
-// for ; len(buffer) > 0; j, buffer = bitmap.NextSetMany(j,buffer) {
-// for k := range buffer {
-// do something with buffer[k]
-// }
-// j += 1
-// }
-//
-//
-// It is possible to retrieve all set bits as follow:
-//
-// indices := make([]uint, bitmap.Count())
-// bitmap.NextSetMany(0, indices)
-//
-// However if bitmap.Count() is large, it might be preferable to
-// use several calls to NextSetMany, for performance reasons.
-func (b *BitSet) NextSetMany(i uint, buffer []uint) (uint, []uint) {
- myanswer := buffer
- capacity := cap(buffer)
- x := int(i >> log2WordSize)
- if x >= len(b.set) || capacity == 0 {
- return 0, myanswer[:0]
- }
- skip := i & (wordSize - 1)
- word := b.set[x] >> skip
- myanswer = myanswer[:capacity]
- size := int(0)
- for word != 0 {
- r := trailingZeroes64(word)
- t := word & ((^word) + 1)
- myanswer[size] = r + i
- size++
- if size == capacity {
- goto End
- }
- word = word ^ t
- }
- x++
- for idx, word := range b.set[x:] {
- for word != 0 {
- r := trailingZeroes64(word)
- t := word & ((^word) + 1)
- myanswer[size] = r + (uint(x+idx) << 6)
- size++
- if size == capacity {
- goto End
- }
- word = word ^ t
- }
- }
-End:
- if size > 0 {
- return myanswer[size-1], myanswer[:size]
- }
- return 0, myanswer[:0]
-}
-
-// NextClear returns the next clear bit from the specified index,
-// including possibly the current index
-// along with an error code (true = valid, false = no bit found i.e. all bits are set)
-func (b *BitSet) NextClear(i uint) (uint, bool) {
- x := int(i >> log2WordSize)
- if x >= len(b.set) {
- return 0, false
- }
- w := b.set[x]
- w = w >> (i & (wordSize - 1))
- wA := allBits >> (i & (wordSize - 1))
- index := i + trailingZeroes64(^w)
- if w != wA && index < b.length {
- return index, true
- }
- x++
- for x < len(b.set) {
- index = uint(x)*wordSize + trailingZeroes64(^b.set[x])
- if b.set[x] != allBits && index < b.length {
- return index, true
- }
- x++
- }
- return 0, false
-}
-
-// ClearAll clears the entire BitSet
-func (b *BitSet) ClearAll() *BitSet {
- if b != nil && b.set != nil {
- for i := range b.set {
- b.set[i] = 0
- }
- }
- return b
-}
-
-// wordCount returns the number of words used in a bit set
-func (b *BitSet) wordCount() int {
- return len(b.set)
-}
-
-// Clone this BitSet
-func (b *BitSet) Clone() *BitSet {
- c := New(b.length)
- if b.set != nil { // Clone should not modify current object
- copy(c.set, b.set)
- }
- return c
-}
-
-// Copy into a destination BitSet
-// Returning the size of the destination BitSet
-// like array copy
-func (b *BitSet) Copy(c *BitSet) (count uint) {
- if c == nil {
- return
- }
- if b.set != nil { // Copy should not modify current object
- copy(c.set, b.set)
- }
- count = c.length
- if b.length < c.length {
- count = b.length
- }
- return
-}
-
-// Count (number of set bits).
-// Also known as "popcount" or "population count".
-func (b *BitSet) Count() uint {
- if b != nil && b.set != nil {
- return uint(popcntSlice(b.set))
- }
- return 0
-}
-
-// Equal tests the equivalence of two BitSets.
-// False if they are of different sizes, otherwise true
-// only if all the same bits are set
-func (b *BitSet) Equal(c *BitSet) bool {
- if c == nil || b == nil {
- return c == b
- }
- if b.length != c.length {
- return false
- }
- if b.length == 0 { // if they have both length == 0, then could have nil set
- return true
- }
- // testing for equality shoud not transform the bitset (no call to safeSet)
-
- for p, v := range b.set {
- if c.set[p] != v {
- return false
- }
- }
- return true
-}
-
-func panicIfNull(b *BitSet) {
- if b == nil {
- panic(Error("BitSet must not be null"))
- }
-}
-
-// Difference of base set and other set
-// This is the BitSet equivalent of &^ (and not)
-func (b *BitSet) Difference(compare *BitSet) (result *BitSet) {
- panicIfNull(b)
- panicIfNull(compare)
- result = b.Clone() // clone b (in case b is bigger than compare)
- l := int(compare.wordCount())
- if l > int(b.wordCount()) {
- l = int(b.wordCount())
- }
- for i := 0; i < l; i++ {
- result.set[i] = b.set[i] &^ compare.set[i]
- }
- return
-}
-
-// DifferenceCardinality computes the cardinality of the differnce
-func (b *BitSet) DifferenceCardinality(compare *BitSet) uint {
- panicIfNull(b)
- panicIfNull(compare)
- l := int(compare.wordCount())
- if l > int(b.wordCount()) {
- l = int(b.wordCount())
- }
- cnt := uint64(0)
- cnt += popcntMaskSlice(b.set[:l], compare.set[:l])
- cnt += popcntSlice(b.set[l:])
- return uint(cnt)
-}
-
-// InPlaceDifference computes the difference of base set and other set
-// This is the BitSet equivalent of &^ (and not)
-func (b *BitSet) InPlaceDifference(compare *BitSet) {
- panicIfNull(b)
- panicIfNull(compare)
- l := int(compare.wordCount())
- if l > int(b.wordCount()) {
- l = int(b.wordCount())
- }
- for i := 0; i < l; i++ {
- b.set[i] &^= compare.set[i]
- }
-}
-
-// Convenience function: return two bitsets ordered by
-// increasing length. Note: neither can be nil
-func sortByLength(a *BitSet, b *BitSet) (ap *BitSet, bp *BitSet) {
- if a.length <= b.length {
- ap, bp = a, b
- } else {
- ap, bp = b, a
- }
- return
-}
-
-// Intersection of base set and other set
-// This is the BitSet equivalent of & (and)
-func (b *BitSet) Intersection(compare *BitSet) (result *BitSet) {
- panicIfNull(b)
- panicIfNull(compare)
- b, compare = sortByLength(b, compare)
- result = New(b.length)
- for i, word := range b.set {
- result.set[i] = word & compare.set[i]
- }
- return
-}
-
-// IntersectionCardinality computes the cardinality of the union
-func (b *BitSet) IntersectionCardinality(compare *BitSet) uint {
- panicIfNull(b)
- panicIfNull(compare)
- b, compare = sortByLength(b, compare)
- cnt := popcntAndSlice(b.set, compare.set)
- return uint(cnt)
-}
-
-// InPlaceIntersection destructively computes the intersection of
-// base set and the compare set.
-// This is the BitSet equivalent of & (and)
-func (b *BitSet) InPlaceIntersection(compare *BitSet) {
- panicIfNull(b)
- panicIfNull(compare)
- l := int(compare.wordCount())
- if l > int(b.wordCount()) {
- l = int(b.wordCount())
- }
- for i := 0; i < l; i++ {
- b.set[i] &= compare.set[i]
- }
- for i := l; i < len(b.set); i++ {
- b.set[i] = 0
- }
- if compare.length > 0 {
- b.extendSetMaybe(compare.length - 1)
- }
-}
-
-// Union of base set and other set
-// This is the BitSet equivalent of | (or)
-func (b *BitSet) Union(compare *BitSet) (result *BitSet) {
- panicIfNull(b)
- panicIfNull(compare)
- b, compare = sortByLength(b, compare)
- result = compare.Clone()
- for i, word := range b.set {
- result.set[i] = word | compare.set[i]
- }
- return
-}
-
-// UnionCardinality computes the cardinality of the uniton of the base set
-// and the compare set.
-func (b *BitSet) UnionCardinality(compare *BitSet) uint {
- panicIfNull(b)
- panicIfNull(compare)
- b, compare = sortByLength(b, compare)
- cnt := popcntOrSlice(b.set, compare.set)
- if len(compare.set) > len(b.set) {
- cnt += popcntSlice(compare.set[len(b.set):])
- }
- return uint(cnt)
-}
-
-// InPlaceUnion creates the destructive union of base set and compare set.
-// This is the BitSet equivalent of | (or).
-func (b *BitSet) InPlaceUnion(compare *BitSet) {
- panicIfNull(b)
- panicIfNull(compare)
- l := int(compare.wordCount())
- if l > int(b.wordCount()) {
- l = int(b.wordCount())
- }
- if compare.length > 0 {
- b.extendSetMaybe(compare.length - 1)
- }
- for i := 0; i < l; i++ {
- b.set[i] |= compare.set[i]
- }
- if len(compare.set) > l {
- for i := l; i < len(compare.set); i++ {
- b.set[i] = compare.set[i]
- }
- }
-}
-
-// SymmetricDifference of base set and other set
-// This is the BitSet equivalent of ^ (xor)
-func (b *BitSet) SymmetricDifference(compare *BitSet) (result *BitSet) {
- panicIfNull(b)
- panicIfNull(compare)
- b, compare = sortByLength(b, compare)
- // compare is bigger, so clone it
- result = compare.Clone()
- for i, word := range b.set {
- result.set[i] = word ^ compare.set[i]
- }
- return
-}
-
-// SymmetricDifferenceCardinality computes the cardinality of the symmetric difference
-func (b *BitSet) SymmetricDifferenceCardinality(compare *BitSet) uint {
- panicIfNull(b)
- panicIfNull(compare)
- b, compare = sortByLength(b, compare)
- cnt := popcntXorSlice(b.set, compare.set)
- if len(compare.set) > len(b.set) {
- cnt += popcntSlice(compare.set[len(b.set):])
- }
- return uint(cnt)
-}
-
-// InPlaceSymmetricDifference creates the destructive SymmetricDifference of base set and other set
-// This is the BitSet equivalent of ^ (xor)
-func (b *BitSet) InPlaceSymmetricDifference(compare *BitSet) {
- panicIfNull(b)
- panicIfNull(compare)
- l := int(compare.wordCount())
- if l > int(b.wordCount()) {
- l = int(b.wordCount())
- }
- if compare.length > 0 {
- b.extendSetMaybe(compare.length - 1)
- }
- for i := 0; i < l; i++ {
- b.set[i] ^= compare.set[i]
- }
- if len(compare.set) > l {
- for i := l; i < len(compare.set); i++ {
- b.set[i] = compare.set[i]
- }
- }
-}
-
-// Is the length an exact multiple of word sizes?
-func (b *BitSet) isLenExactMultiple() bool {
- return b.length%wordSize == 0
-}
-
-// Clean last word by setting unused bits to 0
-func (b *BitSet) cleanLastWord() {
- if !b.isLenExactMultiple() {
- b.set[len(b.set)-1] &= allBits >> (wordSize - b.length%wordSize)
- }
-}
-
-// Complement computes the (local) complement of a biset (up to length bits)
-func (b *BitSet) Complement() (result *BitSet) {
- panicIfNull(b)
- result = New(b.length)
- for i, word := range b.set {
- result.set[i] = ^word
- }
- result.cleanLastWord()
- return
-}
-
-// All returns true if all bits are set, false otherwise. Returns true for
-// empty sets.
-func (b *BitSet) All() bool {
- panicIfNull(b)
- return b.Count() == b.length
-}
-
-// None returns true if no bit is set, false otherwise. Returns true for
-// empty sets.
-func (b *BitSet) None() bool {
- panicIfNull(b)
- if b != nil && b.set != nil {
- for _, word := range b.set {
- if word > 0 {
- return false
- }
- }
- return true
- }
- return true
-}
-
-// Any returns true if any bit is set, false otherwise
-func (b *BitSet) Any() bool {
- panicIfNull(b)
- return !b.None()
-}
-
-// IsSuperSet returns true if this is a superset of the other set
-func (b *BitSet) IsSuperSet(other *BitSet) bool {
- for i, e := other.NextSet(0); e; i, e = other.NextSet(i + 1) {
- if !b.Test(i) {
- return false
- }
- }
- return true
-}
-
-// IsStrictSuperSet returns true if this is a strict superset of the other set
-func (b *BitSet) IsStrictSuperSet(other *BitSet) bool {
- return b.Count() > other.Count() && b.IsSuperSet(other)
-}
-
-// DumpAsBits dumps a bit set as a string of bits
-func (b *BitSet) DumpAsBits() string {
- if b.set == nil {
- return "."
- }
- buffer := bytes.NewBufferString("")
- i := len(b.set) - 1
- for ; i >= 0; i-- {
- fmt.Fprintf(buffer, "%064b.", b.set[i])
- }
- return buffer.String()
-}
-
-// BinaryStorageSize returns the binary storage requirements
-func (b *BitSet) BinaryStorageSize() int {
- return binary.Size(uint64(0)) + binary.Size(b.set)
-}
-
-// WriteTo writes a BitSet to a stream
-func (b *BitSet) WriteTo(stream io.Writer) (int64, error) {
- length := uint64(b.length)
-
- // Write length
- err := binary.Write(stream, binaryOrder, length)
- if err != nil {
- return 0, err
- }
-
- // Write set
- err = binary.Write(stream, binaryOrder, b.set)
- return int64(b.BinaryStorageSize()), err
-}
-
-// ReadFrom reads a BitSet from a stream written using WriteTo
-func (b *BitSet) ReadFrom(stream io.Reader) (int64, error) {
- var length uint64
-
- // Read length first
- err := binary.Read(stream, binaryOrder, &length)
- if err != nil {
- return 0, err
- }
- newset := New(uint(length))
-
- if uint64(newset.length) != length {
- return 0, errors.New("unmarshalling error: type mismatch")
- }
-
- // Read remaining bytes as set
- err = binary.Read(stream, binaryOrder, newset.set)
- if err != nil {
- return 0, err
- }
-
- *b = *newset
- return int64(b.BinaryStorageSize()), nil
-}
-
-// MarshalBinary encodes a BitSet into a binary form and returns the result.
-func (b *BitSet) MarshalBinary() ([]byte, error) {
- var buf bytes.Buffer
- writer := bufio.NewWriter(&buf)
-
- _, err := b.WriteTo(writer)
- if err != nil {
- return []byte{}, err
- }
-
- err = writer.Flush()
-
- return buf.Bytes(), err
-}
-
-// UnmarshalBinary decodes the binary form generated by MarshalBinary.
-func (b *BitSet) UnmarshalBinary(data []byte) error {
- buf := bytes.NewReader(data)
- reader := bufio.NewReader(buf)
-
- _, err := b.ReadFrom(reader)
-
- return err
-}
-
-// MarshalJSON marshals a BitSet as a JSON structure
-func (b *BitSet) MarshalJSON() ([]byte, error) {
- buffer := bytes.NewBuffer(make([]byte, 0, b.BinaryStorageSize()))
- _, err := b.WriteTo(buffer)
- if err != nil {
- return nil, err
- }
-
- // URLEncode all bytes
- return json.Marshal(base64Encoding.EncodeToString(buffer.Bytes()))
-}
-
-// UnmarshalJSON unmarshals a BitSet from JSON created using MarshalJSON
-func (b *BitSet) UnmarshalJSON(data []byte) error {
- // Unmarshal as string
- var s string
- err := json.Unmarshal(data, &s)
- if err != nil {
- return err
- }
-
- // URLDecode string
- buf, err := base64Encoding.DecodeString(s)
- if err != nil {
- return err
- }
-
- _, err = b.ReadFrom(bytes.NewReader(buf))
- return err
-}
diff --git a/vendor/github.com/bits-and-blooms/bitset/go.mod b/vendor/github.com/bits-and-blooms/bitset/go.mod
deleted file mode 100644
index c43e4522b..000000000
--- a/vendor/github.com/bits-and-blooms/bitset/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module github.com/bits-and-blooms/bitset
-
-go 1.14
diff --git a/vendor/github.com/bits-and-blooms/bitset/go.sum b/vendor/github.com/bits-and-blooms/bitset/go.sum
deleted file mode 100644
index e69de29bb..000000000
--- a/vendor/github.com/bits-and-blooms/bitset/go.sum
+++ /dev/null
diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt.go b/vendor/github.com/bits-and-blooms/bitset/popcnt.go
deleted file mode 100644
index 76577a838..000000000
--- a/vendor/github.com/bits-and-blooms/bitset/popcnt.go
+++ /dev/null
@@ -1,53 +0,0 @@
-package bitset
-
-// bit population count, take from
-// https://code.google.com/p/go/issues/detail?id=4988#c11
-// credit: https://code.google.com/u/arnehormann/
-func popcount(x uint64) (n uint64) {
- x -= (x >> 1) & 0x5555555555555555
- x = (x>>2)&0x3333333333333333 + x&0x3333333333333333
- x += x >> 4
- x &= 0x0f0f0f0f0f0f0f0f
- x *= 0x0101010101010101
- return x >> 56
-}
-
-func popcntSliceGo(s []uint64) uint64 {
- cnt := uint64(0)
- for _, x := range s {
- cnt += popcount(x)
- }
- return cnt
-}
-
-func popcntMaskSliceGo(s, m []uint64) uint64 {
- cnt := uint64(0)
- for i := range s {
- cnt += popcount(s[i] &^ m[i])
- }
- return cnt
-}
-
-func popcntAndSliceGo(s, m []uint64) uint64 {
- cnt := uint64(0)
- for i := range s {
- cnt += popcount(s[i] & m[i])
- }
- return cnt
-}
-
-func popcntOrSliceGo(s, m []uint64) uint64 {
- cnt := uint64(0)
- for i := range s {
- cnt += popcount(s[i] | m[i])
- }
- return cnt
-}
-
-func popcntXorSliceGo(s, m []uint64) uint64 {
- cnt := uint64(0)
- for i := range s {
- cnt += popcount(s[i] ^ m[i])
- }
- return cnt
-}
diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go b/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go
deleted file mode 100644
index fc8ff4f36..000000000
--- a/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go
+++ /dev/null
@@ -1,45 +0,0 @@
-// +build go1.9
-
-package bitset
-
-import "math/bits"
-
-func popcntSlice(s []uint64) uint64 {
- var cnt int
- for _, x := range s {
- cnt += bits.OnesCount64(x)
- }
- return uint64(cnt)
-}
-
-func popcntMaskSlice(s, m []uint64) uint64 {
- var cnt int
- for i := range s {
- cnt += bits.OnesCount64(s[i] &^ m[i])
- }
- return uint64(cnt)
-}
-
-func popcntAndSlice(s, m []uint64) uint64 {
- var cnt int
- for i := range s {
- cnt += bits.OnesCount64(s[i] & m[i])
- }
- return uint64(cnt)
-}
-
-func popcntOrSlice(s, m []uint64) uint64 {
- var cnt int
- for i := range s {
- cnt += bits.OnesCount64(s[i] | m[i])
- }
- return uint64(cnt)
-}
-
-func popcntXorSlice(s, m []uint64) uint64 {
- var cnt int
- for i := range s {
- cnt += bits.OnesCount64(s[i] ^ m[i])
- }
- return uint64(cnt)
-}
diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go b/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go
deleted file mode 100644
index 4cf64f24a..000000000
--- a/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go
+++ /dev/null
@@ -1,68 +0,0 @@
-// +build !go1.9
-// +build amd64,!appengine
-
-package bitset
-
-// *** the following functions are defined in popcnt_amd64.s
-
-//go:noescape
-
-func hasAsm() bool
-
-// useAsm is a flag used to select the GO or ASM implementation of the popcnt function
-var useAsm = hasAsm()
-
-//go:noescape
-
-func popcntSliceAsm(s []uint64) uint64
-
-//go:noescape
-
-func popcntMaskSliceAsm(s, m []uint64) uint64
-
-//go:noescape
-
-func popcntAndSliceAsm(s, m []uint64) uint64
-
-//go:noescape
-
-func popcntOrSliceAsm(s, m []uint64) uint64
-
-//go:noescape
-
-func popcntXorSliceAsm(s, m []uint64) uint64
-
-func popcntSlice(s []uint64) uint64 {
- if useAsm {
- return popcntSliceAsm(s)
- }
- return popcntSliceGo(s)
-}
-
-func popcntMaskSlice(s, m []uint64) uint64 {
- if useAsm {
- return popcntMaskSliceAsm(s, m)
- }
- return popcntMaskSliceGo(s, m)
-}
-
-func popcntAndSlice(s, m []uint64) uint64 {
- if useAsm {
- return popcntAndSliceAsm(s, m)
- }
- return popcntAndSliceGo(s, m)
-}
-
-func popcntOrSlice(s, m []uint64) uint64 {
- if useAsm {
- return popcntOrSliceAsm(s, m)
- }
- return popcntOrSliceGo(s, m)
-}
-
-func popcntXorSlice(s, m []uint64) uint64 {
- if useAsm {
- return popcntXorSliceAsm(s, m)
- }
- return popcntXorSliceGo(s, m)
-}
diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.s b/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.s
deleted file mode 100644
index 666c0dcc1..000000000
--- a/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.s
+++ /dev/null
@@ -1,104 +0,0 @@
-// +build !go1.9
-// +build amd64,!appengine
-
-TEXT ·hasAsm(SB),4,$0-1
-MOVQ $1, AX
-CPUID
-SHRQ $23, CX
-ANDQ $1, CX
-MOVB CX, ret+0(FP)
-RET
-
-#define POPCNTQ_DX_DX BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0xd2
-
-TEXT ·popcntSliceAsm(SB),4,$0-32
-XORQ AX, AX
-MOVQ s+0(FP), SI
-MOVQ s_len+8(FP), CX
-TESTQ CX, CX
-JZ popcntSliceEnd
-popcntSliceLoop:
-BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0x16 // POPCNTQ (SI), DX
-ADDQ DX, AX
-ADDQ $8, SI
-LOOP popcntSliceLoop
-popcntSliceEnd:
-MOVQ AX, ret+24(FP)
-RET
-
-TEXT ·popcntMaskSliceAsm(SB),4,$0-56
-XORQ AX, AX
-MOVQ s+0(FP), SI
-MOVQ s_len+8(FP), CX
-TESTQ CX, CX
-JZ popcntMaskSliceEnd
-MOVQ m+24(FP), DI
-popcntMaskSliceLoop:
-MOVQ (DI), DX
-NOTQ DX
-ANDQ (SI), DX
-POPCNTQ_DX_DX
-ADDQ DX, AX
-ADDQ $8, SI
-ADDQ $8, DI
-LOOP popcntMaskSliceLoop
-popcntMaskSliceEnd:
-MOVQ AX, ret+48(FP)
-RET
-
-TEXT ·popcntAndSliceAsm(SB),4,$0-56
-XORQ AX, AX
-MOVQ s+0(FP), SI
-MOVQ s_len+8(FP), CX
-TESTQ CX, CX
-JZ popcntAndSliceEnd
-MOVQ m+24(FP), DI
-popcntAndSliceLoop:
-MOVQ (DI), DX
-ANDQ (SI), DX
-POPCNTQ_DX_DX
-ADDQ DX, AX
-ADDQ $8, SI
-ADDQ $8, DI
-LOOP popcntAndSliceLoop
-popcntAndSliceEnd:
-MOVQ AX, ret+48(FP)
-RET
-
-TEXT ·popcntOrSliceAsm(SB),4,$0-56
-XORQ AX, AX
-MOVQ s+0(FP), SI
-MOVQ s_len+8(FP), CX
-TESTQ CX, CX
-JZ popcntOrSliceEnd
-MOVQ m+24(FP), DI
-popcntOrSliceLoop:
-MOVQ (DI), DX
-ORQ (SI), DX
-POPCNTQ_DX_DX
-ADDQ DX, AX
-ADDQ $8, SI
-ADDQ $8, DI
-LOOP popcntOrSliceLoop
-popcntOrSliceEnd:
-MOVQ AX, ret+48(FP)
-RET
-
-TEXT ·popcntXorSliceAsm(SB),4,$0-56
-XORQ AX, AX
-MOVQ s+0(FP), SI
-MOVQ s_len+8(FP), CX
-TESTQ CX, CX
-JZ popcntXorSliceEnd
-MOVQ m+24(FP), DI
-popcntXorSliceLoop:
-MOVQ (DI), DX
-XORQ (SI), DX
-POPCNTQ_DX_DX
-ADDQ DX, AX
-ADDQ $8, SI
-ADDQ $8, DI
-LOOP popcntXorSliceLoop
-popcntXorSliceEnd:
-MOVQ AX, ret+48(FP)
-RET
diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go b/vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go
deleted file mode 100644
index 21e0ff7b4..000000000
--- a/vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// +build !go1.9
-// +build !amd64 appengine
-
-package bitset
-
-func popcntSlice(s []uint64) uint64 {
- return popcntSliceGo(s)
-}
-
-func popcntMaskSlice(s, m []uint64) uint64 {
- return popcntMaskSliceGo(s, m)
-}
-
-func popcntAndSlice(s, m []uint64) uint64 {
- return popcntAndSliceGo(s, m)
-}
-
-func popcntOrSlice(s, m []uint64) uint64 {
- return popcntOrSliceGo(s, m)
-}
-
-func popcntXorSlice(s, m []uint64) uint64 {
- return popcntXorSliceGo(s, m)
-}
diff --git a/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go b/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go
deleted file mode 100644
index c52b61be9..000000000
--- a/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go
+++ /dev/null
@@ -1,14 +0,0 @@
-// +build !go1.9
-
-package bitset
-
-var deBruijn = [...]byte{
- 0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4,
- 62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5,
- 63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11,
- 54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
-}
-
-func trailingZeroes64(v uint64) uint {
- return uint(deBruijn[((v&-v)*0x03f79d71b4ca8b09)>>58])
-}
diff --git a/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go b/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go
deleted file mode 100644
index 36a988e71..000000000
--- a/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go
+++ /dev/null
@@ -1,9 +0,0 @@
-// +build go1.9
-
-package bitset
-
-import "math/bits"
-
-func trailingZeroes64(v uint64) uint {
- return uint(bits.TrailingZeros64(v))
-}
diff --git a/vendor/github.com/containerd/stargz-snapshotter/estargz/estargz.go b/vendor/github.com/containerd/stargz-snapshotter/estargz/estargz.go
index e997d9cce..3ef029116 100644
--- a/vendor/github.com/containerd/stargz-snapshotter/estargz/estargz.go
+++ b/vendor/github.com/containerd/stargz-snapshotter/estargz/estargz.go
@@ -23,7 +23,6 @@
package estargz
import (
- "archive/tar"
"bufio"
"bytes"
"compress/gzip"
@@ -42,6 +41,7 @@ import (
"github.com/containerd/stargz-snapshotter/estargz/errorutil"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
+ "github.com/vbatts/tar-split/archive/tar"
)
// A Reader permits random access reads from a stargz file.
@@ -95,10 +95,10 @@ func WithTelemetry(telemetry *Telemetry) OpenOption {
}
}
-// A func which takes start time and records the diff
+// MeasureLatencyHook is a func which takes start time and records the diff
type MeasureLatencyHook func(time.Time)
-// A struct which defines telemetry hooks. By implementing these hooks you should be able to record
+// Telemetry is a struct which defines telemetry hooks. By implementing these hooks you should be able to record
// the latency metrics of the respective steps of estargz open operation. To be used with estargz.OpenWithTelemetry(...)
type Telemetry struct {
GetFooterLatency MeasureLatencyHook // measure time to get stargz footer (in milliseconds)
@@ -146,7 +146,7 @@ func Open(sr *io.SectionReader, opt ...OpenOption) (*Reader, error) {
fSize := d.FooterSize()
fOffset := positive(int64(len(footer)) - fSize)
maybeTocBytes := footer[:fOffset]
- tocOffset, tocSize, err := d.ParseFooter(footer[fOffset:])
+ _, tocOffset, tocSize, err := d.ParseFooter(footer[fOffset:])
if err != nil {
allErr = append(allErr, err)
continue
@@ -187,7 +187,7 @@ func OpenFooter(sr *io.SectionReader) (tocOffset int64, footerSize int64, rErr e
for _, d := range []Decompressor{new(GzipDecompressor), new(legacyGzipDecompressor)} {
fSize := d.FooterSize()
fOffset := positive(int64(len(footer)) - fSize)
- tocOffset, _, err := d.ParseFooter(footer[fOffset:])
+ _, tocOffset, _, err := d.ParseFooter(footer[fOffset:])
if err == nil {
return tocOffset, fSize, err
}
@@ -326,6 +326,10 @@ func (r *Reader) getOrCreateDir(d string) *TOCEntry {
return e
}
+func (r *Reader) TOCDigest() digest.Digest {
+ return r.tocDigest
+}
+
// VerifyTOC checks that the TOC JSON in the passed blob matches the
// passed digests and that the TOC JSON contains digests for all chunks
// contained in the blob. If the verification succceeds, this function
@@ -335,7 +339,12 @@ func (r *Reader) VerifyTOC(tocDigest digest.Digest) (TOCEntryVerifier, error) {
if r.tocDigest != tocDigest {
return nil, fmt.Errorf("invalid TOC JSON %q; want %q", r.tocDigest, tocDigest)
}
+ return r.Verifiers()
+}
+// Verifiers returns TOCEntryVerifier of this chunk. Use VerifyTOC instead in most cases
+// because this doesn't verify TOC.
+func (r *Reader) Verifiers() (TOCEntryVerifier, error) {
chunkDigestMap := make(map[int64]digest.Digest) // map from chunk offset to the chunk digest
regDigestMap := make(map[int64]digest.Digest) // map from chunk offset to the reg file digest
var chunkDigestMapIncomplete bool
@@ -591,6 +600,11 @@ type currentCompressionWriter struct{ w *Writer }
func (ccw currentCompressionWriter) Write(p []byte) (int, error) {
ccw.w.diffHash.Write(p)
+ if ccw.w.gz == nil {
+ if err := ccw.w.condOpenGz(); err != nil {
+ return 0, err
+ }
+ }
return ccw.w.gz.Write(p)
}
@@ -601,6 +615,25 @@ func (w *Writer) chunkSize() int {
return w.ChunkSize
}
+// Unpack decompresses the given estargz blob and returns a ReadCloser of the tar blob.
+// TOC JSON and footer are removed.
+func Unpack(sr *io.SectionReader, c Decompressor) (io.ReadCloser, error) {
+ footerSize := c.FooterSize()
+ if sr.Size() < footerSize {
+ return nil, fmt.Errorf("blob is too small; %d < %d", sr.Size(), footerSize)
+ }
+ footerOffset := sr.Size() - footerSize
+ footer := make([]byte, footerSize)
+ if _, err := sr.ReadAt(footer, footerOffset); err != nil {
+ return nil, err
+ }
+ blobPayloadSize, _, _, err := c.ParseFooter(footer)
+ if err != nil {
+ return nil, errors.Wrapf(err, "failed to parse footer")
+ }
+ return c.Reader(io.LimitReader(sr, blobPayloadSize))
+}
+
// NewWriter returns a new stargz writer (gzip-based) writing to w.
//
// The writer must be closed to write its trailing table of contents.
@@ -616,7 +649,7 @@ func NewWriterLevel(w io.Writer, compressionLevel int) *Writer {
return NewWriterWithCompressor(w, NewGzipCompressorWithLevel(compressionLevel))
}
-// NewWriterLevel returns a new stargz writer writing to w.
+// NewWriterWithCompressor returns a new stargz writer writing to w.
// The compression method is configurable.
//
// The writer must be closed to write its trailing table of contents.
@@ -696,29 +729,71 @@ func (w *Writer) condOpenGz() (err error) {
// each of its contents to w.
//
// The input r can optionally be gzip compressed but the output will
-// always be gzip compressed.
+// always be compressed by the specified compressor.
func (w *Writer) AppendTar(r io.Reader) error {
+ return w.appendTar(r, false)
+}
+
+// AppendTarLossLess reads the tar or tar.gz file from r and appends
+// each of its contents to w.
+//
+// The input r can optionally be gzip compressed but the output will
+// always be compressed by the specified compressor.
+//
+// The difference of this func with AppendTar is that this writes
+// the input tar stream into w without any modification (e.g. to header bytes).
+//
+// Note that if the input tar stream already contains TOC JSON, this returns
+// error because w cannot overwrite the TOC JSON to the one generated by w without
+// lossy modification. To avoid this error, if the input stream is known to be stargz/estargz,
+// you shoud decompress it and remove TOC JSON in advance.
+func (w *Writer) AppendTarLossLess(r io.Reader) error {
+ return w.appendTar(r, true)
+}
+
+func (w *Writer) appendTar(r io.Reader, lossless bool) error {
+ var src io.Reader
br := bufio.NewReader(r)
- var tr *tar.Reader
if isGzip(br) {
- // NewReader can't fail if isGzip returned true.
zr, _ := gzip.NewReader(br)
- tr = tar.NewReader(zr)
+ src = zr
} else {
- tr = tar.NewReader(br)
+ src = io.Reader(br)
+ }
+ dst := currentCompressionWriter{w}
+ var tw *tar.Writer
+ if !lossless {
+ tw = tar.NewWriter(dst) // use tar writer only when this isn't lossless mode.
+ }
+ tr := tar.NewReader(src)
+ if lossless {
+ tr.RawAccounting = true
}
for {
h, err := tr.Next()
if err == io.EOF {
+ if lossless {
+ if remain := tr.RawBytes(); len(remain) > 0 {
+ // Collect the remaining null bytes.
+ // https://github.com/vbatts/tar-split/blob/80a436fd6164c557b131f7c59ed69bd81af69761/concept/main.go#L49-L53
+ if _, err := dst.Write(remain); err != nil {
+ return err
+ }
+ }
+ }
break
}
if err != nil {
return fmt.Errorf("error reading from source tar: tar.Reader.Next: %v", err)
}
- if h.Name == TOCTarName {
+ if cleanEntryName(h.Name) == TOCTarName {
// It is possible for a layer to be "stargzified" twice during the
// distribution lifecycle. So we reserve "TOCTarName" here to avoid
// duplicated entries in the resulting layer.
+ if lossless {
+ // We cannot handle this in lossless way.
+ return fmt.Errorf("existing TOC JSON is not allowed; decompress layer before append")
+ }
continue
}
@@ -744,9 +819,14 @@ func (w *Writer) AppendTar(r io.Reader) error {
if err := w.condOpenGz(); err != nil {
return err
}
- tw := tar.NewWriter(currentCompressionWriter{w})
- if err := tw.WriteHeader(h); err != nil {
- return err
+ if tw != nil {
+ if err := tw.WriteHeader(h); err != nil {
+ return err
+ }
+ } else {
+ if _, err := dst.Write(tr.RawBytes()); err != nil {
+ return err
+ }
}
switch h.Typeflag {
case tar.TypeLink:
@@ -808,7 +888,13 @@ func (w *Writer) AppendTar(r io.Reader) error {
}
teeChunk := io.TeeReader(tee, chunkDigest.Hash())
- if _, err := io.CopyN(tw, teeChunk, chunkSize); err != nil {
+ var out io.Writer
+ if tw != nil {
+ out = tw
+ } else {
+ out = dst
+ }
+ if _, err := io.CopyN(out, teeChunk, chunkSize); err != nil {
return fmt.Errorf("error copying %q: %v", h.Name, err)
}
ent.ChunkDigest = chunkDigest.Digest().String()
@@ -825,11 +911,18 @@ func (w *Writer) AppendTar(r io.Reader) error {
if payloadDigest != nil {
regFileEntry.Digest = payloadDigest.Digest().String()
}
- if err := tw.Flush(); err != nil {
- return err
+ if tw != nil {
+ if err := tw.Flush(); err != nil {
+ return err
+ }
}
}
- return nil
+ remainDest := ioutil.Discard
+ if lossless {
+ remainDest = dst // Preserve the remaining bytes in lossless mode
+ }
+ _, err := io.Copy(remainDest, src)
+ return err
}
// DiffID returns the SHA-256 of the uncompressed tar bytes.
diff --git a/vendor/github.com/containerd/stargz-snapshotter/estargz/go.mod b/vendor/github.com/containerd/stargz-snapshotter/estargz/go.mod
index ee6b2e17f..144d022ba 100644
--- a/vendor/github.com/containerd/stargz-snapshotter/estargz/go.mod
+++ b/vendor/github.com/containerd/stargz-snapshotter/estargz/go.mod
@@ -3,8 +3,9 @@ module github.com/containerd/stargz-snapshotter/estargz
go 1.16
require (
- github.com/klauspost/compress v1.13.5
+ github.com/klauspost/compress v1.13.6
github.com/opencontainers/go-digest v1.0.0
github.com/pkg/errors v0.9.1
+ github.com/vbatts/tar-split v0.11.2
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
)
diff --git a/vendor/github.com/containerd/stargz-snapshotter/estargz/go.sum b/vendor/github.com/containerd/stargz-snapshotter/estargz/go.sum
index 66cd2d69c..d3c934ff8 100644
--- a/vendor/github.com/containerd/stargz-snapshotter/estargz/go.sum
+++ b/vendor/github.com/containerd/stargz-snapshotter/estargz/go.sum
@@ -1,8 +1,22 @@
-github.com/klauspost/compress v1.13.5 h1:9O69jUPDcsT9fEm74W92rZL9FQY7rCdaXVneq+yyzl4=
-github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
+github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME=
+github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/vendor/github.com/containerd/stargz-snapshotter/estargz/gzip.go b/vendor/github.com/containerd/stargz-snapshotter/estargz/gzip.go
index efc435e09..88e1283d8 100644
--- a/vendor/github.com/containerd/stargz-snapshotter/estargz/gzip.go
+++ b/vendor/github.com/containerd/stargz-snapshotter/estargz/gzip.go
@@ -124,31 +124,31 @@ func (gz *GzipDecompressor) ParseTOC(r io.Reader) (toc *JTOC, tocDgst digest.Dig
return parseTOCEStargz(r)
}
-func (gz *GzipDecompressor) ParseFooter(p []byte) (tocOffset, tocSize int64, err error) {
+func (gz *GzipDecompressor) ParseFooter(p []byte) (blobPayloadSize, tocOffset, tocSize int64, err error) {
if len(p) != FooterSize {
- return 0, 0, fmt.Errorf("invalid length %d cannot be parsed", len(p))
+ return 0, 0, 0, fmt.Errorf("invalid length %d cannot be parsed", len(p))
}
zr, err := gzip.NewReader(bytes.NewReader(p))
if err != nil {
- return 0, 0, err
+ return 0, 0, 0, err
}
defer zr.Close()
extra := zr.Header.Extra
si1, si2, subfieldlen, subfield := extra[0], extra[1], extra[2:4], extra[4:]
if si1 != 'S' || si2 != 'G' {
- return 0, 0, fmt.Errorf("invalid subfield IDs: %q, %q; want E, S", si1, si2)
+ return 0, 0, 0, fmt.Errorf("invalid subfield IDs: %q, %q; want E, S", si1, si2)
}
if slen := binary.LittleEndian.Uint16(subfieldlen); slen != uint16(16+len("STARGZ")) {
- return 0, 0, fmt.Errorf("invalid length of subfield %d; want %d", slen, 16+len("STARGZ"))
+ return 0, 0, 0, fmt.Errorf("invalid length of subfield %d; want %d", slen, 16+len("STARGZ"))
}
if string(subfield[16:]) != "STARGZ" {
- return 0, 0, fmt.Errorf("STARGZ magic string must be included in the footer subfield")
+ return 0, 0, 0, fmt.Errorf("STARGZ magic string must be included in the footer subfield")
}
tocOffset, err = strconv.ParseInt(string(subfield[:16]), 16, 64)
if err != nil {
- return 0, 0, errors.Wrapf(err, "legacy: failed to parse toc offset")
+ return 0, 0, 0, errors.Wrapf(err, "legacy: failed to parse toc offset")
}
- return tocOffset, 0, nil
+ return tocOffset, tocOffset, 0, nil
}
func (gz *GzipDecompressor) FooterSize() int64 {
@@ -165,27 +165,27 @@ func (gz *legacyGzipDecompressor) ParseTOC(r io.Reader) (toc *JTOC, tocDgst dige
return parseTOCEStargz(r)
}
-func (gz *legacyGzipDecompressor) ParseFooter(p []byte) (tocOffset, tocSize int64, err error) {
+func (gz *legacyGzipDecompressor) ParseFooter(p []byte) (blobPayloadSize, tocOffset, tocSize int64, err error) {
if len(p) != legacyFooterSize {
- return 0, 0, fmt.Errorf("legacy: invalid length %d cannot be parsed", len(p))
+ return 0, 0, 0, fmt.Errorf("legacy: invalid length %d cannot be parsed", len(p))
}
zr, err := gzip.NewReader(bytes.NewReader(p))
if err != nil {
- return 0, 0, errors.Wrapf(err, "legacy: failed to get footer gzip reader")
+ return 0, 0, 0, errors.Wrapf(err, "legacy: failed to get footer gzip reader")
}
defer zr.Close()
extra := zr.Header.Extra
if len(extra) != 16+len("STARGZ") {
- return 0, 0, fmt.Errorf("legacy: invalid stargz's extra field size")
+ return 0, 0, 0, fmt.Errorf("legacy: invalid stargz's extra field size")
}
if string(extra[16:]) != "STARGZ" {
- return 0, 0, fmt.Errorf("legacy: magic string STARGZ not found")
+ return 0, 0, 0, fmt.Errorf("legacy: magic string STARGZ not found")
}
tocOffset, err = strconv.ParseInt(string(extra[:16]), 16, 64)
if err != nil {
- return 0, 0, errors.Wrapf(err, "legacy: failed to parse toc offset")
+ return 0, 0, 0, errors.Wrapf(err, "legacy: failed to parse toc offset")
}
- return tocOffset, 0, nil
+ return tocOffset, tocOffset, 0, nil
}
func (gz *legacyGzipDecompressor) FooterSize() int64 {
diff --git a/vendor/github.com/containerd/stargz-snapshotter/estargz/testutil.go b/vendor/github.com/containerd/stargz-snapshotter/estargz/testutil.go
index 020729b7e..9224e456d 100644
--- a/vendor/github.com/containerd/stargz-snapshotter/estargz/testutil.go
+++ b/vendor/github.com/containerd/stargz-snapshotter/estargz/testutil.go
@@ -148,93 +148,96 @@ func testBuild(t *testing.T, controllers ...TestingController) {
srcCompression := srcCompression
for _, cl := range controllers {
cl := cl
- for _, prefix := range allowedPrefix {
- prefix := prefix
- t.Run(tt.name+"-"+fmt.Sprintf("compression=%v-prefix=%q-src=%d", cl, prefix, srcCompression), func(t *testing.T) {
- tarBlob := buildTarStatic(t, tt.in, prefix)
- // Test divideEntries()
- entries, err := sortEntries(tarBlob, nil, nil) // identical order
- if err != nil {
- t.Fatalf("faield to parse tar: %v", err)
- }
- var merged []*entry
- for _, part := range divideEntries(entries, 4) {
- merged = append(merged, part...)
- }
- if !reflect.DeepEqual(entries, merged) {
- for _, e := range entries {
- t.Logf("Original: %v", e.header)
+ for _, srcTarFormat := range []tar.Format{tar.FormatUSTAR, tar.FormatPAX, tar.FormatGNU} {
+ srcTarFormat := srcTarFormat
+ for _, prefix := range allowedPrefix {
+ prefix := prefix
+ t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,src=%d,format=%s", cl, prefix, srcCompression, srcTarFormat), func(t *testing.T) {
+ tarBlob := buildTar(t, tt.in, prefix, srcTarFormat)
+ // Test divideEntries()
+ entries, err := sortEntries(tarBlob, nil, nil) // identical order
+ if err != nil {
+ t.Fatalf("failed to parse tar: %v", err)
}
- for _, e := range merged {
- t.Logf("Merged: %v", e.header)
+ var merged []*entry
+ for _, part := range divideEntries(entries, 4) {
+ merged = append(merged, part...)
+ }
+ if !reflect.DeepEqual(entries, merged) {
+ for _, e := range entries {
+ t.Logf("Original: %v", e.header)
+ }
+ for _, e := range merged {
+ t.Logf("Merged: %v", e.header)
+ }
+ t.Errorf("divided entries couldn't be merged")
+ return
}
- t.Errorf("divided entries couldn't be merged")
- return
- }
- // Prepare sample data
- wantBuf := new(bytes.Buffer)
- sw := NewWriterWithCompressor(wantBuf, cl)
- sw.ChunkSize = tt.chunkSize
- if err := sw.AppendTar(tarBlob); err != nil {
- t.Fatalf("faield to append tar to want stargz: %v", err)
- }
- if _, err := sw.Close(); err != nil {
- t.Fatalf("faield to prepare want stargz: %v", err)
- }
- wantData := wantBuf.Bytes()
- want, err := Open(io.NewSectionReader(
- bytes.NewReader(wantData), 0, int64(len(wantData))),
- WithDecompressors(cl),
- )
- if err != nil {
- t.Fatalf("failed to parse the want stargz: %v", err)
- }
+ // Prepare sample data
+ wantBuf := new(bytes.Buffer)
+ sw := NewWriterWithCompressor(wantBuf, cl)
+ sw.ChunkSize = tt.chunkSize
+ if err := sw.AppendTar(tarBlob); err != nil {
+ t.Fatalf("failed to append tar to want stargz: %v", err)
+ }
+ if _, err := sw.Close(); err != nil {
+ t.Fatalf("failed to prepare want stargz: %v", err)
+ }
+ wantData := wantBuf.Bytes()
+ want, err := Open(io.NewSectionReader(
+ bytes.NewReader(wantData), 0, int64(len(wantData))),
+ WithDecompressors(cl),
+ )
+ if err != nil {
+ t.Fatalf("failed to parse the want stargz: %v", err)
+ }
- // Prepare testing data
- rc, err := Build(compressBlob(t, tarBlob, srcCompression),
- WithChunkSize(tt.chunkSize), WithCompression(cl))
- if err != nil {
- t.Fatalf("faield to build stargz: %v", err)
- }
- defer rc.Close()
- gotBuf := new(bytes.Buffer)
- if _, err := io.Copy(gotBuf, rc); err != nil {
- t.Fatalf("failed to copy built stargz blob: %v", err)
- }
- gotData := gotBuf.Bytes()
- got, err := Open(io.NewSectionReader(
- bytes.NewReader(gotBuf.Bytes()), 0, int64(len(gotData))),
- WithDecompressors(cl),
- )
- if err != nil {
- t.Fatalf("failed to parse the got stargz: %v", err)
- }
+ // Prepare testing data
+ rc, err := Build(compressBlob(t, tarBlob, srcCompression),
+ WithChunkSize(tt.chunkSize), WithCompression(cl))
+ if err != nil {
+ t.Fatalf("failed to build stargz: %v", err)
+ }
+ defer rc.Close()
+ gotBuf := new(bytes.Buffer)
+ if _, err := io.Copy(gotBuf, rc); err != nil {
+ t.Fatalf("failed to copy built stargz blob: %v", err)
+ }
+ gotData := gotBuf.Bytes()
+ got, err := Open(io.NewSectionReader(
+ bytes.NewReader(gotBuf.Bytes()), 0, int64(len(gotData))),
+ WithDecompressors(cl),
+ )
+ if err != nil {
+ t.Fatalf("failed to parse the got stargz: %v", err)
+ }
- // Check DiffID is properly calculated
- rc.Close()
- diffID := rc.DiffID()
- wantDiffID := cl.DiffIDOf(t, gotData)
- if diffID.String() != wantDiffID {
- t.Errorf("DiffID = %q; want %q", diffID, wantDiffID)
- }
+ // Check DiffID is properly calculated
+ rc.Close()
+ diffID := rc.DiffID()
+ wantDiffID := cl.DiffIDOf(t, gotData)
+ if diffID.String() != wantDiffID {
+ t.Errorf("DiffID = %q; want %q", diffID, wantDiffID)
+ }
- // Compare as stargz
- if !isSameVersion(t, cl, wantData, gotData) {
- t.Errorf("built stargz hasn't same json")
- return
- }
- if !isSameEntries(t, want, got) {
- t.Errorf("built stargz isn't same as the original")
- return
- }
+ // Compare as stargz
+ if !isSameVersion(t, cl, wantData, gotData) {
+ t.Errorf("built stargz hasn't same json")
+ return
+ }
+ if !isSameEntries(t, want, got) {
+ t.Errorf("built stargz isn't same as the original")
+ return
+ }
- // Compare as tar.gz
- if !isSameTarGz(t, cl, wantData, gotData) {
- t.Errorf("built stargz isn't same tar.gz")
- return
- }
- })
+ // Compare as tar.gz
+ if !isSameTarGz(t, cl, wantData, gotData) {
+ t.Errorf("built stargz isn't same tar.gz")
+ return
+ }
+ })
+ }
}
}
}
@@ -526,7 +529,7 @@ func testDigestAndVerify(t *testing.T, controllers ...TestingController) {
checks: []check{
checkStargzTOC,
checkVerifyTOC,
- checkVerifyInvalidStargzFail(buildTarStatic(t, tarOf(
+ checkVerifyInvalidStargzFail(buildTar(t, tarOf(
dir("test2/"), // modified
), allowedPrefix[0])),
},
@@ -544,7 +547,7 @@ func testDigestAndVerify(t *testing.T, controllers ...TestingController) {
checks: []check{
checkStargzTOC,
checkVerifyTOC,
- checkVerifyInvalidStargzFail(buildTarStatic(t, tarOf(
+ checkVerifyInvalidStargzFail(buildTar(t, tarOf(
file("baz.txt", ""),
file("foo.txt", "M"), // modified
dir("test/"),
@@ -567,7 +570,7 @@ func testDigestAndVerify(t *testing.T, controllers ...TestingController) {
checks: []check{
checkStargzTOC,
checkVerifyTOC,
- checkVerifyInvalidStargzFail(buildTarStatic(t, tarOf(
+ checkVerifyInvalidStargzFail(buildTar(t, tarOf(
file("baz.txt", "bazbazbazMMMbazbazbaz"), // modified
file("foo.txt", "a"),
dir("test/"),
@@ -593,7 +596,7 @@ func testDigestAndVerify(t *testing.T, controllers ...TestingController) {
checks: []check{
checkStargzTOC,
checkVerifyTOC,
- checkVerifyInvalidStargzFail(buildTarStatic(t, tarOf(
+ checkVerifyInvalidStargzFail(buildTar(t, tarOf(
file("baz.txt", "bazbazbazbazbazbazbaz"),
file("foo.txt", "a"),
symlink("barlink", "test/bar.txt"),
@@ -615,30 +618,33 @@ func testDigestAndVerify(t *testing.T, controllers ...TestingController) {
cl := cl
for _, prefix := range allowedPrefix {
prefix := prefix
- t.Run(tt.name+"-"+fmt.Sprintf("compression=%v-prefix=%q", cl, prefix), func(t *testing.T) {
- // Get original tar file and chunk digests
- dgstMap := make(map[string]digest.Digest)
- tarBlob := buildTarStatic(t, tt.tarInit(t, dgstMap), prefix)
-
- rc, err := Build(compressBlob(t, tarBlob, srcCompression),
- WithChunkSize(chunkSize), WithCompression(cl))
- if err != nil {
- t.Fatalf("failed to convert stargz: %v", err)
- }
- tocDigest := rc.TOCDigest()
- defer rc.Close()
- buf := new(bytes.Buffer)
- if _, err := io.Copy(buf, rc); err != nil {
- t.Fatalf("failed to copy built stargz blob: %v", err)
- }
- newStargz := buf.Bytes()
- // NoPrefetchLandmark is added during `Bulid`, which is expected behaviour.
- dgstMap[chunkID(NoPrefetchLandmark, 0, int64(len([]byte{landmarkContents})))] = digest.FromBytes([]byte{landmarkContents})
+ for _, srcTarFormat := range []tar.Format{tar.FormatUSTAR, tar.FormatPAX, tar.FormatGNU} {
+ srcTarFormat := srcTarFormat
+ t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,format=%s", cl, prefix, srcTarFormat), func(t *testing.T) {
+ // Get original tar file and chunk digests
+ dgstMap := make(map[string]digest.Digest)
+ tarBlob := buildTar(t, tt.tarInit(t, dgstMap), prefix, srcTarFormat)
+
+ rc, err := Build(compressBlob(t, tarBlob, srcCompression),
+ WithChunkSize(chunkSize), WithCompression(cl))
+ if err != nil {
+ t.Fatalf("failed to convert stargz: %v", err)
+ }
+ tocDigest := rc.TOCDigest()
+ defer rc.Close()
+ buf := new(bytes.Buffer)
+ if _, err := io.Copy(buf, rc); err != nil {
+ t.Fatalf("failed to copy built stargz blob: %v", err)
+ }
+ newStargz := buf.Bytes()
+ // NoPrefetchLandmark is added during `Bulid`, which is expected behaviour.
+ dgstMap[chunkID(NoPrefetchLandmark, 0, int64(len([]byte{landmarkContents})))] = digest.FromBytes([]byte{landmarkContents})
- for _, check := range tt.checks {
- check(t, newStargz, tocDigest, dgstMap, cl)
- }
- })
+ for _, check := range tt.checks {
+ check(t, newStargz, tocDigest, dgstMap, cl)
+ }
+ })
+ }
}
}
}
@@ -1058,7 +1064,7 @@ func parseStargz(sgz *io.SectionReader, controller TestingController) (decodedJT
if _, err := sgz.ReadAt(footer, sgz.Size()-fSize); err != nil {
return nil, 0, errors.Wrap(err, "error reading footer")
}
- tocOffset, _, err := controller.ParseFooter(footer[positive(int64(len(footer))-fSize):])
+ _, tocOffset, _, err := controller.ParseFooter(footer[positive(int64(len(footer))-fSize):])
if err != nil {
return nil, 0, errors.Wrapf(err, "failed to parse footer")
}
@@ -1085,11 +1091,15 @@ func testWriteAndOpen(t *testing.T, controllers ...TestingController) {
in []tarEntry
want []stargzCheck
wantNumGz int // expected number of streams
+
+ wantNumGzLossLess int // expected number of streams (> 0) in lossless mode if it's different from wantNumGz
+ wantFailOnLossLess bool
}{
{
- name: "empty",
- in: tarOf(),
- wantNumGz: 2, // TOC + footer
+ name: "empty",
+ in: tarOf(),
+ wantNumGz: 2, // empty tar + TOC + footer
+ wantNumGzLossLess: 3, // empty tar + TOC + footer
want: checks(
numTOCEntries(0),
),
@@ -1224,26 +1234,29 @@ func testWriteAndOpen(t *testing.T, controllers ...TestingController) {
{
name: "block_char_fifo",
in: tarOf(
- tarEntryFunc(func(w *tar.Writer, prefix string) error {
+ tarEntryFunc(func(w *tar.Writer, prefix string, format tar.Format) error {
return w.WriteHeader(&tar.Header{
Name: prefix + "b",
Typeflag: tar.TypeBlock,
Devmajor: 123,
Devminor: 456,
+ Format: format,
})
}),
- tarEntryFunc(func(w *tar.Writer, prefix string) error {
+ tarEntryFunc(func(w *tar.Writer, prefix string, format tar.Format) error {
return w.WriteHeader(&tar.Header{
Name: prefix + "c",
Typeflag: tar.TypeChar,
Devmajor: 111,
Devminor: 222,
+ Format: format,
})
}),
- tarEntryFunc(func(w *tar.Writer, prefix string) error {
+ tarEntryFunc(func(w *tar.Writer, prefix string, format tar.Format) error {
return w.WriteHeader(&tar.Header{
Name: prefix + "f",
Typeflag: tar.TypeFifo,
+ Format: format,
})
}),
),
@@ -1278,6 +1291,29 @@ func testWriteAndOpen(t *testing.T, controllers ...TestingController) {
hasMode("foo3/bar5", os.FileMode(0755)),
),
},
+ {
+ name: "lossy",
+ in: tarOf(
+ dir("bar/", sampleOwner),
+ dir("foo/", sampleOwner),
+ file("foo/bar.txt", content, sampleOwner),
+ file(TOCTarName, "dummy"), // ignored by the writer. (lossless write returns error)
+ ),
+ wantNumGz: 4, // both dirs, foo.txt alone, TOC, footer
+ want: checks(
+ numTOCEntries(3),
+ hasDir("bar/"),
+ hasDir("foo/"),
+ hasFileLen("foo/bar.txt", len(content)),
+ entryHasChildren("", "bar", "foo"),
+ entryHasChildren("foo", "bar.txt"),
+ hasChunkEntries("foo/bar.txt", 1),
+ hasEntryOwner("bar/", sampleOwner),
+ hasEntryOwner("foo/", sampleOwner),
+ hasEntryOwner("foo/bar.txt", sampleOwner),
+ ),
+ wantFailOnLossLess: true,
+ },
}
for _, tt := range tests {
@@ -1285,47 +1321,90 @@ func testWriteAndOpen(t *testing.T, controllers ...TestingController) {
cl := cl
for _, prefix := range allowedPrefix {
prefix := prefix
- t.Run(tt.name+"-"+fmt.Sprintf("compression=%v-prefix=%q", cl, prefix), func(t *testing.T) {
- tr, cancel := buildTar(t, tt.in, prefix)
- defer cancel()
- var stargzBuf bytes.Buffer
- w := NewWriterWithCompressor(&stargzBuf, cl)
- w.ChunkSize = tt.chunkSize
- if err := w.AppendTar(tr); err != nil {
- t.Fatalf("Append: %v", err)
- }
- if _, err := w.Close(); err != nil {
- t.Fatalf("Writer.Close: %v", err)
- }
- b := stargzBuf.Bytes()
+ for _, srcTarFormat := range []tar.Format{tar.FormatUSTAR, tar.FormatPAX, tar.FormatGNU} {
+ srcTarFormat := srcTarFormat
+ for _, lossless := range []bool{true, false} {
+ t.Run(tt.name+"-"+fmt.Sprintf("compression=%v,prefix=%q,lossless=%v,format=%s", cl, prefix, lossless, srcTarFormat), func(t *testing.T) {
+ var tr io.Reader = buildTar(t, tt.in, prefix, srcTarFormat)
+ origTarDgstr := digest.Canonical.Digester()
+ tr = io.TeeReader(tr, origTarDgstr.Hash())
+ var stargzBuf bytes.Buffer
+ w := NewWriterWithCompressor(&stargzBuf, cl)
+ w.ChunkSize = tt.chunkSize
+ if lossless {
+ err := w.AppendTarLossLess(tr)
+ if tt.wantFailOnLossLess {
+ if err != nil {
+ return // expected to fail
+ }
+ t.Fatalf("Append wanted to fail on lossless")
+ }
+ if err != nil {
+ t.Fatalf("Append(lossless): %v", err)
+ }
+ } else {
+ if err := w.AppendTar(tr); err != nil {
+ t.Fatalf("Append: %v", err)
+ }
+ }
+ if _, err := w.Close(); err != nil {
+ t.Fatalf("Writer.Close: %v", err)
+ }
+ b := stargzBuf.Bytes()
+
+ if lossless {
+ // Check if the result blob reserves original tar metadata
+ rc, err := Unpack(io.NewSectionReader(bytes.NewReader(b), 0, int64(len(b))), cl)
+ if err != nil {
+ t.Errorf("failed to decompress blob: %v", err)
+ return
+ }
+ defer rc.Close()
+ resultDgstr := digest.Canonical.Digester()
+ if _, err := io.Copy(resultDgstr.Hash(), rc); err != nil {
+ t.Errorf("failed to read result decompressed blob: %v", err)
+ return
+ }
+ if resultDgstr.Digest() != origTarDgstr.Digest() {
+ t.Errorf("lossy compression occurred: digest=%v; want %v",
+ resultDgstr.Digest(), origTarDgstr.Digest())
+ return
+ }
+ }
- diffID := w.DiffID()
- wantDiffID := cl.DiffIDOf(t, b)
- if diffID != wantDiffID {
- t.Errorf("DiffID = %q; want %q", diffID, wantDiffID)
- }
+ diffID := w.DiffID()
+ wantDiffID := cl.DiffIDOf(t, b)
+ if diffID != wantDiffID {
+ t.Errorf("DiffID = %q; want %q", diffID, wantDiffID)
+ }
- got := cl.CountStreams(t, b)
- if got != tt.wantNumGz {
- t.Errorf("number of streams = %d; want %d", got, tt.wantNumGz)
- }
+ got := cl.CountStreams(t, b)
+ wantNumGz := tt.wantNumGz
+ if lossless && tt.wantNumGzLossLess > 0 {
+ wantNumGz = tt.wantNumGzLossLess
+ }
+ if got != wantNumGz {
+ t.Errorf("number of streams = %d; want %d", got, wantNumGz)
+ }
- telemetry, checkCalled := newCalledTelemetry()
- r, err := Open(
- io.NewSectionReader(bytes.NewReader(b), 0, int64(len(b))),
- WithDecompressors(cl),
- WithTelemetry(telemetry),
- )
- if err != nil {
- t.Fatalf("stargz.Open: %v", err)
- }
- if err := checkCalled(); err != nil {
- t.Errorf("telemetry failure: %v", err)
- }
- for _, want := range tt.want {
- want.check(t, r)
+ telemetry, checkCalled := newCalledTelemetry()
+ r, err := Open(
+ io.NewSectionReader(bytes.NewReader(b), 0, int64(len(b))),
+ WithDecompressors(cl),
+ WithTelemetry(telemetry),
+ )
+ if err != nil {
+ t.Fatalf("stargz.Open: %v", err)
+ }
+ if err := checkCalled(); err != nil {
+ t.Errorf("telemetry failure: %v", err)
+ }
+ for _, want := range tt.want {
+ want.check(t, r)
+ }
+ })
}
- })
+ }
}
}
}
@@ -1655,49 +1734,41 @@ func hasEntryOwner(entry string, owner owner) stargzCheck {
func tarOf(s ...tarEntry) []tarEntry { return s }
type tarEntry interface {
- appendTar(tw *tar.Writer, prefix string) error
+ appendTar(tw *tar.Writer, prefix string, format tar.Format) error
}
-type tarEntryFunc func(*tar.Writer, string) error
-
-func (f tarEntryFunc) appendTar(tw *tar.Writer, prefix string) error { return f(tw, prefix) }
+type tarEntryFunc func(*tar.Writer, string, tar.Format) error
-func buildTar(t *testing.T, ents []tarEntry, prefix string) (r io.Reader, cancel func()) {
- pr, pw := io.Pipe()
- go func() {
- tw := tar.NewWriter(pw)
- for _, ent := range ents {
- if err := ent.appendTar(tw, prefix); err != nil {
- t.Errorf("building input tar: %v", err)
- pw.Close()
- return
- }
- }
- if err := tw.Close(); err != nil {
- t.Errorf("closing write of input tar: %v", err)
- }
- pw.Close()
- }()
- return pr, func() { go pr.Close(); go pw.Close() }
+func (f tarEntryFunc) appendTar(tw *tar.Writer, prefix string, format tar.Format) error {
+ return f(tw, prefix, format)
}
-func buildTarStatic(t *testing.T, ents []tarEntry, prefix string) *io.SectionReader {
+func buildTar(t *testing.T, ents []tarEntry, prefix string, opts ...interface{}) *io.SectionReader {
+ format := tar.FormatUnknown
+ for _, opt := range opts {
+ switch v := opt.(type) {
+ case tar.Format:
+ format = v
+ default:
+ panic(fmt.Errorf("unsupported opt for buildTar: %v", opt))
+ }
+ }
buf := new(bytes.Buffer)
tw := tar.NewWriter(buf)
for _, ent := range ents {
- if err := ent.appendTar(tw, prefix); err != nil {
+ if err := ent.appendTar(tw, prefix, format); err != nil {
t.Fatalf("building input tar: %v", err)
}
}
if err := tw.Close(); err != nil {
t.Errorf("closing write of input tar: %v", err)
}
- data := buf.Bytes()
+ data := append(buf.Bytes(), make([]byte, 100)...) // append empty bytes at the tail to see lossless works
return io.NewSectionReader(bytes.NewReader(data), 0, int64(len(data)))
}
func dir(name string, opts ...interface{}) tarEntry {
- return tarEntryFunc(func(tw *tar.Writer, prefix string) error {
+ return tarEntryFunc(func(tw *tar.Writer, prefix string, format tar.Format) error {
var o owner
mode := os.FileMode(0755)
for _, opt := range opts {
@@ -1723,6 +1794,7 @@ func dir(name string, opts ...interface{}) tarEntry {
Mode: tm,
Uid: o.uid,
Gid: o.gid,
+ Format: format,
})
})
}
@@ -1737,7 +1809,7 @@ type owner struct {
}
func file(name, contents string, opts ...interface{}) tarEntry {
- return tarEntryFunc(func(tw *tar.Writer, prefix string) error {
+ return tarEntryFunc(func(tw *tar.Writer, prefix string, format tar.Format) error {
var xattrs xAttr
var o owner
mode := os.FileMode(0644)
@@ -1760,6 +1832,9 @@ func file(name, contents string, opts ...interface{}) tarEntry {
if err != nil {
return err
}
+ if len(xattrs) > 0 {
+ format = tar.FormatPAX // only PAX supports xattrs
+ }
if err := tw.WriteHeader(&tar.Header{
Typeflag: tar.TypeReg,
Name: prefix + name,
@@ -1768,6 +1843,7 @@ func file(name, contents string, opts ...interface{}) tarEntry {
Size: int64(len(contents)),
Uid: o.uid,
Gid: o.gid,
+ Format: format,
}); err != nil {
return err
}
@@ -1777,78 +1853,76 @@ func file(name, contents string, opts ...interface{}) tarEntry {
}
func symlink(name, target string) tarEntry {
- return tarEntryFunc(func(tw *tar.Writer, prefix string) error {
+ return tarEntryFunc(func(tw *tar.Writer, prefix string, format tar.Format) error {
return tw.WriteHeader(&tar.Header{
Typeflag: tar.TypeSymlink,
Name: prefix + name,
Linkname: target,
Mode: 0644,
+ Format: format,
})
})
}
func link(name string, linkname string) tarEntry {
now := time.Now()
- return tarEntryFunc(func(w *tar.Writer, prefix string) error {
+ return tarEntryFunc(func(w *tar.Writer, prefix string, format tar.Format) error {
return w.WriteHeader(&tar.Header{
- Typeflag: tar.TypeLink,
- Name: prefix + name,
- Linkname: linkname,
- ModTime: now,
- AccessTime: now,
- ChangeTime: now,
+ Typeflag: tar.TypeLink,
+ Name: prefix + name,
+ Linkname: linkname,
+ ModTime: now,
+ Format: format,
})
})
}
func chardev(name string, major, minor int64) tarEntry {
now := time.Now()
- return tarEntryFunc(func(w *tar.Writer, prefix string) error {
+ return tarEntryFunc(func(w *tar.Writer, prefix string, format tar.Format) error {
return w.WriteHeader(&tar.Header{
- Typeflag: tar.TypeChar,
- Name: prefix + name,
- Devmajor: major,
- Devminor: minor,
- ModTime: now,
- AccessTime: now,
- ChangeTime: now,
+ Typeflag: tar.TypeChar,
+ Name: prefix + name,
+ Devmajor: major,
+ Devminor: minor,
+ ModTime: now,
+ Format: format,
})
})
}
func blockdev(name string, major, minor int64) tarEntry {
now := time.Now()
- return tarEntryFunc(func(w *tar.Writer, prefix string) error {
+ return tarEntryFunc(func(w *tar.Writer, prefix string, format tar.Format) error {
return w.WriteHeader(&tar.Header{
- Typeflag: tar.TypeBlock,
- Name: prefix + name,
- Devmajor: major,
- Devminor: minor,
- ModTime: now,
- AccessTime: now,
- ChangeTime: now,
+ Typeflag: tar.TypeBlock,
+ Name: prefix + name,
+ Devmajor: major,
+ Devminor: minor,
+ ModTime: now,
+ Format: format,
})
})
}
func fifo(name string) tarEntry {
now := time.Now()
- return tarEntryFunc(func(w *tar.Writer, prefix string) error {
+ return tarEntryFunc(func(w *tar.Writer, prefix string, format tar.Format) error {
return w.WriteHeader(&tar.Header{
- Typeflag: tar.TypeFifo,
- Name: prefix + name,
- ModTime: now,
- AccessTime: now,
- ChangeTime: now,
+ Typeflag: tar.TypeFifo,
+ Name: prefix + name,
+ ModTime: now,
+ Format: format,
})
})
}
func prefetchLandmark() tarEntry {
- return tarEntryFunc(func(w *tar.Writer, prefix string) error {
+ return tarEntryFunc(func(w *tar.Writer, prefix string, format tar.Format) error {
if err := w.WriteHeader(&tar.Header{
Name: PrefetchLandmark,
Typeflag: tar.TypeReg,
Size: int64(len([]byte{landmarkContents})),
+ Format: format,
}); err != nil {
return err
}
@@ -1861,11 +1935,12 @@ func prefetchLandmark() tarEntry {
}
func noPrefetchLandmark() tarEntry {
- return tarEntryFunc(func(w *tar.Writer, prefix string) error {
+ return tarEntryFunc(func(w *tar.Writer, prefix string, format tar.Format) error {
if err := w.WriteHeader(&tar.Header{
Name: NoPrefetchLandmark,
Typeflag: tar.TypeReg,
Size: int64(len([]byte{landmarkContents})),
+ Format: format,
}); err != nil {
return err
}
@@ -1899,11 +1974,12 @@ func regDigest(t *testing.T, name string, contentStr string, digestMap map[strin
n += size
}
- return tarEntryFunc(func(w *tar.Writer, prefix string) error {
+ return tarEntryFunc(func(w *tar.Writer, prefix string, format tar.Format) error {
if err := w.WriteHeader(&tar.Header{
Typeflag: tar.TypeReg,
Name: prefix + name,
Size: int64(len(content)),
+ Format: format,
}); err != nil {
return err
}
diff --git a/vendor/github.com/containerd/stargz-snapshotter/estargz/types.go b/vendor/github.com/containerd/stargz-snapshotter/estargz/types.go
index 1b1075a64..384ff7fd7 100644
--- a/vendor/github.com/containerd/stargz-snapshotter/estargz/types.go
+++ b/vendor/github.com/containerd/stargz-snapshotter/estargz/types.go
@@ -290,7 +290,7 @@ type Compressor interface {
WriteTOCAndFooter(w io.Writer, off int64, toc *JTOC, diffHash hash.Hash) (tocDgst digest.Digest, err error)
}
-// Deompressor represents the helper mothods to be used for parsing eStargz.
+// Decompressor represents the helper mothods to be used for parsing eStargz.
type Decompressor interface {
// Reader returns ReadCloser to be used for decompressing file payload.
Reader(r io.Reader) (io.ReadCloser, error)
@@ -299,10 +299,12 @@ type Decompressor interface {
FooterSize() int64
// ParseFooter parses the footer and returns the offset and (compressed) size of TOC.
+ // payloadBlobSize is the (compressed) size of the blob payload (i.e. the size between
+ // the top until the TOC JSON).
//
// Here, tocSize is optional. If tocSize <= 0, it's by default the size of the range
// from tocOffset until the beginning of the footer (blob size - tocOff - FooterSize).
- ParseFooter(p []byte) (tocOffset, tocSize int64, err error)
+ ParseFooter(p []byte) (blobPayloadSize, tocOffset, tocSize int64, err error)
// ParseTOC parses TOC from the passed reader. The reader provides the partial contents
// of the underlying blob that has the range specified by ParseFooter method.
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 80701a761..56c39c141 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
@@ -16,11 +16,10 @@ import (
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/internal/blobinfocache"
- "github.com/containers/image/v5/internal/iolimits"
"github.com/containers/image/v5/internal/putblobdigest"
+ "github.com/containers/image/v5/internal/streamdigest"
"github.com/containers/image/v5/internal/uploadreader"
"github.com/containers/image/v5/manifest"
- "github.com/containers/image/v5/pkg/blobinfocache/none"
"github.com/containers/image/v5/types"
"github.com/docker/distribution/registry/api/errcode"
v2 "github.com/docker/distribution/registry/api/v2"
@@ -132,11 +131,23 @@ func (d *dockerImageDestination) 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 *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader, inputInfo types.BlobInfo, cache types.BlobInfoCache, isConfig bool) (types.BlobInfo, error) {
+ // If requested, precompute the blob digest to prevent uploading layers that already exist on the registry.
+ // This functionality is particularly useful when BlobInfoCache has not been populated with compressed digests,
+ // the source blob is uncompressed, and the destination blob is being compressed "on the fly".
+ if inputInfo.Digest == "" && d.c.sys.DockerRegistryPushPrecomputeDigests {
+ logrus.Debugf("Precomputing digest layer for %s", reference.Path(d.ref.ref))
+ streamCopy, cleanup, err := streamdigest.ComputeBlobInfo(d.c.sys, stream, &inputInfo)
+ if err != nil {
+ return types.BlobInfo{}, err
+ }
+ defer cleanup()
+ stream = streamCopy
+ }
+
if inputInfo.Digest != "" {
// This should not really be necessary, at least the copy code calls TryReusingBlob automatically.
// Still, we need to check, if only because the "initiate upload" endpoint does not have a documented "blob already exists" return value.
- // But we do that with NoCache, so that it _only_ checks the primary destination, instead of trying all mount candidates _again_.
- haveBlob, reusedInfo, err := d.TryReusingBlob(ctx, inputInfo, none.NoCache, false)
+ haveBlob, reusedInfo, err := d.tryReusingExactBlob(ctx, inputInfo, cache)
if err != nil {
return types.BlobInfo{}, err
}
@@ -283,6 +294,21 @@ func (d *dockerImageDestination) mountBlob(ctx context.Context, srcRepo referenc
}
}
+// tryReusingExactBlob is a subset of TryReusingBlob which _only_ looks for exactly the specified
+// blob in the current repository, with no cross-repo reuse or mounting; cache may be updated, it is not read.
+// The caller must ensure info.Digest is set.
+func (d *dockerImageDestination) tryReusingExactBlob(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache) (bool, types.BlobInfo, error) {
+ exists, size, err := d.blobExists(ctx, d.ref.ref, info.Digest, nil)
+ if err != nil {
+ return false, types.BlobInfo{}, err
+ }
+ if exists {
+ cache.RecordKnownLocation(d.ref.Transport(), bicTransportScope(d.ref), info.Digest, newBICLocationReference(d.ref))
+ return true, types.BlobInfo{Digest: info.Digest, MediaType: info.MediaType, Size: size}, nil
+ }
+ return false, types.BlobInfo{}, 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.
@@ -298,13 +324,12 @@ func (d *dockerImageDestination) TryReusingBlob(ctx context.Context, info types.
}
// First, check whether the blob happens to already exist at the destination.
- exists, size, err := d.blobExists(ctx, d.ref.ref, info.Digest, nil)
+ haveBlob, reusedInfo, err := d.tryReusingExactBlob(ctx, info, cache)
if err != nil {
return false, types.BlobInfo{}, err
}
- if exists {
- cache.RecordKnownLocation(d.ref.Transport(), bicTransportScope(d.ref), info.Digest, newBICLocationReference(d.ref))
- return true, types.BlobInfo{Digest: info.Digest, MediaType: info.MediaType, Size: size}, nil
+ if haveBlob {
+ return true, reusedInfo, nil
}
// Then try reusing blobs from other locations.
@@ -432,8 +457,9 @@ func (d *dockerImageDestination) PutManifest(ctx context.Context, m []byte, inst
}
defer res.Body.Close()
if !successStatus(res.StatusCode) {
- err = errors.Wrapf(registryHTTPResponseToError(res), "uploading manifest %s to %s", refTail, d.ref.ref.Name())
- if isManifestInvalidError(errors.Cause(err)) {
+ rawErr := registryHTTPResponseToError(res)
+ err := errors.Wrapf(rawErr, "uploading manifest %s to %s", refTail, d.ref.ref.Name())
+ if isManifestInvalidError(rawErr) {
err = types.ManifestTypeRejectedError{Err: err}
}
return err
@@ -648,10 +674,6 @@ sigExists:
}
defer res.Body.Close()
if res.StatusCode != http.StatusCreated {
- body, err := iolimits.ReadAtMost(res.Body, iolimits.MaxErrorBodySize)
- if err == nil {
- logrus.Debugf("Error body %s", string(body))
- }
logrus.Debugf("Error uploading signature, status %d, %#v", res.StatusCode, res)
return errors.Wrapf(registryHTTPResponseToError(res), "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 1333cf9e2..314e9b394 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
@@ -236,6 +236,9 @@ func (s *dockerImageSource) ensureManifestIsLoaded(ctx context.Context) error {
return nil
}
+// getExternalBlob returns the reader of the first available blob URL from urls, which must not be empty.
+// This function can return nil reader when no url is supported by this function. In this case, the caller
+// should fallback to fetch the non-external blob (i.e. pull from the registry).
func (s *dockerImageSource) getExternalBlob(ctx context.Context, urls []string) (io.ReadCloser, int64, error) {
var (
resp *http.Response
@@ -244,14 +247,17 @@ func (s *dockerImageSource) getExternalBlob(ctx context.Context, urls []string)
if len(urls) == 0 {
return nil, 0, errors.New("internal error: getExternalBlob called with no URLs")
}
- for _, url := range urls {
+ for _, u := range urls {
+ if u, err := url.Parse(u); err != nil || (u.Scheme != "http" && u.Scheme != "https") {
+ continue // unsupported url. skip this url.
+ }
// NOTE: we must not authenticate on additional URLs as those
// can be abused to leak credentials or tokens. Please
// refer to CVE-2020-15157 for more information.
- resp, err = s.c.makeRequestToResolvedURL(ctx, http.MethodGet, url, nil, nil, -1, noAuth, nil)
+ resp, err = s.c.makeRequestToResolvedURL(ctx, http.MethodGet, u, nil, nil, -1, noAuth, nil)
if err == nil {
if resp.StatusCode != http.StatusOK {
- err = errors.Errorf("error fetching external blob from %q: %d (%s)", url, resp.StatusCode, http.StatusText(resp.StatusCode))
+ err = errors.Errorf("error fetching external blob from %q: %d (%s)", u, resp.StatusCode, http.StatusText(resp.StatusCode))
logrus.Debug(err)
resp.Body.Close()
continue
@@ -259,6 +265,9 @@ func (s *dockerImageSource) getExternalBlob(ctx context.Context, urls []string)
break
}
}
+ if resp == nil && err == nil {
+ return nil, 0, nil // fallback to non-external blob
+ }
if err != nil {
return nil, 0, err
}
@@ -370,12 +379,6 @@ func (s *dockerImageSource) GetBlobAt(ctx context.Context, info types.BlobInfo,
if err != nil {
return nil, nil, err
}
- if err := httpResponseToError(res, "Error fetching partial blob"); err != nil {
- if res.Body != nil {
- res.Body.Close()
- }
- return nil, nil, err
- }
switch res.StatusCode {
case http.StatusOK:
@@ -396,9 +399,16 @@ func (s *dockerImageSource) GetBlobAt(ctx context.Context, info types.BlobInfo,
go handle206Response(streams, errs, res.Body, chunks, mediaType, params)
return streams, errs, nil
+ case http.StatusBadRequest:
+ res.Body.Close()
+ return nil, nil, internalTypes.BadPartialRequestError{Status: res.Status}
default:
+ err := httpResponseToError(res, "Error fetching partial blob")
+ if err == nil {
+ err = errors.Errorf("invalid status code returned when fetching blob %d (%s)", res.StatusCode, http.StatusText(res.StatusCode))
+ }
res.Body.Close()
- return nil, nil, errors.Errorf("invalid status code returned when fetching blob %d (%s)", res.StatusCode, http.StatusText(res.StatusCode))
+ return nil, nil, err
}
}
@@ -407,7 +417,12 @@ func (s *dockerImageSource) GetBlobAt(ctx context.Context, info types.BlobInfo,
// May update BlobInfoCache, preferably after it knows for certain that a blob truly exists at a specific location.
func (s *dockerImageSource) GetBlob(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache) (io.ReadCloser, int64, error) {
if len(info.URLs) != 0 {
- return s.getExternalBlob(ctx, info.URLs)
+ r, s, err := s.getExternalBlob(ctx, info.URLs)
+ if err != nil {
+ return nil, 0, err
+ } else if r != nil {
+ return r, s, nil
+ }
}
path := fmt.Sprintf(blobsPath, reference.Path(s.physicalRef.ref), info.Digest.String())
diff --git a/vendor/github.com/containers/image/v5/docker/errors.go b/vendor/github.com/containers/image/v5/docker/errors.go
index 6f2c5fde5..6f707db7d 100644
--- a/vendor/github.com/containers/image/v5/docker/errors.go
+++ b/vendor/github.com/containers/image/v5/docker/errors.go
@@ -5,7 +5,6 @@ import (
"fmt"
"net/http"
- internalTypes "github.com/containers/image/v5/internal/types"
"github.com/docker/distribution/registry/client"
perrors "github.com/pkg/errors"
)
@@ -29,19 +28,16 @@ func (e ErrUnauthorizedForCredentials) Error() string {
// httpResponseToError translates the https.Response into an error, possibly prefixing it with the supplied context. It returns
// nil if the response is not considered an error.
+// NOTE: Almost all callers in this package should use registryHTTPResponseToError instead.
func httpResponseToError(res *http.Response, context string) error {
switch res.StatusCode {
case http.StatusOK:
return nil
- case http.StatusPartialContent:
- return nil
case http.StatusTooManyRequests:
return ErrTooManyRequests
case http.StatusUnauthorized:
err := client.HandleErrorResponse(res)
return ErrUnauthorizedForCredentials{Err: err}
- case http.StatusBadRequest:
- return internalTypes.BadPartialRequestError{Status: res.Status}
default:
if context != "" {
context = context + ": "
@@ -53,13 +49,13 @@ func httpResponseToError(res *http.Response, context string) error {
// 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 {
+ err := client.HandleErrorResponse(res)
+ if e, ok := err.(*client.UnexpectedHTTPResponseError); ok {
response := string(e.Response)
if len(response) > 50 {
response = response[:50] + "..."
}
- errResponse = fmt.Errorf("StatusCode: %d, %s", e.StatusCode, response)
+ err = fmt.Errorf("StatusCode: %d, %s", e.StatusCode, response)
}
- return errResponse
+ return err
}
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
index 44b0af110..7e1580990 100644
--- a/vendor/github.com/containers/image/v5/docker/internal/tarfile/dest.go
+++ b/vendor/github.com/containers/image/v5/docker/internal/tarfile/dest.go
@@ -5,13 +5,10 @@ import (
"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/putblobdigest"
- "github.com/containers/image/v5/internal/tmpdir"
+ "github.com/containers/image/v5/internal/streamdigest"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/types"
"github.com/opencontainers/go-digest"
@@ -98,25 +95,11 @@ func (d *Destination) PutBlob(ctx context.Context, stream io.Reader, inputInfo t
// When the layer is decompressed, we also have to generate the digest on uncompressed data.
if inputInfo.Size == -1 || inputInfo.Digest == "" {
logrus.Debugf("docker tarfile: input with unknown size, streaming to disk first ...")
- streamCopy, err := ioutil.TempFile(tmpdir.TemporaryDirectoryForBigFiles(d.sysCtx), "docker-tarfile-blob")
+ streamCopy, cleanup, err := streamdigest.ComputeBlobInfo(d.sysCtx, stream, &inputInfo)
if err != nil {
return types.BlobInfo{}, err
}
- defer os.Remove(streamCopy.Name())
- defer streamCopy.Close()
-
- digester, stream2 := putblobdigest.DigestIfUnknown(stream, inputInfo)
- // TODO: This can take quite some time, and should ideally be cancellable using ctx.Done().
- size, err := io.Copy(streamCopy, stream2)
- 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.
- inputInfo.Digest = digester.Digest()
+ defer cleanup()
stream = streamCopy
logrus.Debugf("... streaming done")
}
diff --git a/vendor/github.com/containers/image/v5/internal/streamdigest/stream_digest.go b/vendor/github.com/containers/image/v5/internal/streamdigest/stream_digest.go
new file mode 100644
index 000000000..306220585
--- /dev/null
+++ b/vendor/github.com/containers/image/v5/internal/streamdigest/stream_digest.go
@@ -0,0 +1,41 @@
+package streamdigest
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+
+ "github.com/containers/image/v5/internal/putblobdigest"
+ "github.com/containers/image/v5/internal/tmpdir"
+ "github.com/containers/image/v5/types"
+)
+
+// ComputeBlobInfo streams a blob to a temporary file and populates Digest and Size in inputInfo.
+// The temporary file is returned as an io.Reader along with a cleanup function.
+// It is the caller's responsibility to call the cleanup function, which closes and removes the temporary file.
+// If an error occurs, inputInfo is not modified.
+func ComputeBlobInfo(sys *types.SystemContext, stream io.Reader, inputInfo *types.BlobInfo) (io.Reader, func(), error) {
+ diskBlob, err := ioutil.TempFile(tmpdir.TemporaryDirectoryForBigFiles(sys), "stream-blob")
+ if err != nil {
+ return nil, nil, fmt.Errorf("creating temporary on-disk layer: %w", err)
+ }
+ cleanup := func() {
+ diskBlob.Close()
+ os.Remove(diskBlob.Name())
+ }
+ digester, stream := putblobdigest.DigestIfCanonicalUnknown(stream, *inputInfo)
+ written, err := io.Copy(diskBlob, stream)
+ if err != nil {
+ cleanup()
+ return nil, nil, fmt.Errorf("writing to temporary on-disk layer: %w", err)
+ }
+ _, err = diskBlob.Seek(0, io.SeekStart)
+ if err != nil {
+ cleanup()
+ return nil, nil, fmt.Errorf("rewinding temporary on-disk layer: %w", err)
+ }
+ inputInfo.Digest = digester.Digest()
+ inputInfo.Size = written
+ return diskBlob, cleanup, nil
+}
diff --git a/vendor/github.com/containers/image/v5/manifest/common.go b/vendor/github.com/containers/image/v5/manifest/common.go
index 4692211c0..511cdcc37 100644
--- a/vendor/github.com/containers/image/v5/manifest/common.go
+++ b/vendor/github.com/containers/image/v5/manifest/common.go
@@ -1,6 +1,7 @@
package manifest
import (
+ "encoding/json"
"fmt"
compressiontypes "github.com/containers/image/v5/pkg/compression/types"
@@ -32,6 +33,72 @@ func dupStringStringMap(m map[string]string) map[string]string {
return result
}
+// allowedManifestFields is a bit mask of “essential” manifest fields that validateUnambiguousManifestFormat
+// can expect to be present.
+type allowedManifestFields int
+
+const (
+ allowedFieldConfig allowedManifestFields = 1 << iota
+ allowedFieldFSLayers
+ allowedFieldHistory
+ allowedFieldLayers
+ allowedFieldManifests
+ allowedFieldFirstUnusedBit // Keep this at the end!
+)
+
+// validateUnambiguousManifestFormat rejects manifests (incl. multi-arch) that look like more than
+// one kind we currently recognize, i.e. if they contain any of the known “essential” format fields
+// other than the ones the caller specifically allows.
+// expectedMIMEType is used only for diagnostics.
+// NOTE: The caller should do the non-heuristic validations (e.g. check for any specified format
+// identification/version, or other “magic numbers”) before calling this, to cleanly reject unambigous
+// data that just isn’t what was expected, as opposed to actually ambiguous data.
+func validateUnambiguousManifestFormat(manifest []byte, expectedMIMEType string,
+ allowed allowedManifestFields) error {
+ if allowed >= allowedFieldFirstUnusedBit {
+ return fmt.Errorf("internal error: invalid allowedManifestFields value %#v", allowed)
+ }
+ // Use a private type to decode, not just a map[string]interface{}, because we want
+ // to also reject case-insensitive matches (which would be used by Go when really decoding
+ // the manifest).
+ // (It is expected that as manifest formats are added or extended over time, more fields will be added
+ // here.)
+ detectedFields := struct {
+ Config interface{} `json:"config"`
+ FSLayers interface{} `json:"fsLayers"`
+ History interface{} `json:"history"`
+ Layers interface{} `json:"layers"`
+ Manifests interface{} `json:"manifests"`
+ }{}
+ if err := json.Unmarshal(manifest, &detectedFields); err != nil {
+ // The caller was supposed to already validate version numbers, so this shold not happen;
+ // let’s not bother with making this error “nice”.
+ return err
+ }
+ unexpected := []string{}
+ // Sadly this isn’t easy to automate in Go, without reflection. So, copy&paste.
+ if detectedFields.Config != nil && (allowed&allowedFieldConfig) == 0 {
+ unexpected = append(unexpected, "config")
+ }
+ if detectedFields.FSLayers != nil && (allowed&allowedFieldFSLayers) == 0 {
+ unexpected = append(unexpected, "fsLayers")
+ }
+ if detectedFields.History != nil && (allowed&allowedFieldHistory) == 0 {
+ unexpected = append(unexpected, "history")
+ }
+ if detectedFields.Layers != nil && (allowed&allowedFieldLayers) == 0 {
+ unexpected = append(unexpected, "layers")
+ }
+ if detectedFields.Manifests != nil && (allowed&allowedFieldManifests) == 0 {
+ unexpected = append(unexpected, "manifests")
+ }
+ if len(unexpected) != 0 {
+ return fmt.Errorf(`rejecting ambiguous manifest, unexpected fields %#v in supposedly %s`,
+ unexpected, expectedMIMEType)
+ }
+ return nil
+}
+
// layerInfosToStrings converts a list of layer infos, presumably obtained from a Manifest.LayerInfos()
// method call, into a format suitable for inclusion in a types.ImageInspectInfo structure.
func layerInfosToStrings(infos []LayerInfo) []string {
diff --git a/vendor/github.com/containers/image/v5/manifest/docker_schema1.go b/vendor/github.com/containers/image/v5/manifest/docker_schema1.go
index 8679cad11..6d12c4cec 100644
--- a/vendor/github.com/containers/image/v5/manifest/docker_schema1.go
+++ b/vendor/github.com/containers/image/v5/manifest/docker_schema1.go
@@ -60,6 +60,10 @@ func Schema1FromManifest(manifest []byte) (*Schema1, error) {
if s1.SchemaVersion != 1 {
return nil, errors.Errorf("unsupported schema version %d", s1.SchemaVersion)
}
+ if err := validateUnambiguousManifestFormat(manifest, DockerV2Schema1SignedMediaType,
+ allowedFieldFSLayers|allowedFieldHistory); err != nil {
+ return nil, err
+ }
if err := s1.initialize(); err != nil {
return nil, err
}
diff --git a/vendor/github.com/containers/image/v5/manifest/docker_schema2.go b/vendor/github.com/containers/image/v5/manifest/docker_schema2.go
index 2711ca5eb..1f4db54ee 100644
--- a/vendor/github.com/containers/image/v5/manifest/docker_schema2.go
+++ b/vendor/github.com/containers/image/v5/manifest/docker_schema2.go
@@ -165,6 +165,10 @@ func Schema2FromManifest(manifest []byte) (*Schema2, error) {
if err := json.Unmarshal(manifest, &s2); err != nil {
return nil, err
}
+ if err := validateUnambiguousManifestFormat(manifest, DockerV2Schema2MediaType,
+ allowedFieldConfig|allowedFieldLayers); err != nil {
+ return nil, err
+ }
// Check manifest's and layers' media types.
if err := SupportedSchema2MediaType(s2.MediaType); err != nil {
return nil, err
diff --git a/vendor/github.com/containers/image/v5/manifest/docker_schema2_list.go b/vendor/github.com/containers/image/v5/manifest/docker_schema2_list.go
index 9ebb8d6b9..e97dfbd88 100644
--- a/vendor/github.com/containers/image/v5/manifest/docker_schema2_list.go
+++ b/vendor/github.com/containers/image/v5/manifest/docker_schema2_list.go
@@ -192,6 +192,10 @@ func Schema2ListFromManifest(manifest []byte) (*Schema2List, error) {
if err := json.Unmarshal(manifest, &list); err != nil {
return nil, errors.Wrapf(err, "unmarshaling Schema2List %q", string(manifest))
}
+ if err := validateUnambiguousManifestFormat(manifest, DockerV2ListMediaType,
+ allowedFieldManifests); err != nil {
+ return nil, err
+ }
return &list, nil
}
diff --git a/vendor/github.com/containers/image/v5/manifest/oci.go b/vendor/github.com/containers/image/v5/manifest/oci.go
index 29a479c94..c4616b965 100644
--- a/vendor/github.com/containers/image/v5/manifest/oci.go
+++ b/vendor/github.com/containers/image/v5/manifest/oci.go
@@ -54,6 +54,10 @@ func OCI1FromManifest(manifest []byte) (*OCI1, error) {
if err := json.Unmarshal(manifest, &oci1); err != nil {
return nil, err
}
+ if err := validateUnambiguousManifestFormat(manifest, imgspecv1.MediaTypeImageIndex,
+ allowedFieldConfig|allowedFieldLayers); err != nil {
+ return nil, err
+ }
return &oci1, nil
}
diff --git a/vendor/github.com/containers/image/v5/manifest/oci_index.go b/vendor/github.com/containers/image/v5/manifest/oci_index.go
index 5b4111e4e..5bec43ff9 100644
--- a/vendor/github.com/containers/image/v5/manifest/oci_index.go
+++ b/vendor/github.com/containers/image/v5/manifest/oci_index.go
@@ -202,6 +202,10 @@ func OCI1IndexFromManifest(manifest []byte) (*OCI1Index, error) {
if err := json.Unmarshal(manifest, &index); err != nil {
return nil, errors.Wrapf(err, "unmarshaling OCI1Index %q", string(manifest))
}
+ if err := validateUnambiguousManifestFormat(manifest, imgspecv1.MediaTypeImageIndex,
+ allowedFieldManifests); err != nil {
+ return nil, err
+ }
return &index, nil
}
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 55d3f637a..9d8ab689b 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
@@ -5,6 +5,7 @@ import (
"io"
"io/ioutil"
"net/http"
+ "net/url"
"os"
"strconv"
@@ -113,7 +114,12 @@ func (s *ociImageSource) HasThreadSafeGetBlob() bool {
// May update BlobInfoCache, preferably after it knows for certain that a blob truly exists at a specific location.
func (s *ociImageSource) GetBlob(ctx context.Context, info types.BlobInfo, cache types.BlobInfoCache) (io.ReadCloser, int64, error) {
if len(info.URLs) != 0 {
- return s.getExternalBlob(ctx, info.URLs)
+ r, s, err := s.getExternalBlob(ctx, info.URLs)
+ if err != nil {
+ return nil, 0, err
+ } else if r != nil {
+ return r, s, nil
+ }
}
path, err := s.ref.blobPath(info.Digest, s.sharedBlobDir)
@@ -140,34 +146,44 @@ func (s *ociImageSource) GetSignatures(ctx context.Context, instanceDigest *dige
return [][]byte{}, nil
}
+// getExternalBlob returns the reader of the first available blob URL from urls, which must not be empty.
+// This function can return nil reader when no url is supported by this function. In this case, the caller
+// should fallback to fetch the non-external blob (i.e. pull from the registry).
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 {
-
- req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
+ hasSupportedURL := false
+ for _, u := range urls {
+ if u, err := url.Parse(u); err != nil || (u.Scheme != "http" && u.Scheme != "https") {
+ continue // unsupported url. skip this url.
+ }
+ hasSupportedURL = true
+ req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)
if err != nil {
- errWrap = errors.Wrapf(errWrap, "fetching %s failed %s", url, err.Error())
+ errWrap = errors.Wrapf(errWrap, "fetching %s failed %s", u, err.Error())
continue
}
resp, err := s.client.Do(req)
if err != nil {
- errWrap = errors.Wrapf(errWrap, "fetching %s failed %s", url, err.Error())
+ errWrap = errors.Wrapf(errWrap, "fetching %s failed %s", u, err.Error())
continue
}
if resp.StatusCode != http.StatusOK {
resp.Body.Close()
- errWrap = errors.Wrapf(errWrap, "fetching %s failed, response code not 200", url)
+ errWrap = errors.Wrapf(errWrap, "fetching %s failed, response code not 200", u)
continue
}
return resp.Body, getBlobSize(resp), nil
}
+ if !hasSupportedURL {
+ return nil, 0, nil // fallback to non-external blob
+ }
return nil, 0, errWrap
}
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 e37f4c19e..63f5bd53e 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
@@ -268,18 +268,18 @@ func getCredentialsWithHomeDir(sys *types.SystemContext, ref reference.Named, re
}
// Anonymous function to query credentials from auth files.
- getCredentialsFromAuthFiles := func() (types.DockerAuthConfig, error) {
+ getCredentialsFromAuthFiles := func() (types.DockerAuthConfig, string, error) {
for _, path := range getAuthFilePaths(sys, homeDir) {
authConfig, err := findAuthentication(ref, registry, path.path, path.legacyFormat)
if err != nil {
- return types.DockerAuthConfig{}, err
+ return types.DockerAuthConfig{}, "", err
}
if (authConfig.Username != "" && authConfig.Password != "") || authConfig.IdentityToken != "" {
- return authConfig, nil
+ return authConfig, path.path, nil
}
}
- return types.DockerAuthConfig{}, nil
+ return types.DockerAuthConfig{}, "", nil
}
helpers, err := sysregistriesv2.CredentialHelpers(sys)
@@ -289,12 +289,15 @@ func getCredentialsWithHomeDir(sys *types.SystemContext, ref reference.Named, re
var multiErr error
for _, helper := range helpers {
- var creds types.DockerAuthConfig
- var err error
+ var (
+ creds types.DockerAuthConfig
+ credHelperPath string
+ err error
+ )
switch helper {
// Special-case the built-in helper for auth files.
case sysregistriesv2.AuthenticationFileHelper:
- creds, err = getCredentialsFromAuthFiles()
+ creds, credHelperPath, err = getCredentialsFromAuthFiles()
// External helpers.
default:
creds, err = getAuthFromCredHelper(helper, registry)
@@ -307,7 +310,11 @@ func getCredentialsWithHomeDir(sys *types.SystemContext, ref reference.Named, re
if len(creds.Username)+len(creds.Password)+len(creds.IdentityToken) == 0 {
continue
}
- logrus.Debugf("Found credentials for %s in credential helper %s", registry, helper)
+ msg := fmt.Sprintf("Found credentials for %s in credential helper %s", registry, helper)
+ if credHelperPath != "" {
+ msg = fmt.Sprintf("%s in file %s", msg, credHelperPath)
+ }
+ logrus.Debug(msg)
return creds, nil
}
if multiErr != nil {
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 4c1629f56..c8a603c4e 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
@@ -80,7 +80,7 @@ func (e *Endpoint) rewriteReference(ref reference.Named, prefix string) (referen
// be dropped.
// https://github.com/containers/image/pull/1191#discussion_r610621608
if e.Location == "" {
- if prefix[:2] != "*." {
+ if !strings.HasPrefix(prefix, "*.") {
return nil, fmt.Errorf("invalid prefix '%v' for empty location, should be in the format: *.example.com", prefix)
}
return ref, nil
@@ -369,7 +369,7 @@ func (config *V2RegistriesConf) postProcessRegistries() error {
}
// FIXME: allow config authors to always use Prefix.
// https://github.com/containers/image/pull/1191#discussion_r610622495
- if reg.Prefix[:2] != "*." && reg.Location == "" {
+ if !strings.HasPrefix(reg.Prefix, "*.") && reg.Location == "" {
return &InvalidRegistries{s: "invalid condition: location is unset and prefix is not in the format: *.example.com"}
}
}
@@ -804,7 +804,7 @@ func refMatchingSubdomainPrefix(ref, prefix string) int {
// (This is split from the caller primarily to make testing easier.)
func refMatchingPrefix(ref, prefix string) int {
switch {
- case prefix[0:2] == "*.":
+ case strings.HasPrefix(prefix, "*."):
return refMatchingSubdomainPrefix(ref, prefix)
case len(ref) < len(prefix):
return -1
@@ -924,7 +924,7 @@ func loadConfigFile(path string, forceV2 bool) (*parsedConfig, error) {
// https://github.com/containers/image/pull/1191#discussion_r610623829
for i := range res.partialV2.Registries {
prefix := res.partialV2.Registries[i].Prefix
- if prefix[:2] == "*." && strings.ContainsAny(prefix, "/@:") {
+ if strings.HasPrefix(prefix, "*.") && strings.ContainsAny(prefix, "/@:") {
msg := fmt.Sprintf("Wildcarded prefix should be in the format: *.example.com. Current prefix %q is incorrectly formatted", prefix)
return nil, &InvalidRegistries{s: msg}
}
diff --git a/vendor/github.com/containers/image/v5/storage/storage_transport.go b/vendor/github.com/containers/image/v5/storage/storage_transport.go
index ab59c8a29..07393ee74 100644
--- a/vendor/github.com/containers/image/v5/storage/storage_transport.go
+++ b/vendor/github.com/containers/image/v5/storage/storage_transport.go
@@ -225,7 +225,7 @@ func (s *storageTransport) ParseReference(reference string) (types.ImageReferenc
// needs to match a store that was previously initialized using
// storage.GetStore(), or be enough to let the storage library fill out
// the rest using knowledge that it has from elsewhere.
- if reference[0] == '[' {
+ if len(reference) > 0 && reference[0] == '[' {
closeIndex := strings.IndexRune(reference, ']')
if closeIndex < 1 {
return nil, ErrInvalidReference
diff --git a/vendor/github.com/containers/image/v5/types/types.go b/vendor/github.com/containers/image/v5/types/types.go
index 354b3f663..c98a6c6fd 100644
--- a/vendor/github.com/containers/image/v5/types/types.go
+++ b/vendor/github.com/containers/image/v5/types/types.go
@@ -622,6 +622,10 @@ type SystemContext struct {
DockerLogMirrorChoice bool
// Directory to use for OSTree temporary files
OSTreeTmpDirPath string
+ // If true, all blobs will have precomputed digests to ensure layers are not uploaded that already exist on the registry.
+ // Note that this requires writing blobs to temporary files, and takes more time than the default behavior,
+ // when the digest for a blob is unknown.
+ DockerRegistryPushPrecomputeDigests bool
// === docker/daemon.Transport overrides ===
// A directory containing a CA certificate (ending with ".crt"),
diff --git a/vendor/github.com/containers/image/v5/version/version.go b/vendor/github.com/containers/image/v5/version/version.go
index b9f8c3e9f..ffb2a4ce2 100644
--- a/vendor/github.com/containers/image/v5/version/version.go
+++ b/vendor/github.com/containers/image/v5/version/version.go
@@ -6,7 +6,7 @@ const (
// VersionMajor is for an API incompatible changes
VersionMajor = 5
// VersionMinor is for functionality in a backwards-compatible manner
- VersionMinor = 16
+ VersionMinor = 17
// VersionPatch is for backwards-compatible bug fixes
VersionPatch = 0
diff --git a/vendor/github.com/containers/storage/.cirrus.yml b/vendor/github.com/containers/storage/.cirrus.yml
index 20bede452..d080d790c 100644
--- a/vendor/github.com/containers/storage/.cirrus.yml
+++ b/vendor/github.com/containers/storage/.cirrus.yml
@@ -20,16 +20,14 @@ env:
FEDORA_NAME: "fedora-34"
PRIOR_FEDORA_NAME: "fedora-33"
UBUNTU_NAME: "ubuntu-2104"
- PRIOR_UBUNTU_NAME: "ubuntu-2010"
# GCE project where images live
IMAGE_PROJECT: "libpod-218412"
# VM Image built in containers/automation_images
- _BUILT_IMAGE_SUFFIX: "c6248193773010944"
+ _BUILT_IMAGE_SUFFIX: "c6431352024203264"
FEDORA_CACHE_IMAGE_NAME: "fedora-${_BUILT_IMAGE_SUFFIX}"
PRIOR_FEDORA_CACHE_IMAGE_NAME: "prior-fedora-${_BUILT_IMAGE_SUFFIX}"
UBUNTU_CACHE_IMAGE_NAME: "ubuntu-${_BUILT_IMAGE_SUFFIX}"
- PRIOR_UBUNTU_CACHE_IMAGE_NAME: "prior-ubuntu-${_BUILT_IMAGE_SUFFIX}"
####
#### Command variables to help avoid duplication
@@ -115,15 +113,6 @@ ubuntu_testing_task: &ubuntu_testing
TEST_DRIVER: "overlay"
-prior_ubuntu_testing_task:
- <<: *ubuntu_testing
- alias: prior_ubuntu_testing
- name: *std_test_name
- env:
- OS_NAME: "${PRIOR_UBUNTU_NAME}"
- VM_IMAGE: "${PRIOR_UBUNTU_CACHE_IMAGE_NAME}"
-
-
lint_task:
env:
CIRRUS_WORKING_DIR: "/go/src/github.com/containers/storage"
@@ -153,7 +142,6 @@ meta_task:
${FEDORA_CACHE_IMAGE_NAME}
${PRIOR_FEDORA_CACHE_IMAGE_NAME}
${UBUNTU_CACHE_IMAGE_NAME}
- ${PRIOR_UBUNTU_CACHE_IMAGE_NAME}
BUILDID: "${CIRRUS_BUILD_ID}"
REPOREF: "${CIRRUS_CHANGE_IN_REPO}"
GCPJSON: ENCRYPTED[244a93fe8b386b48b96f748342bf741350e43805eee81dd04b45093bdf737e540b993fc735df41f131835fa0f9b65826]
@@ -181,7 +169,6 @@ success_task:
- fedora_testing
- prior_fedora_testing
- ubuntu_testing
- - prior_ubuntu_testing
- meta
- vendor
container:
diff --git a/vendor/github.com/containers/storage/VERSION b/vendor/github.com/containers/storage/VERSION
index 39fc130ef..bf50e910e 100644
--- a/vendor/github.com/containers/storage/VERSION
+++ b/vendor/github.com/containers/storage/VERSION
@@ -1 +1 @@
-1.36.0
+1.37.0
diff --git a/vendor/github.com/containers/storage/drivers/aufs/aufs.go b/vendor/github.com/containers/storage/drivers/aufs/aufs.go
index 76f12ec3b..a566fbffa 100644
--- a/vendor/github.com/containers/storage/drivers/aufs/aufs.go
+++ b/vendor/github.com/containers/storage/drivers/aufs/aufs.go
@@ -730,14 +730,14 @@ func useDirperm() bool {
enableDirpermLock.Do(func() {
base, err := ioutil.TempDir("", "storage-aufs-base")
if err != nil {
- logrus.Errorf("error checking dirperm1: %v", err)
+ logrus.Errorf("Checking dirperm1: %v", err)
return
}
defer os.RemoveAll(base)
union, err := ioutil.TempDir("", "storage-aufs-union")
if err != nil {
- logrus.Errorf("error checking dirperm1: %v", err)
+ logrus.Errorf("Checking dirperm1: %v", err)
return
}
defer os.RemoveAll(union)
@@ -748,7 +748,7 @@ func useDirperm() bool {
}
enableDirperm = true
if err := Unmount(union); err != nil {
- logrus.Errorf("error checking dirperm1: failed to unmount %v", err)
+ logrus.Errorf("Checking dirperm1: failed to unmount %v", err)
}
})
return enableDirperm
diff --git a/vendor/github.com/containers/storage/drivers/driver_linux.go b/vendor/github.com/containers/storage/drivers/driver_linux.go
index dddf8a8b4..0fe3eea7a 100644
--- a/vendor/github.com/containers/storage/drivers/driver_linux.go
+++ b/vendor/github.com/containers/storage/drivers/driver_linux.go
@@ -50,6 +50,40 @@ const (
FsMagicOverlay = FsMagic(0x794C7630)
// FsMagicFUSE filesystem id for FUSE
FsMagicFUSE = FsMagic(0x65735546)
+ // FsMagicAcfs filesystem id for Acfs
+ FsMagicAcfs = FsMagic(0x61636673)
+ // FsMagicAfs filesystem id for Afs
+ FsMagicAfs = FsMagic(0x5346414f)
+ // FsMagicCephFs filesystem id for Ceph
+ FsMagicCephFs = FsMagic(0x00C36400)
+ // FsMagicCIFS filesystem id for CIFS
+ FsMagicCIFS = FsMagic(0xFF534D42)
+ // FsMagicFHGFS filesystem id for FHGFS
+ FsMagicFHGFSFs = FsMagic(0x19830326)
+ // FsMagicIBRIX filesystem id for IBRIX
+ FsMagicIBRIX = FsMagic(0x013111A8)
+ // FsMagicKAFS filesystem id for KAFS
+ FsMagicKAFS = FsMagic(0x6B414653)
+ // FsMagicLUSTRE filesystem id for LUSTRE
+ FsMagicLUSTRE = FsMagic(0x0BD00BD0)
+ // FsMagicNCP filesystem id for NCP
+ FsMagicNCP = FsMagic(0x564C)
+ // FsMagicNFSD filesystem id for NFSD
+ FsMagicNFSD = FsMagic(0x6E667364)
+ // FsMagicOCFS2 filesystem id for OCFS2
+ FsMagicOCFS2 = FsMagic(0x7461636F)
+ // FsMagicPANFS filesystem id for PANFS
+ FsMagicPANFS = FsMagic(0xAAD7AAEA)
+ // FsMagicPRLFS filesystem id for PRLFS
+ FsMagicPRLFS = FsMagic(0x7C7C6673)
+ // FsMagicSMB2 filesystem id for SMB2
+ FsMagicSMB2 = FsMagic(0xFE534D42)
+ // FsMagicSNFS filesystem id for SNFS
+ FsMagicSNFS = FsMagic(0xBEEFDEAD)
+ // FsMagicVBOXSF filesystem id for VBOXSF
+ FsMagicVBOXSF = FsMagic(0x786F4256)
+ // FsMagicVXFS filesystem id for VXFS
+ FsMagicVXFS = FsMagic(0xA501FCF5)
)
var (
diff --git a/vendor/github.com/containers/storage/drivers/fsdiff.go b/vendor/github.com/containers/storage/drivers/fsdiff.go
index c52788509..a534630df 100644
--- a/vendor/github.com/containers/storage/drivers/fsdiff.go
+++ b/vendor/github.com/containers/storage/drivers/fsdiff.go
@@ -180,7 +180,7 @@ func (gdw *NaiveDiffDriver) ApplyDiff(id, parent string, options ApplyDiffOpts)
start := time.Now().UTC()
logrus.Debug("Start untar layer")
if size, err = ApplyUncompressedLayer(layerFs, options.Diff, tarOptions); err != nil {
- logrus.Errorf("Error while applying layer: %s", err)
+ logrus.Errorf("While applying layer: %s", err)
return
}
logrus.Debugf("Untar time: %vs", time.Now().UTC().Sub(start).Seconds())
diff --git a/vendor/github.com/containers/storage/drivers/overlay/overlay.go b/vendor/github.com/containers/storage/drivers/overlay/overlay.go
index f546f9b10..1efe7316d 100644
--- a/vendor/github.com/containers/storage/drivers/overlay/overlay.go
+++ b/vendor/github.com/containers/storage/drivers/overlay/overlay.go
@@ -174,21 +174,21 @@ func checkSupportVolatile(home, runhome string) (bool, error) {
var usingVolatile bool
if err == nil {
if volatileCacheResult {
- logrus.Debugf("cached value indicated that volatile is being used")
+ logrus.Debugf("Cached value indicated that volatile is being used")
} else {
- logrus.Debugf("cached value indicated that volatile is not being used")
+ logrus.Debugf("Cached value indicated that volatile is not being used")
}
usingVolatile = volatileCacheResult
} else {
usingVolatile, err = doesVolatile(home)
if err == nil {
if usingVolatile {
- logrus.Debugf("overlay test mount indicated that volatile is being used")
+ logrus.Debugf("overlay: test mount indicated that volatile is being used")
} else {
- logrus.Debugf("overlay test mount indicated that volatile is not being used")
+ logrus.Debugf("overlay: test mount indicated that volatile is not being used")
}
if err = cachedFeatureRecord(runhome, feature, usingVolatile, ""); err != nil {
- return false, errors.Wrap(err, "error recording volatile-being-used status")
+ return false, errors.Wrap(err, "recording volatile-being-used status")
}
}
}
@@ -206,9 +206,9 @@ func checkAndRecordOverlaySupport(fsMagic graphdriver.FsMagic, home, runhome str
overlayCacheResult, overlayCacheText, err := cachedFeatureCheck(runhome, feature)
if err == nil {
if overlayCacheResult {
- logrus.Debugf("cached value indicated that overlay is supported")
+ logrus.Debugf("Cached value indicated that overlay is supported")
} else {
- logrus.Debugf("cached value indicated that overlay is not supported")
+ logrus.Debugf("Cached value indicated that overlay is not supported")
}
supportsDType = overlayCacheResult
if !supportsDType {
@@ -225,12 +225,12 @@ func checkAndRecordOverlaySupport(fsMagic graphdriver.FsMagic, home, runhome str
}
err = errors.Wrap(err, "kernel does not support overlay fs")
if err2 := cachedFeatureRecord(runhome, feature, false, err.Error()); err2 != nil {
- return false, errors.Wrapf(err2, "error recording overlay not being supported (%v)", err)
+ return false, errors.Wrapf(err2, "recording overlay not being supported (%v)", err)
}
return false, err
}
if err = cachedFeatureRecord(runhome, feature, supportsDType, ""); err != nil {
- return false, errors.Wrap(err, "error recording overlay support status")
+ return false, errors.Wrap(err, "recording overlay support status")
}
}
return supportsDType, nil
@@ -248,6 +248,23 @@ func (d *Driver) getSupportsVolatile() (bool, error) {
return supportsVolatile, nil
}
+// isNetworkFileSystem checks if the specified file system is supported by native overlay
+// as backing store when running in a user namespace.
+func isNetworkFileSystem(fsMagic graphdriver.FsMagic) bool {
+ switch fsMagic {
+ // a bunch of network file systems...
+ case graphdriver.FsMagicNfsFs, graphdriver.FsMagicSmbFs, graphdriver.FsMagicAcfs,
+ graphdriver.FsMagicAfs, graphdriver.FsMagicCephFs, graphdriver.FsMagicCIFS,
+ graphdriver.FsMagicFHGFSFs, graphdriver.FsMagicGPFS, graphdriver.FsMagicIBRIX,
+ graphdriver.FsMagicKAFS, graphdriver.FsMagicLUSTRE, graphdriver.FsMagicNCP,
+ graphdriver.FsMagicNFSD, graphdriver.FsMagicOCFS2, graphdriver.FsMagicPANFS,
+ graphdriver.FsMagicPRLFS, graphdriver.FsMagicSMB2, graphdriver.FsMagicSNFS,
+ graphdriver.FsMagicVBOXSF, graphdriver.FsMagicVXFS:
+ return true
+ }
+ return false
+}
+
// Init returns the a native diff driver for overlay filesystem.
// If overlay filesystem is not supported on the host, a wrapped graphdriver.ErrNotSupported is returned as error.
// If an overlay filesystem is not supported over an existing filesystem then a wrapped graphdriver.ErrIncompatibleFS is returned.
@@ -266,18 +283,27 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error)
}
if opts.mountProgram != "" {
+ if unshare.IsRootless() && isNetworkFileSystem(fsMagic) && opts.forceMask == nil {
+ m := os.FileMode(0700)
+ opts.forceMask = &m
+ logrus.Warnf("Network file system detected as backing store. Enforcing overlay option `force_mask=\"%o\"`. Add it to storage.conf to silence this warning", m)
+ }
+
if err := ioutil.WriteFile(getMountProgramFlagFile(home), []byte("true"), 0600); err != nil {
return nil, err
}
} else {
- // check if they are running over btrfs, aufs, zfs, overlay, or ecryptfs
if opts.forceMask != nil {
return nil, errors.New("'force_mask' is supported only with 'mount_program'")
}
+ // check if they are running over btrfs, aufs, zfs, overlay, or ecryptfs
switch fsMagic {
case graphdriver.FsMagicAufs, graphdriver.FsMagicZfs, graphdriver.FsMagicOverlay, graphdriver.FsMagicEcryptfs:
return nil, errors.Wrapf(graphdriver.ErrIncompatibleFS, "'overlay' is not supported over %s, a mount_program is required", backingFs)
}
+ if unshare.IsRootless() && isNetworkFileSystem(fsMagic) {
+ return nil, errors.Wrapf(graphdriver.ErrIncompatibleFS, "A network file system with user namespaces is not supported. Please use a mount_program")
+ }
}
rootUID, rootGID, err := idtools.GetRootUIDGID(options.UIDMaps, options.GIDMaps)
@@ -310,24 +336,24 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error)
metacopyCacheResult, _, err := cachedFeatureCheck(runhome, feature)
if err == nil {
if metacopyCacheResult {
- logrus.Debugf("cached value indicated that metacopy is being used")
+ logrus.Debugf("Cached value indicated that metacopy is being used")
} else {
- logrus.Debugf("cached value indicated that metacopy is not being used")
+ logrus.Debugf("Cached value indicated that metacopy is not being used")
}
usingMetacopy = metacopyCacheResult
} else {
usingMetacopy, err = doesMetacopy(home, opts.mountOptions)
if err == nil {
if usingMetacopy {
- logrus.Debugf("overlay test mount indicated that metacopy is being used")
+ logrus.Debugf("overlay: test mount indicated that metacopy is being used")
} else {
- logrus.Debugf("overlay test mount indicated that metacopy is not being used")
+ logrus.Debugf("overlay: test mount indicated that metacopy is not being used")
}
if err = cachedFeatureRecord(runhome, feature, usingMetacopy, ""); err != nil {
- return nil, errors.Wrap(err, "error recording metacopy-being-used status")
+ return nil, errors.Wrap(err, "recording metacopy-being-used status")
}
} else {
- logrus.Infof("overlay test mount did not indicate whether or not metacopy is being used: %v", err)
+ logrus.Infof("overlay: test mount did not indicate whether or not metacopy is being used: %v", err)
return nil, err
}
}
@@ -548,7 +574,7 @@ func SupportsNativeOverlay(graphroot, rundir string) (bool, error) {
}
switch contents {
case "true":
- logrus.Debugf("overlay storage already configured with a mount-program")
+ logrus.Debugf("overlay: storage already configured with a mount-program")
return false, nil
default:
needsMountProgram, err := scanForMountProgramIndicators(home)
@@ -640,17 +666,17 @@ func supportsOverlay(home string, homeMagic graphdriver.FsMagic, rootUID, rootGI
flags = fmt.Sprintf("%s,userxattr", flags)
}
if err := syscall.Mknod(filepath.Join(upperDir, "whiteout"), syscall.S_IFCHR|0600, int(unix.Mkdev(0, 0))); err != nil {
- logrus.Debugf("unable to create kernel-style whiteout: %v", err)
+ logrus.Debugf("Unable to create kernel-style whiteout: %v", err)
return supportsDType, errors.Wrapf(err, "unable to create kernel-style whiteout")
}
if len(flags) < unix.Getpagesize() {
err := unix.Mount("overlay", mergedDir, "overlay", 0, flags)
if err == nil {
- logrus.Debugf("overlay test mount with multiple lowers succeeded")
+ logrus.Debugf("overlay: test mount with multiple lowers succeeded")
return supportsDType, nil
}
- logrus.Debugf("overlay test mount with multiple lowers failed %v", err)
+ logrus.Debugf("overlay: test mount with multiple lowers failed %v", err)
}
flags = fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lower1Dir, upperDir, workDir)
if selinux.GetEnabled() {
@@ -659,10 +685,10 @@ func supportsOverlay(home string, homeMagic graphdriver.FsMagic, rootUID, rootGI
if len(flags) < unix.Getpagesize() {
err := unix.Mount("overlay", mergedDir, "overlay", 0, flags)
if err == nil {
- logrus.StandardLogger().Logf(logLevel, "overlay test mount with multiple lowers failed, but succeeded with a single lower")
+ logrus.StandardLogger().Logf(logLevel, "overlay: test mount with multiple lowers failed, but succeeded with a single lower")
return supportsDType, errors.Wrap(graphdriver.ErrNotSupported, "kernel too old to provide multiple lowers feature for overlay")
}
- logrus.Debugf("overlay test mount with a single lower failed %v", err)
+ logrus.Debugf("overlay: test mount with a single lower failed %v", err)
}
logrus.StandardLogger().Logf(logLevel, "'overlay' is not supported over %s at %q", backingFs, home)
return supportsDType, errors.Wrapf(graphdriver.ErrIncompatibleFS, "'overlay' is not supported over %s at %q", backingFs, home)
@@ -682,9 +708,9 @@ func (d *Driver) useNaiveDiff() bool {
nativeDiffCacheResult, nativeDiffCacheText, err := cachedFeatureCheck(d.runhome, feature)
if err == nil {
if nativeDiffCacheResult {
- logrus.Debugf("cached value indicated that native-diff is usable")
+ logrus.Debugf("Cached value indicated that native-diff is usable")
} else {
- logrus.Debugf("cached value indicated that native-diff is not being used")
+ logrus.Debugf("Cached value indicated that native-diff is not being used")
logrus.Info(nativeDiffCacheText)
}
useNaiveDiffOnly = !nativeDiffCacheResult
@@ -821,7 +847,7 @@ func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts
opts.StorageOpt["inodes"] = strconv.FormatUint(d.options.quota.Inodes, 10)
}
- return d.create(id, parent, opts)
+ return d.create(id, parent, opts, false)
}
// Create is used to create the upper, lower, and merge directories required for overlay fs for a given id.
@@ -831,15 +857,16 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) (retErr
if _, ok := opts.StorageOpt["size"]; ok {
return fmt.Errorf("--storage-opt size is only supported for ReadWrite Layers")
}
+
if _, ok := opts.StorageOpt["inodes"]; ok {
return fmt.Errorf("--storage-opt inodes is only supported for ReadWrite Layers")
}
}
- return d.create(id, parent, opts)
+ return d.create(id, parent, opts, true)
}
-func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr error) {
+func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, disableQuota bool) (retErr error) {
dir := d.dir(id)
uidMaps := d.uidMaps
@@ -880,7 +907,7 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr
}
}()
- if d.quotaCtl != nil {
+ if d.quotaCtl != nil && !disableQuota {
quota := quota.Quota{}
if opts != nil && len(opts.StorageOpt) > 0 {
driver := &Driver{}
@@ -994,7 +1021,7 @@ func (d *Driver) getLower(parent string) (string, error) {
}
logrus.Warnf("Can't read parent link %q because it does not exist. Going through storage to recreate the missing links.", path.Join(parentDir, "link"))
if err := d.recreateSymlinks(); err != nil {
- return "", errors.Wrap(err, "error recreating the links")
+ return "", errors.Wrap(err, "recreating the links")
}
parentLink, err = ioutil.ReadFile(path.Join(parentDir, "link"))
if err != nil {
@@ -1038,7 +1065,7 @@ func (d *Driver) getLowerDirs(id string) ([]string, error) {
if os.IsNotExist(err) {
logrus.Warnf("Can't read link %q because it does not exist. A storage corruption might have occurred, attempting to recreate the missing symlinks. It might be best wipe the storage to avoid further errors due to storage corruption.", lower)
if err := d.recreateSymlinks(); err != nil {
- return nil, fmt.Errorf("error recreating the missing symlinks: %v", err)
+ return nil, fmt.Errorf("recreating the missing symlinks: %v", err)
}
// let's call Readlink on lower again now that we have recreated the missing symlinks
lp, err = os.Readlink(lower)
@@ -1121,7 +1148,7 @@ func (d *Driver) recreateSymlinks() error {
// List all the directories under the home directory
dirs, err := ioutil.ReadDir(d.home)
if err != nil {
- return fmt.Errorf("error reading driver home directory %q: %v", d.home, err)
+ return fmt.Errorf("reading driver home directory %q: %v", d.home, err)
}
linksDir := filepath.Join(d.home, "l")
// This makes the link directory if it doesn't exist
@@ -1148,7 +1175,7 @@ func (d *Driver) recreateSymlinks() error {
// Read the "link" file under each layer to get the name of the symlink
data, err := ioutil.ReadFile(path.Join(d.dir(dir.Name()), "link"))
if err != nil {
- errs = multierror.Append(errs, errors.Wrapf(err, "error reading name of symlink for %q", dir))
+ errs = multierror.Append(errs, errors.Wrapf(err, "reading name of symlink for %q", dir))
continue
}
linkPath := path.Join(d.home, linkDir, strings.Trim(string(data), "\n"))
@@ -1162,7 +1189,7 @@ func (d *Driver) recreateSymlinks() error {
}
madeProgress = true
} else if err != nil {
- errs = multierror.Append(errs, errors.Wrapf(err, "error trying to stat %q", linkPath))
+ errs = multierror.Append(errs, err)
continue
}
}
@@ -1170,7 +1197,7 @@ func (d *Driver) recreateSymlinks() error {
// that each symlink we have corresponds to one.
links, err := ioutil.ReadDir(linksDir)
if err != nil {
- errs = multierror.Append(errs, errors.Wrapf(err, "error reading links directory %q", linksDir))
+ errs = multierror.Append(errs, err)
continue
}
// Go through all of the symlinks in the "l" directory
@@ -1178,7 +1205,7 @@ func (d *Driver) recreateSymlinks() error {
// Read the symlink's target, which should be "../$layer/diff"
target, err := os.Readlink(filepath.Join(linksDir, link.Name()))
if err != nil {
- errs = multierror.Append(errs, errors.Wrapf(err, "error reading target of link %q", link))
+ errs = multierror.Append(errs, err)
continue
}
targetComponents := strings.Split(target, string(os.PathSeparator))
@@ -1196,7 +1223,7 @@ func (d *Driver) recreateSymlinks() error {
data, err := ioutil.ReadFile(linkFile)
if err != nil || string(data) != link.Name() {
if err := ioutil.WriteFile(linkFile, []byte(link.Name()), 0644); err != nil {
- errs = multierror.Append(errs, errors.Wrapf(err, "error correcting link for layer %q", targetID))
+ errs = multierror.Append(errs, errors.Wrapf(err, "correcting link for layer %s", targetID))
continue
}
madeProgress = true
@@ -1241,7 +1268,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
if unshare.IsRootless() {
logLevel = logrus.DebugLevel
}
- logrus.StandardLogger().Logf(logLevel, "ignoring metacopy option from storage.conf, not supported with booted kernel")
+ logrus.StandardLogger().Logf(logLevel, "Ignoring metacopy option from storage.conf, not supported with booted kernel")
}
}
}
@@ -1275,7 +1302,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
}
logrus.Warnf("Can't read parent link %q because it does not exist. Going through storage to recreate the missing links.", path.Join(dir, "link"))
if err := d.recreateSymlinks(); err != nil {
- return "", errors.Wrap(err, "error recreating the links")
+ return "", errors.Wrap(err, "recreating the links")
}
link, err = ioutil.ReadFile(path.Join(dir, "link"))
if err != nil {
@@ -1330,7 +1357,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
if lower == "" && os.IsNotExist(err) {
logrus.Warnf("Can't stat lower layer %q because it does not exist. Going through storage to recreate the missing symlinks.", newpath)
if err := d.recreateSymlinks(); err != nil {
- return "", fmt.Errorf("error recreating the missing symlinks: %v", err)
+ return "", fmt.Errorf("Recreating the missing symlinks: %v", err)
}
lower = newpath
} else if lower == "" {
@@ -1381,7 +1408,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
if retErr != nil {
if c := d.ctr.Decrement(mergedDir); c <= 0 {
if mntErr := unix.Unmount(mergedDir, 0); mntErr != nil {
- logrus.Errorf("error unmounting %v: %v", mergedDir, mntErr)
+ logrus.Errorf("Unmounting %v: %v", mergedDir, mntErr)
}
}
}
@@ -1430,6 +1457,11 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
label = d.optsAppendMappings(label, options.UidMaps, options.GidMaps)
}
+ // if forceMask is in place, tell fuse-overlayfs to write the permissions mask to an unprivileged xattr as well.
+ if d.options.forceMask != nil {
+ label = label + ",xattr_permissions=2"
+ }
+
mountProgram := exec.Command(d.options.mountProgram, "-o", label, target)
mountProgram.Dir = d.home
var b bytes.Buffer
@@ -1473,7 +1505,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
flags, data := mount.ParseOptions(mountData)
logrus.Debugf("overlay: mount_data=%s", mountData)
if err := mountFunc("overlay", mountTarget, "overlay", uintptr(flags), data); err != nil {
- return "", fmt.Errorf("error creating overlay mount to %s, mount_data=%q: %v", mountTarget, mountData, err)
+ return "", fmt.Errorf("creating overlay mount to %s, mount_data=%q: %v", mountTarget, mountData, err)
}
return mergedDir, nil
@@ -1820,7 +1852,7 @@ func (d *Driver) UpdateLayerIDMap(id string, toContainer, toHost *idtools.IDMapp
err = graphdriver.ChownPathByMaps(layerFs, toContainer, toHost)
if err != nil {
if err2 := d.Put(id); err2 != nil {
- logrus.Errorf("%v; error unmounting %v: %v", err, id, err2)
+ logrus.Errorf("%v; unmounting %v: %v", err, id, err2)
}
return err
}
@@ -1923,7 +1955,7 @@ func (d *Driver) releaseAdditionalLayerByID(id string) {
if al, err := d.getAdditionalLayerPathByID(id); err == nil {
notifyReleaseAdditionalLayer(al)
} else if !os.IsNotExist(err) {
- logrus.Warnf("unexpected error on reading Additional Layer Store pointer %v", err)
+ logrus.Warnf("Unexpected error on reading Additional Layer Store pointer %v", err)
}
}
@@ -2004,10 +2036,10 @@ func notifyUseAdditionalLayer(al string) {
} else if err == nil {
f.Close()
if err := os.Remove(useFile); err != nil {
- logrus.Warnf("failed to remove use file")
+ logrus.Warnf("Failed to remove use file")
}
}
- logrus.Warnf("unexpected error by Additional Layer Store %v during use; GC doesn't seem to be supported", err)
+ logrus.Warnf("Unexpected error by Additional Layer Store %v during use; GC doesn't seem to be supported", err)
}
// notifyReleaseAdditionalLayer notifies Additional Layer Store that we don't use the specified
@@ -2024,7 +2056,7 @@ func notifyReleaseAdditionalLayer(al string) {
if os.IsNotExist(err) {
return
}
- logrus.Warnf("unexpected error by Additional Layer Store %v during release; GC doesn't seem to be supported", err)
+ logrus.Warnf("Unexpected error by Additional Layer Store %v during release; GC doesn't seem to be supported", err)
}
// redirectDiffIfAdditionalLayer checks if the passed diff path is Additional Layer and
diff --git a/vendor/github.com/containers/storage/drivers/overlay/randomid.go b/vendor/github.com/containers/storage/drivers/overlay/randomid.go
index fc565ef0b..736c48b9c 100644
--- a/vendor/github.com/containers/storage/drivers/overlay/randomid.go
+++ b/vendor/github.com/containers/storage/drivers/overlay/randomid.go
@@ -47,7 +47,7 @@ func generateID(l int) string {
if retryOnError(err) && retries < maxretries {
count += n
retries++
- logrus.Errorf("error generating version 4 uuid, retrying: %v", err)
+ logrus.Errorf("Generating version 4 uuid, retrying: %v", err)
continue
}
diff --git a/vendor/github.com/containers/storage/drivers/template.go b/vendor/github.com/containers/storage/drivers/template.go
index 5d80b8865..d40d71cfc 100644
--- a/vendor/github.com/containers/storage/drivers/template.go
+++ b/vendor/github.com/containers/storage/drivers/template.go
@@ -31,7 +31,7 @@ func NaiveCreateFromTemplate(d TemplateDriver, id, template string, templateIDMa
diff, err := d.Diff(template, templateIDMappings, parent, parentIDMappings, opts.MountLabel)
if err != nil {
if err2 := d.Remove(id); err2 != nil {
- logrus.Errorf("error removing layer %q: %v", id, err2)
+ logrus.Errorf("Removing layer %q: %v", id, err2)
}
return err
}
@@ -44,7 +44,7 @@ func NaiveCreateFromTemplate(d TemplateDriver, id, template string, templateIDMa
}
if _, err = d.ApplyDiff(id, parent, applyOptions); err != nil {
if err2 := d.Remove(id); err2 != nil {
- logrus.Errorf("error removing layer %q: %v", id, err2)
+ logrus.Errorf("Removing layer %q: %v", id, err2)
}
return err
}
diff --git a/vendor/github.com/containers/storage/go.mod b/vendor/github.com/containers/storage/go.mod
index 911469182..6cd809745 100644
--- a/vendor/github.com/containers/storage/go.mod
+++ b/vendor/github.com/containers/storage/go.mod
@@ -6,20 +6,19 @@ require (
github.com/BurntSushi/toml v0.4.1
github.com/Microsoft/go-winio v0.5.0
github.com/Microsoft/hcsshim v0.8.22
- github.com/containerd/stargz-snapshotter/estargz v0.8.0
+ github.com/containerd/stargz-snapshotter/estargz v0.9.0
github.com/docker/go-units v0.4.0
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
github.com/google/go-intervals v0.0.2
github.com/google/uuid v1.2.0 // indirect
github.com/hashicorp/go-multierror v1.1.1
- github.com/json-iterator/go v1.1.11
- github.com/klauspost/compress v1.13.5
+ github.com/json-iterator/go v1.1.12
+ github.com/klauspost/compress v1.13.6
github.com/klauspost/pgzip v1.2.5
github.com/mattn/go-shellwords v1.0.12
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible
github.com/moby/sys/mountinfo v0.4.1
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
- github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/runc v1.0.2
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
diff --git a/vendor/github.com/containers/storage/go.sum b/vendor/github.com/containers/storage/go.sum
index 5cc5da6d3..1b602d484 100644
--- a/vendor/github.com/containers/storage/go.sum
+++ b/vendor/github.com/containers/storage/go.sum
@@ -31,8 +31,8 @@ github.com/containerd/containerd v1.4.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMX
github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM=
github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4=
github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok=
-github.com/containerd/stargz-snapshotter/estargz v0.8.0 h1:oA1wx8kTFfImfsT5bScbrZd8gK+WtQnn15q82Djvm0Y=
-github.com/containerd/stargz-snapshotter/estargz v0.8.0/go.mod h1:mwIwuwb+D8FX2t45Trwi0hmWmZm5VW7zPP/rekwhWQU=
+github.com/containerd/stargz-snapshotter/estargz v0.9.0 h1:PkB6BSTfOKX23erT2GkoUKkJEcXfNcyKskIViK770v8=
+github.com/containerd/stargz-snapshotter/estargz v0.9.0/go.mod h1:aE5PCyhFMwR8sbrErO5eM2GcvkyXTTJremG883D4qF0=
github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
@@ -115,15 +115,15 @@ github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
-github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
-github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
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/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/compress v1.13.5 h1:9O69jUPDcsT9fEm74W92rZL9FQY7rCdaXVneq+yyzl4=
-github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
+github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
+github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
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=
@@ -148,9 +148,8 @@ github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2J
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
-github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
diff --git a/vendor/github.com/containers/storage/layers.go b/vendor/github.com/containers/storage/layers.go
index 32ba20685..fbf6ad362 100644
--- a/vendor/github.com/containers/storage/layers.go
+++ b/vendor/github.com/containers/storage/layers.go
@@ -1557,7 +1557,7 @@ func (r *layerStore) applyDiffWithOptions(to string, layerOptions *LayerOptions,
compressor = pgzip.NewWriter(&tsdata)
}
if err := compressor.SetConcurrency(1024*1024, 1); err != nil { // 1024*1024 is the hard-coded default; we're not changing that
- logrus.Infof("error setting compression concurrency threads to 1: %v; ignoring", err)
+ logrus.Infof("Error setting compression concurrency threads to 1: %v; ignoring", err)
}
metadata := storage.NewJSONPacker(compressor)
uncompressed, err := archive.DecompressStream(defragmented)
diff --git a/vendor/github.com/containers/storage/pkg/archive/archive.go b/vendor/github.com/containers/storage/pkg/archive/archive.go
index 48e846f7c..76544ff28 100644
--- a/vendor/github.com/containers/storage/pkg/archive/archive.go
+++ b/vendor/github.com/containers/storage/pkg/archive/archive.go
@@ -879,7 +879,7 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
if include != relFilePath {
matches, err := pm.IsMatch(relFilePath)
if err != nil {
- logrus.Errorf("Error matching %s: %v", relFilePath, err)
+ logrus.Errorf("Matching %s: %v", relFilePath, err)
return err
}
skip = matches
diff --git a/vendor/github.com/containers/storage/pkg/chunked/storage_linux.go b/vendor/github.com/containers/storage/pkg/chunked/storage_linux.go
index 7bd804c44..6efc6a4c8 100644
--- a/vendor/github.com/containers/storage/pkg/chunked/storage_linux.go
+++ b/vendor/github.com/containers/storage/pkg/chunked/storage_linux.go
@@ -345,6 +345,56 @@ func getFileDigest(f *os.File) (digest.Digest, error) {
return digester.Digest(), nil
}
+// findFileInOSTreeRepos checks whether the requested file already exist in one of the OSTree repo and copies the file content from there if possible.
+// file is the file to look for.
+// ostreeRepos is a list of OSTree repos.
+// dirfd is an open fd to the destination checkout.
+// useHardLinks defines whether the deduplication can be performed using hard links.
+func findFileInOSTreeRepos(file *internal.FileMetadata, ostreeRepos []string, dirfd int, useHardLinks bool) (bool, *os.File, int64, error) {
+ digest, err := digest.Parse(file.Digest)
+ if err != nil {
+ return false, nil, 0, nil
+ }
+ payloadLink := digest.Encoded() + ".payload-link"
+ if len(payloadLink) < 2 {
+ return false, nil, 0, nil
+ }
+
+ for _, repo := range ostreeRepos {
+ sourceFile := filepath.Join(repo, "objects", payloadLink[:2], payloadLink[2:])
+ st, err := os.Stat(sourceFile)
+ if err != nil || !st.Mode().IsRegular() {
+ continue
+ }
+ if st.Size() != file.Size {
+ continue
+ }
+ fd, err := unix.Open(sourceFile, unix.O_RDONLY|unix.O_NONBLOCK, 0)
+ if err != nil {
+ return false, nil, 0, nil
+ }
+ f := os.NewFile(uintptr(fd), "fd")
+ defer f.Close()
+
+ // check if the open file can be deduplicated with hard links
+ if useHardLinks && !canDedupFileWithHardLink(file, fd, st) {
+ continue
+ }
+
+ dstFile, written, err := copyFileContent(fd, file.Name, dirfd, 0, useHardLinks)
+ if err != nil {
+ return false, nil, 0, nil
+ }
+ return true, dstFile, written, nil
+ }
+ // If hard links deduplication was used and it has failed, try again without hard links.
+ if useHardLinks {
+ return findFileInOSTreeRepos(file, ostreeRepos, dirfd, false)
+ }
+
+ return false, nil, 0, nil
+}
+
// findFileOnTheHost checks whether the requested file already exist on the host and copies the file content from there if possible.
// It is currently implemented to look only at the file with the same path. Ideally it can detect the same content also at different
// paths.
@@ -873,6 +923,9 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions) (gra
// modifies the source file as well.
useHardLinks := parseBooleanPullOption(&storeOpts, "use_hard_links", false)
+ // List of OSTree repositories to use for deduplication
+ ostreeRepos := strings.Split(storeOpts.PullOptions["ostree_repos"], ":")
+
// Generate the manifest
var toc internal.TOC
if err := json.Unmarshal(c.manifest, &toc); err != nil {
@@ -1009,18 +1062,35 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions) (gra
totalChunksSize += r.Size
+ finalizeFile := func(dstFile *os.File) error {
+ if dstFile != nil {
+ defer dstFile.Close()
+ if err := setFileAttrs(dstFile, mode, &r, options); err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+
found, dstFile, _, err := findFileInOtherLayers(&r, dirfd, otherLayersCache, c.layersTarget, useHardLinks)
if err != nil {
return output, err
}
- if dstFile != nil {
- if err := setFileAttrs(dstFile, mode, &r, options); err != nil {
- dstFile.Close()
+ if found {
+ if err := finalizeFile(dstFile); err != nil {
return output, err
}
- dstFile.Close()
+ continue
+ }
+
+ found, dstFile, _, err = findFileInOSTreeRepos(&r, ostreeRepos, dirfd, useHardLinks)
+ if err != nil {
+ return output, err
}
if found {
+ if err := finalizeFile(dstFile); err != nil {
+ return output, err
+ }
continue
}
@@ -1029,14 +1099,10 @@ func (c *chunkedDiffer) ApplyDiff(dest string, options *archive.TarOptions) (gra
if err != nil {
return output, err
}
- if dstFile != nil {
- if err := setFileAttrs(dstFile, mode, &r, options); err != nil {
- dstFile.Close()
+ if found {
+ if err := finalizeFile(dstFile); err != nil {
return output, err
}
- dstFile.Close()
- }
- if found {
continue
}
}
diff --git a/vendor/github.com/containers/storage/pkg/fileutils/fileutils_unix.go b/vendor/github.com/containers/storage/pkg/fileutils/fileutils_unix.go
index 9e0e97bd6..92056c1d5 100644
--- a/vendor/github.com/containers/storage/pkg/fileutils/fileutils_unix.go
+++ b/vendor/github.com/containers/storage/pkg/fileutils/fileutils_unix.go
@@ -14,7 +14,7 @@ import (
// reading it via /proc filesystem.
func GetTotalUsedFds() int {
if fds, err := ioutil.ReadDir(fmt.Sprintf("/proc/%d/fd", os.Getpid())); err != nil {
- logrus.Errorf("Error opening /proc/%d/fd: %s", os.Getpid(), err)
+ logrus.Errorf("%v", err)
} else {
return len(fds)
}
diff --git a/vendor/github.com/containers/storage/pkg/lockfile/lockfile_unix.go b/vendor/github.com/containers/storage/pkg/lockfile/lockfile_unix.go
index b224e7b5c..fc080acbe 100644
--- a/vendor/github.com/containers/storage/pkg/lockfile/lockfile_unix.go
+++ b/vendor/github.com/containers/storage/pkg/lockfile/lockfile_unix.go
@@ -36,7 +36,7 @@ type lockfile struct {
// necessary.
func openLock(path string, ro bool) (fd int, err error) {
if ro {
- fd, err = unix.Open(path, os.O_RDONLY|unix.O_CLOEXEC, 0)
+ fd, err = unix.Open(path, os.O_RDONLY|unix.O_CLOEXEC|os.O_CREATE, 0)
} else {
fd, err = unix.Open(path,
os.O_RDWR|unix.O_CLOEXEC|os.O_CREATE,
diff --git a/vendor/github.com/containers/storage/pkg/loopback/attach_loopback.go b/vendor/github.com/containers/storage/pkg/loopback/attach_loopback.go
index e2cf30b41..6f0726505 100644
--- a/vendor/github.com/containers/storage/pkg/loopback/attach_loopback.go
+++ b/vendor/github.com/containers/storage/pkg/loopback/attach_loopback.go
@@ -43,7 +43,7 @@ func openNextAvailableLoopback(index int, sparseName string, sparseFile *os.File
var st syscall.Stat_t
err = syscall.Fstat(int(sparseFile.Fd()), &st)
if err != nil {
- logrus.Errorf("Error reading information about loopback file %s: %v", sparseName, err)
+ logrus.Errorf("Reading information about loopback file %s: %v", sparseName, err)
return nil, ErrAttachLoopbackDevice
}
@@ -68,7 +68,7 @@ func openNextAvailableLoopback(index int, sparseName string, sparseFile *os.File
// OpenFile adds O_CLOEXEC
loopFile, err = os.OpenFile(target, os.O_RDWR, 0644)
if err != nil {
- logrus.Errorf("Error opening loopback device: %s", err)
+ logrus.Errorf("Opening loopback device: %s", err)
return nil, ErrAttachLoopbackDevice
}
@@ -90,7 +90,7 @@ func openNextAvailableLoopback(index int, sparseName string, sparseFile *os.File
// device and inode numbers.
dev, ino, err := getLoopbackBackingFile(loopFile)
if err != nil {
- logrus.Errorf("Error getting loopback backing file: %s", err)
+ logrus.Errorf("Getting loopback backing file: %s", err)
return nil, ErrGetLoopbackBackingFile
}
if dev != uint64(st.Dev) || ino != st.Ino {
@@ -125,7 +125,7 @@ func AttachLoopDevice(sparseName string) (loop *os.File, err error) {
// OpenFile adds O_CLOEXEC
sparseFile, err := os.OpenFile(sparseName, os.O_RDWR, 0644)
if err != nil {
- logrus.Errorf("Error opening sparse file %s: %s", sparseName, err)
+ logrus.Errorf("Opening sparse file: %v", err)
return nil, ErrAttachLoopbackDevice
}
defer sparseFile.Close()
@@ -147,7 +147,7 @@ func AttachLoopDevice(sparseName string) (loop *os.File, err error) {
// If the call failed, then free the loopback device
if err := ioctlLoopClrFd(loopFile.Fd()); err != nil {
- logrus.Error("Error while cleaning up the loopback device")
+ logrus.Error("While cleaning up the loopback device")
}
loopFile.Close()
return nil, ErrAttachLoopbackDevice
diff --git a/vendor/github.com/containers/storage/pkg/loopback/loopback.go b/vendor/github.com/containers/storage/pkg/loopback/loopback.go
index f4cf2826e..c9be05776 100644
--- a/vendor/github.com/containers/storage/pkg/loopback/loopback.go
+++ b/vendor/github.com/containers/storage/pkg/loopback/loopback.go
@@ -13,7 +13,7 @@ import (
func getLoopbackBackingFile(file *os.File) (uint64, uint64, error) {
loopInfo, err := ioctlLoopGetStatus64(file.Fd())
if err != nil {
- logrus.Errorf("Error get loopback backing file: %s", err)
+ logrus.Errorf("Get loopback backing file: %v", err)
return 0, 0, ErrGetLoopbackBackingFile
}
return loopInfo.loDevice, loopInfo.loInode, nil
@@ -22,7 +22,7 @@ func getLoopbackBackingFile(file *os.File) (uint64, uint64, error) {
// SetCapacity reloads the size for the loopback device.
func SetCapacity(file *os.File) error {
if err := ioctlLoopSetCapacity(file.Fd(), 0); err != nil {
- logrus.Errorf("Error loopbackSetCapacity: %s", err)
+ logrus.Errorf("loopbackSetCapacity: %s", err)
return ErrSetCapacity
}
return nil
diff --git a/vendor/github.com/containers/storage/pkg/parsers/kernel/kernel_unix.go b/vendor/github.com/containers/storage/pkg/parsers/kernel/kernel_unix.go
index 76e1e499f..7a68bc39b 100644
--- a/vendor/github.com/containers/storage/pkg/parsers/kernel/kernel_unix.go
+++ b/vendor/github.com/containers/storage/pkg/parsers/kernel/kernel_unix.go
@@ -35,7 +35,7 @@ func GetKernelVersion() (*VersionInfo, error) {
// the given version.
func CheckKernelVersion(k, major, minor int) bool {
if v, err := GetKernelVersion(); err != nil {
- logrus.Warnf("error getting kernel version: %s", err)
+ logrus.Warnf("Error getting kernel version: %s", err)
} else {
if CompareKernelVersion(*v, VersionInfo{Kernel: k, Major: major, Minor: minor}) < 0 {
return false
diff --git a/vendor/github.com/containers/storage/pkg/system/syscall_unix.go b/vendor/github.com/containers/storage/pkg/system/syscall_unix.go
index 49dbdd378..1bb852d11 100644
--- a/vendor/github.com/containers/storage/pkg/system/syscall_unix.go
+++ b/vendor/github.com/containers/storage/pkg/system/syscall_unix.go
@@ -1,8 +1,11 @@
-// +build linux freebsd
+// +build linux freebsd darwin
package system
-import "golang.org/x/sys/unix"
+import (
+ "github.com/pkg/errors"
+ "golang.org/x/sys/unix"
+)
// Unmount is a platform-specific helper function to call
// the unmount syscall.
@@ -15,3 +18,8 @@ func Unmount(dest string) error {
func CommandLineToArgv(commandLine string) ([]string, error) {
return []string{commandLine}, nil
}
+
+// IsEBUSY checks if the specified error is EBUSY.
+func IsEBUSY(err error) bool {
+ return errors.Is(err, unix.EBUSY)
+}
diff --git a/vendor/github.com/containers/storage/pkg/system/syscall_windows.go b/vendor/github.com/containers/storage/pkg/system/syscall_windows.go
index 23e9b207c..f4d8692cd 100644
--- a/vendor/github.com/containers/storage/pkg/system/syscall_windows.go
+++ b/vendor/github.com/containers/storage/pkg/system/syscall_windows.go
@@ -120,3 +120,8 @@ func HasWin32KSupport() bool {
// APIs.
return ntuserApiset.Load() == nil
}
+
+// IsEBUSY checks if the specified error is EBUSY.
+func IsEBUSY(err error) bool {
+ return false
+}
diff --git a/vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go b/vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go
index 26cd8504c..674e0a0ba 100644
--- a/vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go
+++ b/vendor/github.com/containers/storage/pkg/tarlog/tarlogger.go
@@ -34,7 +34,7 @@ func NewLogger(logger func(*tar.Header)) (io.WriteCloser, error) {
}
// Make sure to avoid writes after the reader has been closed.
if err := reader.Close(); err != nil {
- logrus.Errorf("error closing tarlogger reader: %v", err)
+ logrus.Errorf("Closing tarlogger reader: %v", err)
}
// Unblock the Close().
t.closeMutex.Unlock()
diff --git a/vendor/github.com/containers/storage/pkg/unshare/unshare_linux.go b/vendor/github.com/containers/storage/pkg/unshare/unshare_linux.go
index 96b857543..6d351ce80 100644
--- a/vendor/github.com/containers/storage/pkg/unshare/unshare_linux.go
+++ b/vendor/github.com/containers/storage/pkg/unshare/unshare_linux.go
@@ -154,7 +154,7 @@ func (c *Cmd) Start() error {
pidString := ""
b := new(bytes.Buffer)
if _, err := io.Copy(b, pidRead); err != nil {
- return errors.Wrapf(err, "error reading child PID")
+ return errors.Wrapf(err, "Reading child PID")
}
pidString = b.String()
pid, err := strconv.Atoi(pidString)
@@ -188,8 +188,8 @@ func (c *Cmd) Start() error {
if len(c.UidMappings) == 0 || len(c.GidMappings) == 0 {
uidmap, gidmap, err := GetHostIDMappings("")
if err != nil {
- fmt.Fprintf(continueWrite, "error reading ID mappings in parent: %v", err)
- return errors.Wrapf(err, "error reading ID mappings in parent")
+ fmt.Fprintf(continueWrite, "Reading ID mappings in parent: %v", err)
+ return errors.Wrapf(err, "Reading ID mappings in parent")
}
if len(c.UidMappings) == 0 {
c.UidMappings = uidmap
@@ -222,8 +222,8 @@ func (c *Cmd) Start() error {
if err == nil {
gidmapSet = true
} else {
- logrus.Warnf("error running newgidmap: %v: %s", err, g.String())
- logrus.Warnf("falling back to single mapping")
+ logrus.Warnf("Error running newgidmap: %v: %s", err, g.String())
+ logrus.Warnf("Falling back to single mapping")
g.Reset()
g.Write([]byte(fmt.Sprintf("0 %d 1\n", os.Getegid())))
}
@@ -271,8 +271,8 @@ func (c *Cmd) Start() error {
if err == nil {
uidmapSet = true
} else {
- logrus.Warnf("error running newuidmap: %v: %s", err, u.String())
- logrus.Warnf("falling back to single mapping")
+ logrus.Warnf("Error running newuidmap: %v: %s", err, u.String())
+ logrus.Warnf("Falling back to single mapping")
u.Reset()
u.Write([]byte(fmt.Sprintf("0 %d 1\n", os.Geteuid())))
}
@@ -407,7 +407,7 @@ func MaybeReexecUsingUserNamespace(evenForRoot bool) {
// ID and a range size.
uidmap, gidmap, err = GetSubIDMappings(me.Username, me.Username)
if err != nil {
- logrus.Warnf("error reading allowed ID mappings: %v", err)
+ logrus.Warnf("Reading allowed ID mappings: %v", err)
}
if len(uidmap) == 0 {
logrus.Warnf("Found no UID ranges set aside for user %q in /etc/subuid.", me.Username)
@@ -434,13 +434,13 @@ func MaybeReexecUsingUserNamespace(evenForRoot bool) {
// If we have CAP_SYS_ADMIN, then we don't need to create a new namespace in order to be able
// to use unshare(), so don't bother creating a new user namespace at this point.
capabilities, err := capability.NewPid(0)
- bailOnError(err, "error reading the current capabilities sets")
+ bailOnError(err, "Reading the current capabilities sets")
if capabilities.Get(capability.EFFECTIVE, capability.CAP_SYS_ADMIN) {
return
}
// Read the set of ID mappings that we're currently using.
uidmap, gidmap, err = GetHostIDMappings("")
- bailOnError(err, "error reading current ID mappings")
+ bailOnError(err, "Reading current ID mappings")
// Just reuse them.
for i := range uidmap {
uidmap[i].HostID = uidmap[i].ContainerID
@@ -463,7 +463,7 @@ func MaybeReexecUsingUserNamespace(evenForRoot bool) {
if _, present := os.LookupEnv("BUILDAH_ISOLATION"); !present {
if err = os.Setenv("BUILDAH_ISOLATION", "rootless"); err != nil {
if err := os.Setenv("BUILDAH_ISOLATION", "rootless"); err != nil {
- logrus.Errorf("error setting BUILDAH_ISOLATION=rootless in environment: %v", err)
+ logrus.Errorf("Setting BUILDAH_ISOLATION=rootless in environment: %v", err)
os.Exit(1)
}
}
@@ -483,7 +483,7 @@ func MaybeReexecUsingUserNamespace(evenForRoot bool) {
cmd.GidMappingsEnableSetgroups = true
// Finish up.
- logrus.Debugf("running %+v with environment %+v, UID map %+v, and GID map %+v", cmd.Cmd.Args, os.Environ(), cmd.UidMappings, cmd.GidMappings)
+ logrus.Debugf("Running %+v with environment %+v, UID map %+v, and GID map %+v", cmd.Cmd.Args, os.Environ(), cmd.UidMappings, cmd.GidMappings)
ExecRunnable(cmd, nil)
}
@@ -512,7 +512,7 @@ func ExecRunnable(cmd Runnable, cleanup func()) {
}
}
logrus.Errorf("%v", err)
- logrus.Errorf("(unable to determine exit status)")
+ logrus.Errorf("(Unable to determine exit status)")
exit(1)
}
exit(0)
@@ -523,7 +523,7 @@ func getHostIDMappings(path string) ([]specs.LinuxIDMapping, error) {
var mappings []specs.LinuxIDMapping
f, err := os.Open(path)
if err != nil {
- return nil, errors.Wrapf(err, "error reading ID mappings from %q", path)
+ return nil, errors.Wrapf(err, "Reading ID mappings from %q", path)
}
defer f.Close()
scanner := bufio.NewScanner(f)
@@ -571,7 +571,7 @@ func GetHostIDMappings(pid string) ([]specs.LinuxIDMapping, []specs.LinuxIDMappi
func GetSubIDMappings(user, group string) ([]specs.LinuxIDMapping, []specs.LinuxIDMapping, error) {
mappings, err := idtools.NewIDMappings(user, group)
if err != nil {
- return nil, nil, errors.Wrapf(err, "error reading subuid mappings for user %q and subgid mappings for group %q", user, group)
+ return nil, nil, errors.Wrapf(err, "Reading subuid mappings for user %q and subgid mappings for group %q", user, group)
}
var uidmap, gidmap []specs.LinuxIDMapping
for _, m := range mappings.UIDs() {
diff --git a/vendor/github.com/containers/storage/store.go b/vendor/github.com/containers/storage/store.go
index 8d6f2c4d7..169c7d151 100644
--- a/vendor/github.com/containers/storage/store.go
+++ b/vendor/github.com/containers/storage/store.go
@@ -23,6 +23,7 @@ import (
"github.com/containers/storage/pkg/parsers"
"github.com/containers/storage/pkg/stringid"
"github.com/containers/storage/pkg/stringutils"
+ "github.com/containers/storage/pkg/system"
"github.com/containers/storage/types"
"github.com/hashicorp/go-multierror"
digest "github.com/opencontainers/go-digest"
@@ -1131,10 +1132,6 @@ func (s *store) imageTopLayerForMapping(image *Image, ristore ROImageStore, crea
if options.HostGIDMapping && len(layer.GIDMap) != 0 {
return false
}
- // If we don't care about the mapping, it's fine.
- if len(options.UIDMap) == 0 && len(options.GIDMap) == 0 {
- return true
- }
// Compare the maps.
return reflect.DeepEqual(layer.UIDMap, options.UIDMap) && reflect.DeepEqual(layer.GIDMap, options.GIDMap)
}
@@ -2502,7 +2499,15 @@ func (s *store) DeleteContainer(id string) error {
gcpath := filepath.Join(s.GraphRoot(), middleDir, container.ID)
wg.Add(1)
go func() {
- errChan <- os.RemoveAll(gcpath)
+ var err error
+ for attempts := 0; attempts < 50; attempts++ {
+ err = os.RemoveAll(gcpath)
+ if err == nil || !system.IsEBUSY(err) {
+ break
+ }
+ time.Sleep(time.Millisecond * 100)
+ }
+ errChan <- err
wg.Done()
}()
diff --git a/vendor/github.com/containers/storage/types/utils.go b/vendor/github.com/containers/storage/types/utils.go
index b7ab07342..4dd1a786e 100644
--- a/vendor/github.com/containers/storage/types/utils.go
+++ b/vendor/github.com/containers/storage/types/utils.go
@@ -87,7 +87,7 @@ func getRootlessRuntimeDirIsolated(env rootlessRuntimeDirEnvironment) (string, e
if tmpPerUserDir != "" {
if _, err := env.systemLstat(tmpPerUserDir); os.IsNotExist(err) {
if err := os.Mkdir(tmpPerUserDir, 0700); err != nil {
- logrus.Errorf("failed to create temp directory for user: %v", err)
+ logrus.Errorf("Failed to create temp directory for user: %v", err)
} else {
return tmpPerUserDir, nil
}
diff --git a/vendor/github.com/containers/storage/userns.go b/vendor/github.com/containers/storage/userns.go
index 3ada41f73..523c92dc8 100644
--- a/vendor/github.com/containers/storage/userns.go
+++ b/vendor/github.com/containers/storage/userns.go
@@ -43,7 +43,7 @@ func getAdditionalSubIDs(username string) (*idSet, *idSet, error) {
}
mappings, err := idtools.NewIDMappings(username, username)
if err != nil {
- logrus.Errorf("cannot find mappings for user %q: %v", username, err)
+ logrus.Errorf("Cannot find mappings for user %q: %v", username, err)
} else {
uids = getHostIDs(mappings.UIDs())
gids = getHostIDs(mappings.GIDs())
diff --git a/vendor/github.com/json-iterator/go/README.md b/vendor/github.com/json-iterator/go/README.md
index 52b111d5f..c589addf9 100644
--- a/vendor/github.com/json-iterator/go/README.md
+++ b/vendor/github.com/json-iterator/go/README.md
@@ -8,8 +8,6 @@
A high-performance 100% compatible drop-in replacement of "encoding/json"
-You can also use thrift like JSON using [thrift-iterator](https://github.com/thrift-iterator/go)
-
# Benchmark
![benchmark](http://jsoniter.com/benchmarks/go-benchmark.png)
diff --git a/vendor/github.com/json-iterator/go/go.mod b/vendor/github.com/json-iterator/go/go.mod
index e05c42ff5..e817cccbf 100644
--- a/vendor/github.com/json-iterator/go/go.mod
+++ b/vendor/github.com/json-iterator/go/go.mod
@@ -6,6 +6,6 @@ require (
github.com/davecgh/go-spew v1.1.1
github.com/google/gofuzz v1.0.0
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421
- github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742
+ github.com/modern-go/reflect2 v1.0.2
github.com/stretchr/testify v1.3.0
)
diff --git a/vendor/github.com/json-iterator/go/go.sum b/vendor/github.com/json-iterator/go/go.sum
index be00a6df9..4b7bb8a29 100644
--- a/vendor/github.com/json-iterator/go/go.sum
+++ b/vendor/github.com/json-iterator/go/go.sum
@@ -5,11 +5,10 @@ github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
-github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
diff --git a/vendor/github.com/juju/ansiterm/LICENSE b/vendor/github.com/juju/ansiterm/LICENSE
deleted file mode 100644
index ade9307b3..000000000
--- a/vendor/github.com/juju/ansiterm/LICENSE
+++ /dev/null
@@ -1,191 +0,0 @@
-All files in this repository are licensed as follows. If you contribute
-to this repository, it is assumed that you license your contribution
-under the same license unless you state otherwise.
-
-All files Copyright (C) 2015 Canonical Ltd. unless otherwise specified in the file.
-
-This software is licensed under the LGPLv3, included below.
-
-As a special exception to the GNU Lesser General Public License version 3
-("LGPL3"), the copyright holders of this Library give you permission to
-convey to a third party a Combined Work that links statically or dynamically
-to this Library without providing any Minimal Corresponding Source or
-Minimal Application Code as set out in 4d or providing the installation
-information set out in section 4e, provided that you comply with the other
-provisions of LGPL3 and provided that you meet, for the Application the
-terms and conditions of the license(s) which apply to the Application.
-
-Except as stated in this special exception, the provisions of LGPL3 will
-continue to comply in full to this Library. If you modify this Library, you
-may apply this exception to your version of this Library, but you are not
-obliged to do so. If you do not wish to do so, delete this exception
-statement from your version. This exception does not (and cannot) modify any
-license terms which apply to the Application, with which you must still
-comply.
-
-
- GNU LESSER GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-
- This version of the GNU Lesser General Public License incorporates
-the terms and conditions of version 3 of the GNU General Public
-License, supplemented by the additional permissions listed below.
-
- 0. Additional Definitions.
-
- As used herein, "this License" refers to version 3 of the GNU Lesser
-General Public License, and the "GNU GPL" refers to version 3 of the GNU
-General Public License.
-
- "The Library" refers to a covered work governed by this License,
-other than an Application or a Combined Work as defined below.
-
- An "Application" is any work that makes use of an interface provided
-by the Library, but which is not otherwise based on the Library.
-Defining a subclass of a class defined by the Library is deemed a mode
-of using an interface provided by the Library.
-
- A "Combined Work" is a work produced by combining or linking an
-Application with the Library. The particular version of the Library
-with which the Combined Work was made is also called the "Linked
-Version".
-
- The "Minimal Corresponding Source" for a Combined Work means the
-Corresponding Source for the Combined Work, excluding any source code
-for portions of the Combined Work that, considered in isolation, are
-based on the Application, and not on the Linked Version.
-
- The "Corresponding Application Code" for a Combined Work means the
-object code and/or source code for the Application, including any data
-and utility programs needed for reproducing the Combined Work from the
-Application, but excluding the System Libraries of the Combined Work.
-
- 1. Exception to Section 3 of the GNU GPL.
-
- You may convey a covered work under sections 3 and 4 of this License
-without being bound by section 3 of the GNU GPL.
-
- 2. Conveying Modified Versions.
-
- If you modify a copy of the Library, and, in your modifications, a
-facility refers to a function or data to be supplied by an Application
-that uses the facility (other than as an argument passed when the
-facility is invoked), then you may convey a copy of the modified
-version:
-
- a) under this License, provided that you make a good faith effort to
- ensure that, in the event an Application does not supply the
- function or data, the facility still operates, and performs
- whatever part of its purpose remains meaningful, or
-
- b) under the GNU GPL, with none of the additional permissions of
- this License applicable to that copy.
-
- 3. Object Code Incorporating Material from Library Header Files.
-
- The object code form of an Application may incorporate material from
-a header file that is part of the Library. You may convey such object
-code under terms of your choice, provided that, if the incorporated
-material is not limited to numerical parameters, data structure
-layouts and accessors, or small macros, inline functions and templates
-(ten or fewer lines in length), you do both of the following:
-
- a) Give prominent notice with each copy of the object code that the
- Library is used in it and that the Library and its use are
- covered by this License.
-
- b) Accompany the object code with a copy of the GNU GPL and this license
- document.
-
- 4. Combined Works.
-
- You may convey a Combined Work under terms of your choice that,
-taken together, effectively do not restrict modification of the
-portions of the Library contained in the Combined Work and reverse
-engineering for debugging such modifications, if you also do each of
-the following:
-
- a) Give prominent notice with each copy of the Combined Work that
- the Library is used in it and that the Library and its use are
- covered by this License.
-
- b) Accompany the Combined Work with a copy of the GNU GPL and this license
- document.
-
- c) For a Combined Work that displays copyright notices during
- execution, include the copyright notice for the Library among
- these notices, as well as a reference directing the user to the
- copies of the GNU GPL and this license document.
-
- d) Do one of the following:
-
- 0) Convey the Minimal Corresponding Source under the terms of this
- License, and the Corresponding Application Code in a form
- suitable for, and under terms that permit, the user to
- recombine or relink the Application with a modified version of
- the Linked Version to produce a modified Combined Work, in the
- manner specified by section 6 of the GNU GPL for conveying
- Corresponding Source.
-
- 1) Use a suitable shared library mechanism for linking with the
- Library. A suitable mechanism is one that (a) uses at run time
- a copy of the Library already present on the user's computer
- system, and (b) will operate properly with a modified version
- of the Library that is interface-compatible with the Linked
- Version.
-
- e) Provide Installation Information, but only if you would otherwise
- be required to provide such information under section 6 of the
- GNU GPL, and only to the extent that such information is
- necessary to install and execute a modified version of the
- Combined Work produced by recombining or relinking the
- Application with a modified version of the Linked Version. (If
- you use option 4d0, the Installation Information must accompany
- the Minimal Corresponding Source and Corresponding Application
- Code. If you use option 4d1, you must provide the Installation
- Information in the manner specified by section 6 of the GNU GPL
- for conveying Corresponding Source.)
-
- 5. Combined Libraries.
-
- You may place library facilities that are a work based on the
-Library side by side in a single library together with other library
-facilities that are not Applications and are not covered by this
-License, and convey such a combined library under terms of your
-choice, if you do both of the following:
-
- a) Accompany the combined library with a copy of the same work based
- on the Library, uncombined with any other library facilities,
- conveyed under the terms of this License.
-
- b) Give prominent notice with the combined library that part of it
- is a work based on the Library, and explaining where to find the
- accompanying uncombined form of the same work.
-
- 6. Revised Versions of the GNU Lesser General Public License.
-
- The Free Software Foundation may publish revised and/or new versions
-of the GNU Lesser General Public License from time to time. Such new
-versions will be similar in spirit to the present version, but may
-differ in detail to address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Library as you received it specifies that a certain numbered version
-of the GNU Lesser General Public License "or any later version"
-applies to it, you have the option of following the terms and
-conditions either of that published version or of any later version
-published by the Free Software Foundation. If the Library as you
-received it does not specify a version number of the GNU Lesser
-General Public License, you may choose any version of the GNU Lesser
-General Public License ever published by the Free Software Foundation.
-
- If the Library as you received it specifies that a proxy can decide
-whether future versions of the GNU Lesser General Public License shall
-apply, that proxy's public statement of acceptance of any version is
-permanent authorization for you to choose that version for the
-Library.
diff --git a/vendor/github.com/juju/ansiterm/Makefile b/vendor/github.com/juju/ansiterm/Makefile
deleted file mode 100644
index 212fdcbe5..000000000
--- a/vendor/github.com/juju/ansiterm/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright 2016 Canonical Ltd.
-# Licensed under the LGPLv3, see LICENCE file for details.
-
-default: check
-
-check:
- go test
-
-docs:
- godoc2md github.com/juju/ansiterm > README.md
- sed -i 's|\[godoc-link-here\]|[![GoDoc](https://godoc.org/github.com/juju/ansiterm?status.svg)](https://godoc.org/github.com/juju/ansiterm)|' README.md
-
-
-.PHONY: default check docs
diff --git a/vendor/github.com/juju/ansiterm/README.md b/vendor/github.com/juju/ansiterm/README.md
deleted file mode 100644
index 567438721..000000000
--- a/vendor/github.com/juju/ansiterm/README.md
+++ /dev/null
@@ -1,323 +0,0 @@
-
-# ansiterm
- import "github.com/juju/ansiterm"
-
-Package ansiterm provides a Writer that writes out the ANSI escape
-codes for color and styles.
-
-
-
-
-
-
-
-## type Color
-``` go
-type Color int
-```
-Color represents one of the standard 16 ANSI colors.
-
-
-
-``` go
-const (
- Default Color
- Black
- Red
- Green
- Yellow
- Blue
- Magenta
- Cyan
- Gray
- DarkGray
- BrightRed
- BrightGreen
- BrightYellow
- BrightBlue
- BrightMagenta
- BrightCyan
- White
-)
-```
-
-
-
-
-
-
-
-
-### func (Color) String
-``` go
-func (c Color) String() string
-```
-String returns the name of the color.
-
-
-
-## type Context
-``` go
-type Context struct {
- Foreground Color
- Background Color
- Styles []Style
-}
-```
-Context provides a way to specify both foreground and background colors
-along with other styles and write text to a Writer with those colors and
-styles.
-
-
-
-
-
-
-
-
-
-### func Background
-``` go
-func Background(color Color) *Context
-```
-Background is a convenience function that creates a Context with the
-specified color as the background color.
-
-
-### func Foreground
-``` go
-func Foreground(color Color) *Context
-```
-Foreground is a convenience function that creates a Context with the
-specified color as the foreground color.
-
-
-### func Styles
-``` go
-func Styles(styles ...Style) *Context
-```
-Styles is a convenience function that creates a Context with the
-specified styles set.
-
-
-
-
-### func (\*Context) Fprint
-``` go
-func (c *Context) Fprint(w sgrWriter, args ...interface{})
-```
-Fprint will set the sgr values of the writer to the specified foreground,
-background and styles, then formats using the default formats for its
-operands and writes to w. Spaces are added between operands when neither is
-a string. It returns the number of bytes written and any write error
-encountered.
-
-
-
-### func (\*Context) Fprintf
-``` go
-func (c *Context) Fprintf(w sgrWriter, format string, args ...interface{})
-```
-Fprintf will set the sgr values of the writer to the specified
-foreground, background and styles, then write the formatted string,
-then reset the writer.
-
-
-
-### func (\*Context) SetBackground
-``` go
-func (c *Context) SetBackground(color Color) *Context
-```
-SetBackground sets the background to the specified color.
-
-
-
-### func (\*Context) SetForeground
-``` go
-func (c *Context) SetForeground(color Color) *Context
-```
-SetForeground sets the foreground to the specified color.
-
-
-
-### func (\*Context) SetStyle
-``` go
-func (c *Context) SetStyle(styles ...Style) *Context
-```
-SetStyle replaces the styles with the new values.
-
-
-
-## type Style
-``` go
-type Style int
-```
-
-
-``` go
-const (
- Bold Style
- Faint
- Italic
- Underline
- Blink
- Reverse
- Strikethrough
- Conceal
-)
-```
-
-
-
-
-
-
-
-
-### func (Style) String
-``` go
-func (s Style) String() string
-```
-
-
-## type TabWriter
-``` go
-type TabWriter struct {
- Writer
- // contains filtered or unexported fields
-}
-```
-TabWriter is a filter that inserts padding around tab-delimited
-columns in its input to align them in the output.
-
-It also setting of colors and styles over and above the standard
-tabwriter package.
-
-
-
-
-
-
-
-
-
-### func NewTabWriter
-``` go
-func NewTabWriter(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *TabWriter
-```
-NewTabWriter returns a writer that is able to set colors and styels.
-The ansi escape codes are stripped for width calculations.
-
-
-
-
-### func (\*TabWriter) Flush
-``` go
-func (t *TabWriter) Flush() error
-```
-Flush should be called after the last call to Write to ensure
-that any data buffered in the Writer is written to output. Any
-incomplete escape sequence at the end is considered
-complete for formatting purposes.
-
-
-
-### func (\*TabWriter) Init
-``` go
-func (t *TabWriter) Init(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *TabWriter
-```
-A Writer must be initialized with a call to Init. The first parameter (output)
-specifies the filter output. The remaining parameters control the formatting:
-
-
- minwidth minimal cell width including any padding
- tabwidth width of tab characters (equivalent number of spaces)
- padding padding added to a cell before computing its width
- padchar ASCII char used for padding
- if padchar == '\t', the Writer will assume that the
- width of a '\t' in the formatted output is tabwidth,
- and cells are left-aligned independent of align_left
- (for correct-looking results, tabwidth must correspond
- to the tab width in the viewer displaying the result)
- flags formatting control
-
-
-
-## type Writer
-``` go
-type Writer struct {
- io.Writer
- // contains filtered or unexported fields
-}
-```
-Writer allows colors and styles to be specified. If the io.Writer
-is not a terminal capable of color, all attempts to set colors or
-styles are no-ops.
-
-
-
-
-
-
-
-
-
-### func NewWriter
-``` go
-func NewWriter(w io.Writer) *Writer
-```
-NewWriter returns a Writer that allows the caller to specify colors and
-styles. If the io.Writer is not a terminal capable of color, all attempts
-to set colors or styles are no-ops.
-
-
-
-
-### func (\*Writer) ClearStyle
-``` go
-func (w *Writer) ClearStyle(s Style)
-```
-ClearStyle clears the text style.
-
-
-
-### func (\*Writer) Reset
-``` go
-func (w *Writer) Reset()
-```
-Reset returns the default foreground and background colors with no styles.
-
-
-
-### func (\*Writer) SetBackground
-``` go
-func (w *Writer) SetBackground(c Color)
-```
-SetBackground sets the background color.
-
-
-
-### func (\*Writer) SetForeground
-``` go
-func (w *Writer) SetForeground(c Color)
-```
-SetForeground sets the foreground color.
-
-
-
-### func (\*Writer) SetStyle
-``` go
-func (w *Writer) SetStyle(s Style)
-```
-SetStyle sets the text style.
-
-
-
-
-
-
-
-
-
-- - -
-Generated by [godoc2md](http://godoc.org/github.com/davecheney/godoc2md) \ No newline at end of file
diff --git a/vendor/github.com/juju/ansiterm/attribute.go b/vendor/github.com/juju/ansiterm/attribute.go
deleted file mode 100644
index f2daa4813..000000000
--- a/vendor/github.com/juju/ansiterm/attribute.go
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2016 Canonical Ltd.
-// Licensed under the LGPLv3, see LICENCE file for details.
-
-package ansiterm
-
-import (
- "fmt"
- "sort"
- "strings"
-)
-
-type attribute int
-
-const (
- unknownAttribute attribute = -1
- reset attribute = 0
-)
-
-// sgr returns the escape sequence for the Select Graphic Rendition
-// for the attribute.
-func (a attribute) sgr() string {
- if a < 0 {
- return ""
- }
- return fmt.Sprintf("\x1b[%dm", a)
-}
-
-type attributes []attribute
-
-func (a attributes) Len() int { return len(a) }
-func (a attributes) Less(i, j int) bool { return a[i] < a[j] }
-func (a attributes) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
-
-// sgr returns the combined escape sequence for the Select Graphic Rendition
-// for the sequence of attributes.
-func (a attributes) sgr() string {
- switch len(a) {
- case 0:
- return ""
- case 1:
- return a[0].sgr()
- default:
- sort.Sort(a)
- var values []string
- for _, attr := range a {
- values = append(values, fmt.Sprint(attr))
- }
- return fmt.Sprintf("\x1b[%sm", strings.Join(values, ";"))
- }
-}
diff --git a/vendor/github.com/juju/ansiterm/color.go b/vendor/github.com/juju/ansiterm/color.go
deleted file mode 100644
index 0a97de31e..000000000
--- a/vendor/github.com/juju/ansiterm/color.go
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2016 Canonical Ltd.
-// Licensed under the LGPLv3, see LICENCE file for details.
-
-package ansiterm
-
-const (
- _ Color = iota
- Default
- Black
- Red
- Green
- Yellow
- Blue
- Magenta
- Cyan
- Gray
- DarkGray
- BrightRed
- BrightGreen
- BrightYellow
- BrightBlue
- BrightMagenta
- BrightCyan
- White
-)
-
-// Color represents one of the standard 16 ANSI colors.
-type Color int
-
-// String returns the name of the color.
-func (c Color) String() string {
- switch c {
- case Default:
- return "default"
- case Black:
- return "black"
- case Red:
- return "red"
- case Green:
- return "green"
- case Yellow:
- return "yellow"
- case Blue:
- return "blue"
- case Magenta:
- return "magenta"
- case Cyan:
- return "cyan"
- case Gray:
- return "gray"
- case DarkGray:
- return "darkgray"
- case BrightRed:
- return "brightred"
- case BrightGreen:
- return "brightgreen"
- case BrightYellow:
- return "brightyellow"
- case BrightBlue:
- return "brightblue"
- case BrightMagenta:
- return "brightmagenta"
- case BrightCyan:
- return "brightcyan"
- case White:
- return "white"
- default:
- return ""
- }
-}
-
-func (c Color) foreground() attribute {
- switch c {
- case Default:
- return 39
- case Black:
- return 30
- case Red:
- return 31
- case Green:
- return 32
- case Yellow:
- return 33
- case Blue:
- return 34
- case Magenta:
- return 35
- case Cyan:
- return 36
- case Gray:
- return 37
- case DarkGray:
- return 90
- case BrightRed:
- return 91
- case BrightGreen:
- return 92
- case BrightYellow:
- return 93
- case BrightBlue:
- return 94
- case BrightMagenta:
- return 95
- case BrightCyan:
- return 96
- case White:
- return 97
- default:
- return unknownAttribute
- }
-}
-
-func (c Color) background() attribute {
- value := c.foreground()
- if value != unknownAttribute {
- return value + 10
- }
- return value
-}
diff --git a/vendor/github.com/juju/ansiterm/context.go b/vendor/github.com/juju/ansiterm/context.go
deleted file mode 100644
index e61a867ff..000000000
--- a/vendor/github.com/juju/ansiterm/context.go
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2016 Canonical Ltd.
-// Licensed under the LGPLv3, see LICENCE file for details.
-
-package ansiterm
-
-import (
- "fmt"
- "io"
-)
-
-// Context provides a way to specify both foreground and background colors
-// along with other styles and write text to a Writer with those colors and
-// styles.
-type Context struct {
- Foreground Color
- Background Color
- Styles []Style
-}
-
-// Foreground is a convenience function that creates a Context with the
-// specified color as the foreground color.
-func Foreground(color Color) *Context {
- return &Context{Foreground: color}
-}
-
-// Background is a convenience function that creates a Context with the
-// specified color as the background color.
-func Background(color Color) *Context {
- return &Context{Background: color}
-}
-
-// Styles is a convenience function that creates a Context with the
-// specified styles set.
-func Styles(styles ...Style) *Context {
- return &Context{Styles: styles}
-}
-
-// SetForeground sets the foreground to the specified color.
-func (c *Context) SetForeground(color Color) *Context {
- c.Foreground = color
- return c
-}
-
-// SetBackground sets the background to the specified color.
-func (c *Context) SetBackground(color Color) *Context {
- c.Background = color
- return c
-}
-
-// SetStyle replaces the styles with the new values.
-func (c *Context) SetStyle(styles ...Style) *Context {
- c.Styles = styles
- return c
-}
-
-type sgrWriter interface {
- io.Writer
- writeSGR(value sgr)
-}
-
-// Fprintf will set the sgr values of the writer to the specified
-// foreground, background and styles, then write the formatted string,
-// then reset the writer.
-func (c *Context) Fprintf(w sgrWriter, format string, args ...interface{}) {
- w.writeSGR(c)
- fmt.Fprintf(w, format, args...)
- w.writeSGR(reset)
-}
-
-// Fprint will set the sgr values of the writer to the specified foreground,
-// background and styles, then formats using the default formats for its
-// operands and writes to w. Spaces are added between operands when neither is
-// a string. It returns the number of bytes written and any write error
-// encountered.
-func (c *Context) Fprint(w sgrWriter, args ...interface{}) {
- w.writeSGR(c)
- fmt.Fprint(w, args...)
- w.writeSGR(reset)
-}
-
-func (c *Context) sgr() string {
- var values attributes
- if foreground := c.Foreground.foreground(); foreground != unknownAttribute {
- values = append(values, foreground)
- }
- if background := c.Background.background(); background != unknownAttribute {
- values = append(values, background)
- }
- for _, style := range c.Styles {
- if value := style.enable(); value != unknownAttribute {
- values = append(values, value)
- }
- }
- return values.sgr()
-}
diff --git a/vendor/github.com/juju/ansiterm/doc.go b/vendor/github.com/juju/ansiterm/doc.go
deleted file mode 100644
index 782700779..000000000
--- a/vendor/github.com/juju/ansiterm/doc.go
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright 2016 Canonical Ltd.
-// Licensed under the LGPLv3, see LICENCE file for details.
-
-// Package ansiterm provides a Writer that writes out the ANSI escape
-// codes for color and styles.
-package ansiterm
diff --git a/vendor/github.com/juju/ansiterm/style.go b/vendor/github.com/juju/ansiterm/style.go
deleted file mode 100644
index 0be42da56..000000000
--- a/vendor/github.com/juju/ansiterm/style.go
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2016 Canonical Ltd.
-// Licensed under the LGPLv3, see LICENCE file for details.
-
-package ansiterm
-
-const (
- _ Style = iota
- Bold
- Faint
- Italic
- Underline
- Blink
- Reverse
- Strikethrough
- Conceal
-)
-
-type Style int
-
-func (s Style) String() string {
- switch s {
- case Bold:
- return "bold"
- case Faint:
- return "faint"
- case Italic:
- return "italic"
- case Underline:
- return "underline"
- case Blink:
- return "blink"
- case Reverse:
- return "reverse"
- case Strikethrough:
- return "strikethrough"
- case Conceal:
- return "conceal"
- default:
- return ""
- }
-}
-
-func (s Style) enable() attribute {
- switch s {
- case Bold:
- return 1
- case Faint:
- return 2
- case Italic:
- return 3
- case Underline:
- return 4
- case Blink:
- return 5
- case Reverse:
- return 7
- case Conceal:
- return 8
- case Strikethrough:
- return 9
- default:
- return unknownAttribute
- }
-}
-
-func (s Style) disable() attribute {
- value := s.enable()
- if value != unknownAttribute {
- return value + 20
- }
- return value
-}
diff --git a/vendor/github.com/juju/ansiterm/tabwriter.go b/vendor/github.com/juju/ansiterm/tabwriter.go
deleted file mode 100644
index 1ff6faaaf..000000000
--- a/vendor/github.com/juju/ansiterm/tabwriter.go
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2016 Canonical Ltd.
-// Licensed under the LGPLv3, see LICENCE file for details.
-
-package ansiterm
-
-import (
- "io"
-
- "github.com/juju/ansiterm/tabwriter"
-)
-
-// NewTabWriter returns a writer that is able to set colors and styels.
-// The ansi escape codes are stripped for width calculations.
-func NewTabWriter(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *TabWriter {
- return new(TabWriter).Init(output, minwidth, tabwidth, padding, padchar, flags)
-}
-
-// TabWriter is a filter that inserts padding around tab-delimited
-// columns in its input to align them in the output.
-//
-// It also setting of colors and styles over and above the standard
-// tabwriter package.
-type TabWriter struct {
- Writer
- tw tabwriter.Writer
-}
-
-// Flush should be called after the last call to Write to ensure
-// that any data buffered in the Writer is written to output. Any
-// incomplete escape sequence at the end is considered
-// complete for formatting purposes.
-//
-func (t *TabWriter) Flush() error {
- return t.tw.Flush()
-}
-
-// SetColumnAlignRight will mark a particular column as align right.
-// This is reset on the next flush.
-func (t *TabWriter) SetColumnAlignRight(column int) {
- t.tw.SetColumnAlignRight(column)
-}
-
-// A Writer must be initialized with a call to Init. The first parameter (output)
-// specifies the filter output. The remaining parameters control the formatting:
-//
-// minwidth minimal cell width including any padding
-// tabwidth width of tab characters (equivalent number of spaces)
-// padding padding added to a cell before computing its width
-// padchar ASCII char used for padding
-// if padchar == '\t', the Writer will assume that the
-// width of a '\t' in the formatted output is tabwidth,
-// and cells are left-aligned independent of align_left
-// (for correct-looking results, tabwidth must correspond
-// to the tab width in the viewer displaying the result)
-// flags formatting control
-//
-func (t *TabWriter) Init(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *TabWriter {
- writer, colorCapable := colorEnabledWriter(output)
- t.Writer = Writer{
- Writer: t.tw.Init(writer, minwidth, tabwidth, padding, padchar, flags),
- noColor: !colorCapable,
- }
- return t
-}
diff --git a/vendor/github.com/juju/ansiterm/tabwriter/LICENSE b/vendor/github.com/juju/ansiterm/tabwriter/LICENSE
deleted file mode 100644
index 744875676..000000000
--- a/vendor/github.com/juju/ansiterm/tabwriter/LICENSE
+++ /dev/null
@@ -1,27 +0,0 @@
-Copyright (c) 2012 The Go Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/juju/ansiterm/tabwriter/tabwriter.go b/vendor/github.com/juju/ansiterm/tabwriter/tabwriter.go
deleted file mode 100644
index 98949d036..000000000
--- a/vendor/github.com/juju/ansiterm/tabwriter/tabwriter.go
+++ /dev/null
@@ -1,587 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file is mostly a copy of the go standard library text/tabwriter. With
-// the additional stripping of ansi control characters for width calculations.
-
-// Package tabwriter implements a write filter (tabwriter.Writer) that
-// translates tabbed columns in input into properly aligned text.
-//
-// The package is using the Elastic Tabstops algorithm described at
-// http://nickgravgaard.com/elastictabstops/index.html.
-//
-package tabwriter
-
-import (
- "bytes"
- "io"
- "unicode/utf8"
-
- "github.com/lunixbochs/vtclean"
-)
-
-// ----------------------------------------------------------------------------
-// Filter implementation
-
-// A cell represents a segment of text terminated by tabs or line breaks.
-// The text itself is stored in a separate buffer; cell only describes the
-// segment's size in bytes, its width in runes, and whether it's an htab
-// ('\t') terminated cell.
-//
-type cell struct {
- size int // cell size in bytes
- width int // cell width in runes
- htab bool // true if the cell is terminated by an htab ('\t')
-}
-
-// A Writer is a filter that inserts padding around tab-delimited
-// columns in its input to align them in the output.
-//
-// The Writer treats incoming bytes as UTF-8 encoded text consisting
-// of cells terminated by (horizontal or vertical) tabs or line
-// breaks (newline or formfeed characters). Cells in adjacent lines
-// constitute a column. The Writer inserts padding as needed to
-// make all cells in a column have the same width, effectively
-// aligning the columns. It assumes that all characters have the
-// same width except for tabs for which a tabwidth must be specified.
-// Note that cells are tab-terminated, not tab-separated: trailing
-// non-tab text at the end of a line does not form a column cell.
-//
-// The Writer assumes that all Unicode code points have the same width;
-// this may not be true in some fonts.
-//
-// If DiscardEmptyColumns is set, empty columns that are terminated
-// entirely by vertical (or "soft") tabs are discarded. Columns
-// terminated by horizontal (or "hard") tabs are not affected by
-// this flag.
-//
-// If a Writer is configured to filter HTML, HTML tags and entities
-// are passed through. The widths of tags and entities are
-// assumed to be zero (tags) and one (entities) for formatting purposes.
-//
-// A segment of text may be escaped by bracketing it with Escape
-// characters. The tabwriter passes escaped text segments through
-// unchanged. In particular, it does not interpret any tabs or line
-// breaks within the segment. If the StripEscape flag is set, the
-// Escape characters are stripped from the output; otherwise they
-// are passed through as well. For the purpose of formatting, the
-// width of the escaped text is always computed excluding the Escape
-// characters.
-//
-// The formfeed character ('\f') acts like a newline but it also
-// terminates all columns in the current line (effectively calling
-// Flush). Cells in the next line start new columns. Unless found
-// inside an HTML tag or inside an escaped text segment, formfeed
-// characters appear as newlines in the output.
-//
-// The Writer must buffer input internally, because proper spacing
-// of one line may depend on the cells in future lines. Clients must
-// call Flush when done calling Write.
-//
-type Writer struct {
- // configuration
- output io.Writer
- minwidth int
- tabwidth int
- padding int
- padbytes [8]byte
- flags uint
-
- // current state
- buf bytes.Buffer // collected text excluding tabs or line breaks
- pos int // buffer position up to which cell.width of incomplete cell has been computed
- cell cell // current incomplete cell; cell.width is up to buf[pos] excluding ignored sections
- endChar byte // terminating char of escaped sequence (Escape for escapes, '>', ';' for HTML tags/entities, or 0)
- lines [][]cell // list of lines; each line is a list of cells
- widths []int // list of column widths in runes - re-used during formatting
- alignment map[int]uint // column alignment
-}
-
-func (b *Writer) addLine() { b.lines = append(b.lines, []cell{}) }
-
-// Reset the current state.
-func (b *Writer) reset() {
- b.buf.Reset()
- b.pos = 0
- b.cell = cell{}
- b.endChar = 0
- b.lines = b.lines[0:0]
- b.widths = b.widths[0:0]
- b.alignment = make(map[int]uint)
- b.addLine()
-}
-
-// Internal representation (current state):
-//
-// - all text written is appended to buf; tabs and line breaks are stripped away
-// - at any given time there is a (possibly empty) incomplete cell at the end
-// (the cell starts after a tab or line break)
-// - cell.size is the number of bytes belonging to the cell so far
-// - cell.width is text width in runes of that cell from the start of the cell to
-// position pos; html tags and entities are excluded from this width if html
-// filtering is enabled
-// - the sizes and widths of processed text are kept in the lines list
-// which contains a list of cells for each line
-// - the widths list is a temporary list with current widths used during
-// formatting; it is kept in Writer because it's re-used
-//
-// |<---------- size ---------->|
-// | |
-// |<- width ->|<- ignored ->| |
-// | | | |
-// [---processed---tab------------<tag>...</tag>...]
-// ^ ^ ^
-// | | |
-// buf start of incomplete cell pos
-
-// Formatting can be controlled with these flags.
-const (
- // Ignore html tags and treat entities (starting with '&'
- // and ending in ';') as single characters (width = 1).
- FilterHTML uint = 1 << iota
-
- // Strip Escape characters bracketing escaped text segments
- // instead of passing them through unchanged with the text.
- StripEscape
-
- // Force right-alignment of cell content.
- // Default is left-alignment.
- AlignRight
-
- // Handle empty columns as if they were not present in
- // the input in the first place.
- DiscardEmptyColumns
-
- // Always use tabs for indentation columns (i.e., padding of
- // leading empty cells on the left) independent of padchar.
- TabIndent
-
- // Print a vertical bar ('|') between columns (after formatting).
- // Discarded columns appear as zero-width columns ("||").
- Debug
-)
-
-// A Writer must be initialized with a call to Init. The first parameter (output)
-// specifies the filter output. The remaining parameters control the formatting:
-//
-// minwidth minimal cell width including any padding
-// tabwidth width of tab characters (equivalent number of spaces)
-// padding padding added to a cell before computing its width
-// padchar ASCII char used for padding
-// if padchar == '\t', the Writer will assume that the
-// width of a '\t' in the formatted output is tabwidth,
-// and cells are left-aligned independent of align_left
-// (for correct-looking results, tabwidth must correspond
-// to the tab width in the viewer displaying the result)
-// flags formatting control
-//
-func (b *Writer) Init(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *Writer {
- if minwidth < 0 || tabwidth < 0 || padding < 0 {
- panic("negative minwidth, tabwidth, or padding")
- }
- b.output = output
- b.minwidth = minwidth
- b.tabwidth = tabwidth
- b.padding = padding
- for i := range b.padbytes {
- b.padbytes[i] = padchar
- }
- if padchar == '\t' {
- // tab padding enforces left-alignment
- flags &^= AlignRight
- }
- b.flags = flags
-
- b.reset()
-
- return b
-}
-
-// debugging support (keep code around)
-func (b *Writer) dump() {
- pos := 0
- for i, line := range b.lines {
- print("(", i, ") ")
- for _, c := range line {
- print("[", string(b.buf.Bytes()[pos:pos+c.size]), "]")
- pos += c.size
- }
- print("\n")
- }
- print("\n")
-}
-
-// local error wrapper so we can distinguish errors we want to return
-// as errors from genuine panics (which we don't want to return as errors)
-type osError struct {
- err error
-}
-
-func (b *Writer) write0(buf []byte) {
- n, err := b.output.Write(buf)
- if n != len(buf) && err == nil {
- err = io.ErrShortWrite
- }
- if err != nil {
- panic(osError{err})
- }
-}
-
-func (b *Writer) writeN(src []byte, n int) {
- for n > len(src) {
- b.write0(src)
- n -= len(src)
- }
- b.write0(src[0:n])
-}
-
-var (
- newline = []byte{'\n'}
- tabs = []byte("\t\t\t\t\t\t\t\t")
-)
-
-func (b *Writer) writePadding(textw, cellw int, useTabs bool) {
- if b.padbytes[0] == '\t' || useTabs {
- // padding is done with tabs
- if b.tabwidth == 0 {
- return // tabs have no width - can't do any padding
- }
- // make cellw the smallest multiple of b.tabwidth
- cellw = (cellw + b.tabwidth - 1) / b.tabwidth * b.tabwidth
- n := cellw - textw // amount of padding
- if n < 0 {
- panic("internal error")
- }
- b.writeN(tabs, (n+b.tabwidth-1)/b.tabwidth)
- return
- }
-
- // padding is done with non-tab characters
- b.writeN(b.padbytes[0:], cellw-textw)
-}
-
-var vbar = []byte{'|'}
-
-func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int) {
- pos = pos0
- for i := line0; i < line1; i++ {
- line := b.lines[i]
-
- // if TabIndent is set, use tabs to pad leading empty cells
- useTabs := b.flags&TabIndent != 0
-
- for j, c := range line {
- if j > 0 && b.flags&Debug != 0 {
- // indicate column break
- b.write0(vbar)
- }
-
- if c.size == 0 {
- // empty cell
- if j < len(b.widths) {
- b.writePadding(c.width, b.widths[j], useTabs)
- }
- } else {
- // non-empty cell
- useTabs = false
- alignColumnRight := b.alignment[j] == AlignRight
- if (b.flags&AlignRight == 0) && !alignColumnRight { // align left
- b.write0(b.buf.Bytes()[pos : pos+c.size])
- pos += c.size
- if j < len(b.widths) {
- b.writePadding(c.width, b.widths[j], false)
- }
- } else if alignColumnRight && j < len(b.widths) {
- // just this column
- internalSize := b.widths[j] - b.padding
- if j < len(b.widths) {
- b.writePadding(c.width, internalSize, false)
- }
- b.write0(b.buf.Bytes()[pos : pos+c.size])
- if b.padding > 0 {
- b.writePadding(0, b.padding, false)
- }
- pos += c.size
- } else { // align right
- if j < len(b.widths) {
- b.writePadding(c.width, b.widths[j], false)
- }
- b.write0(b.buf.Bytes()[pos : pos+c.size])
- pos += c.size
- }
- }
- }
-
- if i+1 == len(b.lines) {
- // last buffered line - we don't have a newline, so just write
- // any outstanding buffered data
- b.write0(b.buf.Bytes()[pos : pos+b.cell.size])
- pos += b.cell.size
- } else {
- // not the last line - write newline
- b.write0(newline)
- }
- }
- return
-}
-
-// Format the text between line0 and line1 (excluding line1); pos
-// is the buffer position corresponding to the beginning of line0.
-// Returns the buffer position corresponding to the beginning of
-// line1 and an error, if any.
-//
-func (b *Writer) format(pos0 int, line0, line1 int) (pos int) {
- pos = pos0
- column := len(b.widths)
- for this := line0; this < line1; this++ {
- line := b.lines[this]
-
- if column < len(line)-1 {
- // cell exists in this column => this line
- // has more cells than the previous line
- // (the last cell per line is ignored because cells are
- // tab-terminated; the last cell per line describes the
- // text before the newline/formfeed and does not belong
- // to a column)
-
- // print unprinted lines until beginning of block
- pos = b.writeLines(pos, line0, this)
- line0 = this
-
- // column block begin
- width := b.minwidth // minimal column width
- discardable := true // true if all cells in this column are empty and "soft"
- for ; this < line1; this++ {
- line = b.lines[this]
- if column < len(line)-1 {
- // cell exists in this column
- c := line[column]
- // update width
- if w := c.width + b.padding; w > width {
- width = w
- }
- // update discardable
- if c.width > 0 || c.htab {
- discardable = false
- }
- } else {
- break
- }
- }
- // column block end
-
- // discard empty columns if necessary
- if discardable && b.flags&DiscardEmptyColumns != 0 {
- width = 0
- }
-
- // format and print all columns to the right of this column
- // (we know the widths of this column and all columns to the left)
- b.widths = append(b.widths, width) // push width
- pos = b.format(pos, line0, this)
- b.widths = b.widths[0 : len(b.widths)-1] // pop width
- line0 = this
- }
- }
-
- // print unprinted lines until end
- return b.writeLines(pos, line0, line1)
-}
-
-// Append text to current cell.
-func (b *Writer) append(text []byte) {
- b.buf.Write(text)
- b.cell.size += len(text)
-}
-
-// Update the cell width.
-func (b *Writer) updateWidth() {
- // ---- Changes here -----
- newChars := b.buf.Bytes()[b.pos:b.buf.Len()]
- cleaned := vtclean.Clean(string(newChars), false) // false to strip colors
- b.cell.width += utf8.RuneCount([]byte(cleaned))
- // --- end of changes ----
- b.pos = b.buf.Len()
-}
-
-// To escape a text segment, bracket it with Escape characters.
-// For instance, the tab in this string "Ignore this tab: \xff\t\xff"
-// does not terminate a cell and constitutes a single character of
-// width one for formatting purposes.
-//
-// The value 0xff was chosen because it cannot appear in a valid UTF-8 sequence.
-//
-const Escape = '\xff'
-
-// Start escaped mode.
-func (b *Writer) startEscape(ch byte) {
- switch ch {
- case Escape:
- b.endChar = Escape
- case '<':
- b.endChar = '>'
- case '&':
- b.endChar = ';'
- }
-}
-
-// Terminate escaped mode. If the escaped text was an HTML tag, its width
-// is assumed to be zero for formatting purposes; if it was an HTML entity,
-// its width is assumed to be one. In all other cases, the width is the
-// unicode width of the text.
-//
-func (b *Writer) endEscape() {
- switch b.endChar {
- case Escape:
- b.updateWidth()
- if b.flags&StripEscape == 0 {
- b.cell.width -= 2 // don't count the Escape chars
- }
- case '>': // tag of zero width
- case ';':
- b.cell.width++ // entity, count as one rune
- }
- b.pos = b.buf.Len()
- b.endChar = 0
-}
-
-// Terminate the current cell by adding it to the list of cells of the
-// current line. Returns the number of cells in that line.
-//
-func (b *Writer) terminateCell(htab bool) int {
- b.cell.htab = htab
- line := &b.lines[len(b.lines)-1]
- *line = append(*line, b.cell)
- b.cell = cell{}
- return len(*line)
-}
-
-func handlePanic(err *error, op string) {
- if e := recover(); e != nil {
- if nerr, ok := e.(osError); ok {
- *err = nerr.err
- return
- }
- panic("tabwriter: panic during " + op)
- }
-}
-
-// Flush should be called after the last call to Write to ensure
-// that any data buffered in the Writer is written to output. Any
-// incomplete escape sequence at the end is considered
-// complete for formatting purposes.
-//
-func (b *Writer) Flush() (err error) {
- defer b.reset() // even in the presence of errors
- defer handlePanic(&err, "Flush")
-
- // add current cell if not empty
- if b.cell.size > 0 {
- if b.endChar != 0 {
- // inside escape - terminate it even if incomplete
- b.endEscape()
- }
- b.terminateCell(false)
- }
-
- // format contents of buffer
- b.format(0, 0, len(b.lines))
-
- return
-}
-
-var hbar = []byte("---\n")
-
-// SetColumnAlignRight will mark a particular column as align right.
-// This is reset on the next flush.
-func (b *Writer) SetColumnAlignRight(column int) {
- b.alignment[column] = AlignRight
-}
-
-// Write writes buf to the writer b.
-// The only errors returned are ones encountered
-// while writing to the underlying output stream.
-//
-func (b *Writer) Write(buf []byte) (n int, err error) {
- defer handlePanic(&err, "Write")
-
- // split text into cells
- n = 0
- for i, ch := range buf {
- if b.endChar == 0 {
- // outside escape
- switch ch {
- case '\t', '\v', '\n', '\f':
- // end of cell
- b.append(buf[n:i])
- b.updateWidth()
- n = i + 1 // ch consumed
- ncells := b.terminateCell(ch == '\t')
- if ch == '\n' || ch == '\f' {
- // terminate line
- b.addLine()
- if ch == '\f' || ncells == 1 {
- // A '\f' always forces a flush. Otherwise, if the previous
- // line has only one cell which does not have an impact on
- // the formatting of the following lines (the last cell per
- // line is ignored by format()), thus we can flush the
- // Writer contents.
- if err = b.Flush(); err != nil {
- return
- }
- if ch == '\f' && b.flags&Debug != 0 {
- // indicate section break
- b.write0(hbar)
- }
- }
- }
-
- case Escape:
- // start of escaped sequence
- b.append(buf[n:i])
- b.updateWidth()
- n = i
- if b.flags&StripEscape != 0 {
- n++ // strip Escape
- }
- b.startEscape(Escape)
-
- case '<', '&':
- // possibly an html tag/entity
- if b.flags&FilterHTML != 0 {
- // begin of tag/entity
- b.append(buf[n:i])
- b.updateWidth()
- n = i
- b.startEscape(ch)
- }
- }
-
- } else {
- // inside escape
- if ch == b.endChar {
- // end of tag/entity
- j := i + 1
- if ch == Escape && b.flags&StripEscape != 0 {
- j = i // strip Escape
- }
- b.append(buf[n:j])
- n = i + 1 // ch consumed
- b.endEscape()
- }
- }
- }
-
- // append leftover text
- b.append(buf[n:])
- n = len(buf)
- return
-}
-
-// NewWriter allocates and initializes a new tabwriter.Writer.
-// The parameters are the same as for the Init function.
-//
-func NewWriter(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *Writer {
- return new(Writer).Init(output, minwidth, tabwidth, padding, padchar, flags)
-}
diff --git a/vendor/github.com/juju/ansiterm/terminal.go b/vendor/github.com/juju/ansiterm/terminal.go
deleted file mode 100644
index 96fd11c51..000000000
--- a/vendor/github.com/juju/ansiterm/terminal.go
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2016 Canonical Ltd.
-// Licensed under the LGPLv3, see LICENCE file for details.
-
-package ansiterm
-
-import (
- "io"
- "os"
-
- "github.com/mattn/go-colorable"
- "github.com/mattn/go-isatty"
-)
-
-// colorEnabledWriter returns a writer that can handle the ansi color codes
-// and true if the writer passed in is a terminal capable of color. If the
-// TERM environment variable is set to "dumb", the terminal is not considered
-// color capable.
-func colorEnabledWriter(w io.Writer) (io.Writer, bool) {
- f, ok := w.(*os.File)
- if !ok {
- return w, false
- }
- // Check the TERM environment variable specifically
- // to check for "dumb" terminals.
- if os.Getenv("TERM") == "dumb" {
- return w, false
- }
- if !isatty.IsTerminal(f.Fd()) {
- return w, false
- }
- return colorable.NewColorable(f), true
-}
diff --git a/vendor/github.com/juju/ansiterm/writer.go b/vendor/github.com/juju/ansiterm/writer.go
deleted file mode 100644
index 32437bb27..000000000
--- a/vendor/github.com/juju/ansiterm/writer.go
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2016 Canonical Ltd.
-// Licensed under the LGPLv3, see LICENCE file for details.
-
-package ansiterm
-
-import (
- "fmt"
- "io"
-)
-
-// Writer allows colors and styles to be specified. If the io.Writer
-// is not a terminal capable of color, all attempts to set colors or
-// styles are no-ops.
-type Writer struct {
- io.Writer
-
- noColor bool
-}
-
-// NewWriter returns a Writer that allows the caller to specify colors and
-// styles. If the io.Writer is not a terminal capable of color, all attempts
-// to set colors or styles are no-ops.
-func NewWriter(w io.Writer) *Writer {
- writer, colorCapable := colorEnabledWriter(w)
- return &Writer{
- Writer: writer,
- noColor: !colorCapable,
- }
-}
-
-// SetColorCapable forces the writer to either write the ANSI escape color
-// if capable is true, or to not write them if capable is false.
-func (w *Writer) SetColorCapable(capable bool) {
- w.noColor = !capable
-}
-
-// SetForeground sets the foreground color.
-func (w *Writer) SetForeground(c Color) {
- w.writeSGR(c.foreground())
-}
-
-// SetBackground sets the background color.
-func (w *Writer) SetBackground(c Color) {
- w.writeSGR(c.background())
-}
-
-// SetStyle sets the text style.
-func (w *Writer) SetStyle(s Style) {
- w.writeSGR(s.enable())
-}
-
-// ClearStyle clears the text style.
-func (w *Writer) ClearStyle(s Style) {
- w.writeSGR(s.disable())
-}
-
-// Reset returns the default foreground and background colors with no styles.
-func (w *Writer) Reset() {
- w.writeSGR(reset)
-}
-
-type sgr interface {
- // sgr returns the combined escape sequence for the Select Graphic Rendition.
- sgr() string
-}
-
-// writeSGR takes the appropriate integer SGR parameters
-// and writes out the ANIS escape code.
-func (w *Writer) writeSGR(value sgr) {
- if w.noColor {
- return
- }
- fmt.Fprint(w, value.sgr())
-}
diff --git a/vendor/github.com/klauspost/compress/LICENSE b/vendor/github.com/klauspost/compress/LICENSE
index 6cd1e9627..87d557477 100644
--- a/vendor/github.com/klauspost/compress/LICENSE
+++ b/vendor/github.com/klauspost/compress/LICENSE
@@ -290,3 +290,15 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-----------------
+
+Files: s2/cmd/internal/filepathx/*
+
+Copyright 2016 The filepathx Authors
+
+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/klauspost/compress/README.md b/vendor/github.com/klauspost/compress/README.md
index 235dc7cc6..3429879eb 100644
--- a/vendor/github.com/klauspost/compress/README.md
+++ b/vendor/github.com/klauspost/compress/README.md
@@ -17,12 +17,17 @@ This package provides various compression algorithms.
# changelog
+* Aug 30, 2021 (v1.13.5)
+ * gz/zlib/flate: Alias stdlib errors [#425](https://github.com/klauspost/compress/pull/425)
+ * s2: Add block support to commandline tools [#413](https://github.com/klauspost/compress/pull/413)
+ * zstd: pooledZipWriter should return Writers to the same pool [#426](https://github.com/klauspost/compress/pull/426)
+ * Removed golang/snappy as external dependency for tests [#421](https://github.com/klauspost/compress/pull/421)
+
* Aug 12, 2021 (v1.13.4)
* Add [snappy replacement package](https://github.com/klauspost/compress/tree/master/snappy).
* zstd: Fix incorrect encoding in "best" mode [#415](https://github.com/klauspost/compress/pull/415)
* Aug 3, 2021 (v1.13.3)
-
* zstd: Improve Best compression [#404](https://github.com/klauspost/compress/pull/404)
* zstd: Fix WriteTo error forwarding [#411](https://github.com/klauspost/compress/pull/411)
* gzhttp: Return http.HandlerFunc instead of http.Handler. Unlikely breaking change. [#406](https://github.com/klauspost/compress/pull/406)
@@ -31,7 +36,6 @@ This package provides various compression algorithms.
* zstd: use SpeedBestCompression for level >= 10 [#410](https://github.com/klauspost/compress/pull/410)
* Jun 14, 2021 (v1.13.1)
-
* s2: Add full Snappy output support [#396](https://github.com/klauspost/compress/pull/396)
* zstd: Add configurable [Decoder window](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithDecoderMaxWindow) size [#394](https://github.com/klauspost/compress/pull/394)
* gzhttp: Add header to skip compression [#389](https://github.com/klauspost/compress/pull/389)
@@ -64,6 +68,9 @@ This package provides various compression algorithms.
* zstd: Reduce memory usage further when using [WithLowerEncoderMem](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithLowerEncoderMem) [#346](https://github.com/klauspost/compress/pull/346)
* s2: Fix potential problem with amd64 assembly and profilers [#349](https://github.com/klauspost/compress/pull/349)
+<details>
+ <summary>See changes prior to v1.12.1</summary>
+
* Mar 26, 2021 (v1.11.13)
* zstd: Big speedup on small dictionary encodes [#344](https://github.com/klauspost/compress/pull/344) [#345](https://github.com/klauspost/compress/pull/345)
* zstd: Add [WithLowerEncoderMem](https://pkg.go.dev/github.com/klauspost/compress/zstd#WithLowerEncoderMem) encoder option [#336](https://github.com/klauspost/compress/pull/336)
@@ -118,6 +125,7 @@ This package provides various compression algorithms.
* zstd: Add experimental compression [dictionaries](https://github.com/klauspost/compress/tree/master/zstd#dictionaries) [#281](https://github.com/klauspost/compress/pull/281)
* zstd: Fix mixed Write and ReadFrom calls [#282](https://github.com/klauspost/compress/pull/282)
* inflate/gz: Limit variable shifts, ~5% faster decompression [#274](https://github.com/klauspost/compress/pull/274)
+</details>
<details>
<summary>See changes prior to v1.11.0</summary>
diff --git a/vendor/github.com/klauspost/compress/flate/fast_encoder.go b/vendor/github.com/klauspost/compress/flate/fast_encoder.go
index 347ac2c90..a746eb733 100644
--- a/vendor/github.com/klauspost/compress/flate/fast_encoder.go
+++ b/vendor/github.com/klauspost/compress/flate/fast_encoder.go
@@ -215,24 +215,15 @@ func (e *fastGen) Reset() {
func matchLen(a, b []byte) int {
b = b[:len(a)]
var checked int
- if len(a) >= 4 {
- // Try 4 bytes first
- if diff := binary.LittleEndian.Uint32(a) ^ binary.LittleEndian.Uint32(b); diff != 0 {
- return bits.TrailingZeros32(diff) >> 3
- }
- // Switch to 8 byte matching.
- checked = 4
- a = a[4:]
- b = b[4:]
- for len(a) >= 8 {
- b = b[:len(a)]
- if diff := binary.LittleEndian.Uint64(a) ^ binary.LittleEndian.Uint64(b); diff != 0 {
- return checked + (bits.TrailingZeros64(diff) >> 3)
- }
- checked += 8
- a = a[8:]
- b = b[8:]
+
+ for len(a) >= 8 {
+ b = b[:len(a)]
+ if diff := binary.LittleEndian.Uint64(a) ^ binary.LittleEndian.Uint64(b); diff != 0 {
+ return checked + (bits.TrailingZeros64(diff) >> 3)
}
+ checked += 8
+ a = a[8:]
+ b = b[8:]
}
b = b[:len(a)]
for i := range a {
diff --git a/vendor/github.com/klauspost/compress/huff0/decompress.go b/vendor/github.com/klauspost/compress/huff0/decompress.go
index 41703bba4..9b7cc8e97 100644
--- a/vendor/github.com/klauspost/compress/huff0/decompress.go
+++ b/vendor/github.com/klauspost/compress/huff0/decompress.go
@@ -344,35 +344,241 @@ func (d *Decoder) decompress1X8Bit(dst, src []byte) ([]byte, error) {
var buf [256]byte
var off uint8
- shift := (8 - d.actualTableLog) & 7
-
- //fmt.Printf("mask: %b, tl:%d\n", mask, d.actualTableLog)
- for br.off >= 4 {
- br.fillFast()
- v := dt[br.peekByteFast()>>shift]
- br.advance(uint8(v.entry))
- buf[off+0] = uint8(v.entry >> 8)
-
- v = dt[br.peekByteFast()>>shift]
- br.advance(uint8(v.entry))
- buf[off+1] = uint8(v.entry >> 8)
-
- v = dt[br.peekByteFast()>>shift]
- br.advance(uint8(v.entry))
- buf[off+2] = uint8(v.entry >> 8)
-
- v = dt[br.peekByteFast()>>shift]
- br.advance(uint8(v.entry))
- buf[off+3] = uint8(v.entry >> 8)
-
- off += 4
- if off == 0 {
- if len(dst)+256 > maxDecodedSize {
- br.close()
- return nil, ErrMaxDecodedSizeExceeded
+ switch d.actualTableLog {
+ case 8:
+ const shift = 8 - 8
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+ case 7:
+ const shift = 8 - 7
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+ case 6:
+ const shift = 8 - 6
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+ case 5:
+ const shift = 8 - 5
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+ case 4:
+ const shift = 8 - 4
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+ case 3:
+ const shift = 8 - 3
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+ case 2:
+ const shift = 8 - 2
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
+ }
+ }
+ case 1:
+ const shift = 8 - 1
+ for br.off >= 4 {
+ br.fillFast()
+ v := dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+0] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+1] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+2] = uint8(v.entry >> 8)
+
+ v = dt[uint8(br.value>>(56+shift))]
+ br.advance(uint8(v.entry))
+ buf[off+3] = uint8(v.entry >> 8)
+
+ off += 4
+ if off == 0 {
+ if len(dst)+256 > maxDecodedSize {
+ br.close()
+ return nil, ErrMaxDecodedSizeExceeded
+ }
+ dst = append(dst, buf[:]...)
}
- dst = append(dst, buf[:]...)
}
+ default:
+ return nil, fmt.Errorf("invalid tablelog: %d", d.actualTableLog)
}
if len(dst)+int(off) > maxDecodedSize {
@@ -383,6 +589,8 @@ func (d *Decoder) decompress1X8Bit(dst, src []byte) ([]byte, error) {
// br < 4, so uint8 is fine
bitsLeft := int8(uint8(br.off)*8 + (64 - br.bitsRead))
+ shift := (8 - d.actualTableLog) & 7
+
for bitsLeft > 0 {
if br.bitsRead >= 64-8 {
for br.off > 0 {
@@ -423,24 +631,24 @@ func (d *Decoder) decompress1X8BitExactly(dst, src []byte) ([]byte, error) {
var buf [256]byte
var off uint8
- const shift = 0
+ const shift = 56
//fmt.Printf("mask: %b, tl:%d\n", mask, d.actualTableLog)
for br.off >= 4 {
br.fillFast()
- v := dt[br.peekByteFast()>>shift]
+ v := dt[uint8(br.value>>shift)]
br.advance(uint8(v.entry))
buf[off+0] = uint8(v.entry >> 8)
- v = dt[br.peekByteFast()>>shift]
+ v = dt[uint8(br.value>>shift)]
br.advance(uint8(v.entry))
buf[off+1] = uint8(v.entry >> 8)
- v = dt[br.peekByteFast()>>shift]
+ v = dt[uint8(br.value>>shift)]
br.advance(uint8(v.entry))
buf[off+2] = uint8(v.entry >> 8)
- v = dt[br.peekByteFast()>>shift]
+ v = dt[uint8(br.value>>shift)]
br.advance(uint8(v.entry))
buf[off+3] = uint8(v.entry >> 8)
@@ -474,7 +682,7 @@ func (d *Decoder) decompress1X8BitExactly(dst, src []byte) ([]byte, error) {
br.close()
return nil, ErrMaxDecodedSizeExceeded
}
- v := dt[br.peekByteFast()>>shift]
+ v := dt[br.peekByteFast()]
nBits := uint8(v.entry)
br.advance(nBits)
bitsLeft -= int8(nBits)
@@ -709,7 +917,6 @@ func (d *Decoder) decompress4X8bit(dst, src []byte) ([]byte, error) {
shift := (8 - d.actualTableLog) & 7
const tlSize = 1 << 8
- const tlMask = tlSize - 1
single := d.dt.single[:tlSize]
// Use temp table to avoid bound checks/append penalty.
diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash.go b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash.go
index 426b9cac7..2c112a0ab 100644
--- a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash.go
+++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash.go
@@ -195,7 +195,6 @@ func (d *Digest) UnmarshalBinary(b []byte) error {
b, d.v4 = consumeUint64(b)
b, d.total = consumeUint64(b)
copy(d.mem[:], b)
- b = b[len(d.mem):]
d.n = int(d.total % uint64(len(d.mem)))
return nil
}
diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.go b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.go
index 3ddbd5c0b..0ae847f75 100644
--- a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.go
+++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.go
@@ -9,4 +9,4 @@ package xxhash
func Sum64(b []byte) uint64
//go:noescape
-func writeBlocks(*Digest, []byte) int
+func writeBlocks(d *Digest, b []byte) int
diff --git a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.s b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.s
index 2c9c5357a..be8db5bf7 100644
--- a/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.s
+++ b/vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.s
@@ -6,7 +6,7 @@
// Register allocation:
// AX h
-// CX pointer to advance through b
+// SI pointer to advance through b
// DX n
// BX loop end
// R8 v1, k1
@@ -16,39 +16,39 @@
// R12 tmp
// R13 prime1v
// R14 prime2v
-// R15 prime4v
+// DI prime4v
-// round reads from and advances the buffer pointer in CX.
+// round reads from and advances the buffer pointer in SI.
// It assumes that R13 has prime1v and R14 has prime2v.
#define round(r) \
- MOVQ (CX), R12 \
- ADDQ $8, CX \
+ MOVQ (SI), R12 \
+ ADDQ $8, SI \
IMULQ R14, R12 \
ADDQ R12, r \
ROLQ $31, r \
IMULQ R13, r
// mergeRound applies a merge round on the two registers acc and val.
-// It assumes that R13 has prime1v, R14 has prime2v, and R15 has prime4v.
+// It assumes that R13 has prime1v, R14 has prime2v, and DI has prime4v.
#define mergeRound(acc, val) \
IMULQ R14, val \
ROLQ $31, val \
IMULQ R13, val \
XORQ val, acc \
IMULQ R13, acc \
- ADDQ R15, acc
+ ADDQ DI, acc
// func Sum64(b []byte) uint64
TEXT ·Sum64(SB), NOSPLIT, $0-32
// Load fixed primes.
MOVQ ·prime1v(SB), R13
MOVQ ·prime2v(SB), R14
- MOVQ ·prime4v(SB), R15
+ MOVQ ·prime4v(SB), DI
// Load slice.
- MOVQ b_base+0(FP), CX
+ MOVQ b_base+0(FP), SI
MOVQ b_len+8(FP), DX
- LEAQ (CX)(DX*1), BX
+ LEAQ (SI)(DX*1), BX
// The first loop limit will be len(b)-32.
SUBQ $32, BX
@@ -65,14 +65,14 @@ TEXT ·Sum64(SB), NOSPLIT, $0-32
XORQ R11, R11
SUBQ R13, R11
- // Loop until CX > BX.
+ // Loop until SI > BX.
blockLoop:
round(R8)
round(R9)
round(R10)
round(R11)
- CMPQ CX, BX
+ CMPQ SI, BX
JLE blockLoop
MOVQ R8, AX
@@ -100,16 +100,16 @@ noBlocks:
afterBlocks:
ADDQ DX, AX
- // Right now BX has len(b)-32, and we want to loop until CX > len(b)-8.
+ // Right now BX has len(b)-32, and we want to loop until SI > len(b)-8.
ADDQ $24, BX
- CMPQ CX, BX
+ CMPQ SI, BX
JG fourByte
wordLoop:
// Calculate k1.
- MOVQ (CX), R8
- ADDQ $8, CX
+ MOVQ (SI), R8
+ ADDQ $8, SI
IMULQ R14, R8
ROLQ $31, R8
IMULQ R13, R8
@@ -117,18 +117,18 @@ wordLoop:
XORQ R8, AX
ROLQ $27, AX
IMULQ R13, AX
- ADDQ R15, AX
+ ADDQ DI, AX
- CMPQ CX, BX
+ CMPQ SI, BX
JLE wordLoop
fourByte:
ADDQ $4, BX
- CMPQ CX, BX
+ CMPQ SI, BX
JG singles
- MOVL (CX), R8
- ADDQ $4, CX
+ MOVL (SI), R8
+ ADDQ $4, SI
IMULQ R13, R8
XORQ R8, AX
@@ -138,19 +138,19 @@ fourByte:
singles:
ADDQ $4, BX
- CMPQ CX, BX
+ CMPQ SI, BX
JGE finalize
singlesLoop:
- MOVBQZX (CX), R12
- ADDQ $1, CX
+ MOVBQZX (SI), R12
+ ADDQ $1, SI
IMULQ ·prime5v(SB), R12
XORQ R12, AX
ROLQ $11, AX
IMULQ R13, AX
- CMPQ CX, BX
+ CMPQ SI, BX
JL singlesLoop
finalize:
@@ -179,13 +179,13 @@ TEXT ·writeBlocks(SB), NOSPLIT, $0-40
MOVQ ·prime2v(SB), R14
// Load slice.
- MOVQ arg1_base+8(FP), CX
- MOVQ arg1_len+16(FP), DX
- LEAQ (CX)(DX*1), BX
+ MOVQ b_base+8(FP), SI
+ MOVQ b_len+16(FP), DX
+ LEAQ (SI)(DX*1), BX
SUBQ $32, BX
// Load vN from d.
- MOVQ arg+0(FP), AX
+ MOVQ d+0(FP), AX
MOVQ 0(AX), R8 // v1
MOVQ 8(AX), R9 // v2
MOVQ 16(AX), R10 // v3
@@ -199,7 +199,7 @@ blockLoop:
round(R10)
round(R11)
- CMPQ CX, BX
+ CMPQ SI, BX
JLE blockLoop
// Copy vN back to d.
@@ -208,8 +208,8 @@ blockLoop:
MOVQ R10, 16(AX)
MOVQ R11, 24(AX)
- // The number of bytes written is CX minus the old base pointer.
- SUBQ arg1_base+8(FP), CX
- MOVQ CX, ret+32(FP)
+ // The number of bytes written is SI minus the old base pointer.
+ SUBQ b_base+8(FP), SI
+ MOVQ SI, ret+32(FP)
RET
diff --git a/vendor/github.com/lunixbochs/vtclean/.travis.yml b/vendor/github.com/lunixbochs/vtclean/.travis.yml
deleted file mode 100644
index fc0a54325..000000000
--- a/vendor/github.com/lunixbochs/vtclean/.travis.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-language: go
-sudo: false
-
-script: go test -v
-
-go:
- - 1.5
- - 1.6
- - 1.7
diff --git a/vendor/github.com/lunixbochs/vtclean/LICENSE b/vendor/github.com/lunixbochs/vtclean/LICENSE
deleted file mode 100644
index 42e82633f..000000000
--- a/vendor/github.com/lunixbochs/vtclean/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2015 Ryan Hileman
-
-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/lunixbochs/vtclean/README.md b/vendor/github.com/lunixbochs/vtclean/README.md
deleted file mode 100644
index 99910a460..000000000
--- a/vendor/github.com/lunixbochs/vtclean/README.md
+++ /dev/null
@@ -1,46 +0,0 @@
-[![Build Status](https://travis-ci.org/lunixbochs/vtclean.svg?branch=master)](https://travis-ci.org/lunixbochs/vtclean)
-
-vtclean
-----
-
-Clean up raw terminal output by stripping escape sequences, optionally preserving color.
-
-Get it: `go get github.com/lunixbochs/vtclean/vtclean`
-
-API:
-
- import "github.com/lunixbochs/vtclean"
- vtclean.Clean(line string, color bool) string
-
-Command line example:
-
- $ echo -e '\x1b[1;32mcolor example
- color forced to stop at end of line
- backspace is ba\b\bgood
- no beeps!\x07\x07' | ./vtclean -color
-
- color example
- color forced to stop at end of line
- backspace is good
- no beeps!
-
-Go example:
-
- package main
-
- import (
- "fmt"
- "github.com/lunixbochs/vtclean"
- )
-
- func main() {
- line := vtclean.Clean(
- "\033[1;32mcolor, " +
- "curs\033[Aor, " +
- "backspace\b\b\b\b\b\b\b\b\b\b\b\033[K", false)
- fmt.Println(line)
- }
-
-Output:
-
- color, cursor
diff --git a/vendor/github.com/lunixbochs/vtclean/io.go b/vendor/github.com/lunixbochs/vtclean/io.go
deleted file mode 100644
index 31be0076a..000000000
--- a/vendor/github.com/lunixbochs/vtclean/io.go
+++ /dev/null
@@ -1,93 +0,0 @@
-package vtclean
-
-import (
- "bufio"
- "bytes"
- "io"
-)
-
-type reader struct {
- io.Reader
- scanner *bufio.Scanner
- buf []byte
-
- color bool
-}
-
-func NewReader(r io.Reader, color bool) io.Reader {
- return &reader{Reader: r, color: color}
-}
-
-func (r *reader) scan() bool {
- if r.scanner == nil {
- r.scanner = bufio.NewScanner(r.Reader)
- }
- if len(r.buf) > 0 {
- return true
- }
- if r.scanner.Scan() {
- r.buf = []byte(Clean(r.scanner.Text(), r.color) + "\n")
- return true
- }
- return false
-}
-
-func (r *reader) fill(p []byte) int {
- n := len(r.buf)
- copy(p, r.buf)
- if len(p) < len(r.buf) {
- r.buf = r.buf[len(p):]
- n = len(p)
- } else {
- r.buf = nil
- }
- return n
-}
-
-func (r *reader) Read(p []byte) (int, error) {
- n := r.fill(p)
- if n < len(p) {
- if !r.scan() {
- if n == 0 {
- return 0, io.EOF
- }
- return n, nil
- }
- n += r.fill(p[n:])
- }
- return n, nil
-}
-
-type writer struct {
- io.Writer
- buf []byte
- color bool
-}
-
-func NewWriter(w io.Writer, color bool) io.WriteCloser {
- return &writer{Writer: w, color: color}
-}
-
-func (w *writer) Write(p []byte) (int, error) {
- buf := append(w.buf, p...)
- lines := bytes.Split(buf, []byte("\n"))
- if len(lines) > 0 {
- last := len(lines) - 1
- w.buf = lines[last]
- count := 0
- for _, line := range lines[:last] {
- n, err := w.Writer.Write([]byte(Clean(string(line), w.color) + "\n"))
- count += n
- if err != nil {
- return count, err
- }
- }
- }
- return len(p), nil
-}
-
-func (w *writer) Close() error {
- cl := Clean(string(w.buf), w.color)
- _, err := w.Writer.Write([]byte(cl))
- return err
-}
diff --git a/vendor/github.com/lunixbochs/vtclean/line.go b/vendor/github.com/lunixbochs/vtclean/line.go
deleted file mode 100644
index 66ee990be..000000000
--- a/vendor/github.com/lunixbochs/vtclean/line.go
+++ /dev/null
@@ -1,113 +0,0 @@
-package vtclean
-
-type char struct {
- char byte
- vt100 []byte
-}
-
-func chars(p []byte) []char {
- tmp := make([]char, len(p))
- for i, v := range p {
- tmp[i].char = v
- }
- return tmp
-}
-
-type lineEdit struct {
- buf []char
- pos, size int
- vt100 []byte
-}
-
-func newLineEdit(length int) *lineEdit {
- return &lineEdit{buf: make([]char, length)}
-}
-
-func (l *lineEdit) Vt100(p []byte) {
- l.vt100 = p
-}
-
-func (l *lineEdit) Move(x int) {
- if x < 0 && l.pos <= -x {
- l.pos = 0
- } else if x > 0 && l.pos+x > l.size {
- l.pos = l.size
- } else {
- l.pos += x
- }
-}
-
-func (l *lineEdit) MoveAbs(x int) {
- if x < l.size {
- l.pos = x
- }
-}
-
-func (l *lineEdit) Write(p []byte) {
- c := chars(p)
- if len(c) > 0 {
- c[0].vt100 = l.vt100
- l.vt100 = nil
- }
- if len(l.buf)-l.pos < len(c) {
- l.buf = append(l.buf[:l.pos], c...)
- } else {
- copy(l.buf[l.pos:], c)
- }
- l.pos += len(c)
- if l.pos > l.size {
- l.size = l.pos
- }
-}
-
-func (l *lineEdit) Insert(p []byte) {
- c := chars(p)
- if len(c) > 0 {
- c[0].vt100 = l.vt100
- l.vt100 = nil
- }
- l.size += len(c)
- c = append(c, l.buf[l.pos:]...)
- l.buf = append(l.buf[:l.pos], c...)
-}
-
-func (l *lineEdit) Delete(n int) {
- most := l.size - l.pos
- if n > most {
- n = most
- }
- copy(l.buf[l.pos:], l.buf[l.pos+n:])
- l.size -= n
-}
-
-func (l *lineEdit) Clear() {
- for i := 0; i < len(l.buf); i++ {
- l.buf[i].char = ' '
- }
-}
-func (l *lineEdit) ClearLeft() {
- for i := 0; i < l.pos+1; i++ {
- l.buf[i].char = ' '
- }
-}
-func (l *lineEdit) ClearRight() {
- l.size = l.pos
-}
-
-func (l *lineEdit) Bytes() []byte {
- length := 0
- buf := l.buf[:l.size]
- for _, v := range buf {
- length += 1 + len(v.vt100)
- }
- tmp := make([]byte, 0, length)
- for _, v := range buf {
- tmp = append(tmp, v.vt100...)
- tmp = append(tmp, v.char)
- }
- return tmp
-}
-
-func (l *lineEdit) String() string {
- return string(l.Bytes())
-}
diff --git a/vendor/github.com/lunixbochs/vtclean/vtclean.go b/vendor/github.com/lunixbochs/vtclean/vtclean.go
deleted file mode 100644
index 64fe01fdb..000000000
--- a/vendor/github.com/lunixbochs/vtclean/vtclean.go
+++ /dev/null
@@ -1,95 +0,0 @@
-package vtclean
-
-import (
- "bytes"
- "regexp"
- "strconv"
-)
-
-// regex based on ECMA-48:
-// 1. optional:
-// one of [ or ]
-// any amount of 0x30-0x3f
-// any amount of 0x20-0x2f
-// 3. exactly one 0x40-0x7e
-var vt100re = regexp.MustCompile(`^\033([\[\]]([0-9:;<=>\?]*)([!"#$%&'()*+,\-./]*))?([@A-Z\[\]^_\x60a-z{|}~])`)
-var vt100exc = regexp.MustCompile(`^\033(\[[^a-zA-Z0-9@\?]+|[\(\)]).`)
-
-// this is to handle the RGB escape generated by `tput initc 1 500 500 500`
-var vt100long = regexp.MustCompile(`^\033](\d+);([^\033]+)\033\\`)
-
-func Clean(line string, color bool) string {
- var edit = newLineEdit(len(line))
- lineb := []byte(line)
-
- hadColor := false
- for i := 0; i < len(lineb); {
- c := lineb[i]
- switch c {
- case '\r':
- edit.MoveAbs(0)
- case '\b':
- edit.Move(-1)
- case '\033':
- // set terminal title
- if bytes.HasPrefix(lineb[i:], []byte("\x1b]0;")) {
- pos := bytes.Index(lineb[i:], []byte("\a"))
- if pos != -1 {
- i += pos + 1
- continue
- }
- }
- if m := vt100long.Find(lineb[i:]); m != nil {
- i += len(m)
- } else if m := vt100exc.Find(lineb[i:]); m != nil {
- i += len(m)
- } else if m := vt100re.FindSubmatch(lineb[i:]); m != nil {
- i += len(m[0])
- num := string(m[2])
- n, err := strconv.Atoi(num)
- if err != nil || n > 10000 {
- n = 1
- }
- switch m[4][0] {
- case 'm':
- if color {
- hadColor = true
- edit.Vt100(m[0])
- }
- case '@':
- edit.Insert(bytes.Repeat([]byte{' '}, n))
- case 'G':
- edit.MoveAbs(n)
- case 'C':
- edit.Move(n)
- case 'D':
- edit.Move(-n)
- case 'P':
- edit.Delete(n)
- case 'K':
- switch num {
- case "", "0":
- edit.ClearRight()
- case "1":
- edit.ClearLeft()
- case "2":
- edit.Clear()
- }
- }
- } else {
- i += 1
- }
- continue
- default:
- if c == '\n' || c == '\t' || c >= ' ' {
- edit.Write([]byte{c})
- }
- }
- i += 1
- }
- out := edit.Bytes()
- if hadColor {
- out = append(out, []byte("\033[0m")...)
- }
- return string(out)
-}
diff --git a/vendor/github.com/manifoldco/promptui/CHANGELOG.md b/vendor/github.com/manifoldco/promptui/CHANGELOG.md
index 563e9d00a..ff30afdf0 100644
--- a/vendor/github.com/manifoldco/promptui/CHANGELOG.md
+++ b/vendor/github.com/manifoldco/promptui/CHANGELOG.md
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## Unreleased
+## [0.9.0] - 2021-10-30
+
+### Fixed
+
+- Resolve license incompatibility in tabwriter
+
+
## [0.8.0] - 2020-09-28
### Added
diff --git a/vendor/github.com/manifoldco/promptui/go.mod b/vendor/github.com/manifoldco/promptui/go.mod
index 760a44deb..a69023954 100644
--- a/vendor/github.com/manifoldco/promptui/go.mod
+++ b/vendor/github.com/manifoldco/promptui/go.mod
@@ -6,11 +6,5 @@ require (
github.com/chzyer/logex v1.1.10 // indirect
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 // indirect
- github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a
- github.com/kr/pretty v0.1.0 // indirect
- github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a // indirect
- github.com/mattn/go-colorable v0.0.9 // indirect
- github.com/mattn/go-isatty v0.0.4 // indirect
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b // indirect
- gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
)
diff --git a/vendor/github.com/manifoldco/promptui/go.sum b/vendor/github.com/manifoldco/promptui/go.sum
index be5f99025..fcb24c854 100644
--- a/vendor/github.com/manifoldco/promptui/go.sum
+++ b/vendor/github.com/manifoldco/promptui/go.sum
@@ -4,20 +4,5 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5O
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU=
-github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU=
-github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a h1:weJVJJRzAJBFRlAiJQROKQs8oC9vOxvm4rZmBBk0ONw=
-github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
-github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
-github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
-github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
-github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b h1:MQE+LT/ABUuuvEZ+YQAMSXindAdUh7slEmAkup74op4=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/vendor/github.com/manifoldco/promptui/select.go b/vendor/github.com/manifoldco/promptui/select.go
index 19b9e0c2e..b58ed9734 100644
--- a/vendor/github.com/manifoldco/promptui/select.go
+++ b/vendor/github.com/manifoldco/promptui/select.go
@@ -5,10 +5,10 @@ import (
"fmt"
"io"
"os"
+ "text/tabwriter"
"text/template"
"github.com/chzyer/readline"
- "github.com/juju/ansiterm"
"github.com/manifoldco/promptui/list"
"github.com/manifoldco/promptui/screenbuf"
)
@@ -587,7 +587,8 @@ func (s *Select) renderDetails(item interface{}) [][]byte {
}
var buf bytes.Buffer
- w := ansiterm.NewTabWriter(&buf, 0, 0, 8, ' ', 0)
+
+ w := tabwriter.NewWriter(&buf, 0, 0, 8, ' ', 0)
err := s.Templates.details.Execute(w, item)
if err != nil {
diff --git a/vendor/github.com/mattn/go-colorable/.travis.yml b/vendor/github.com/mattn/go-colorable/.travis.yml
deleted file mode 100644
index 7942c565c..000000000
--- a/vendor/github.com/mattn/go-colorable/.travis.yml
+++ /dev/null
@@ -1,15 +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-colorable/LICENSE b/vendor/github.com/mattn/go-colorable/LICENSE
deleted file mode 100644
index 91b5cef30..000000000
--- a/vendor/github.com/mattn/go-colorable/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2016 Yasuhiro Matsumoto
-
-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-colorable/README.md b/vendor/github.com/mattn/go-colorable/README.md
deleted file mode 100644
index e055952b6..000000000
--- a/vendor/github.com/mattn/go-colorable/README.md
+++ /dev/null
@@ -1,48 +0,0 @@
-# go-colorable
-
-[![Build Status](https://travis-ci.org/mattn/go-colorable.svg?branch=master)](https://travis-ci.org/mattn/go-colorable)
-[![Codecov](https://codecov.io/gh/mattn/go-colorable/branch/master/graph/badge.svg)](https://codecov.io/gh/mattn/go-colorable)
-[![GoDoc](https://godoc.org/github.com/mattn/go-colorable?status.svg)](http://godoc.org/github.com/mattn/go-colorable)
-[![Go Report Card](https://goreportcard.com/badge/mattn/go-colorable)](https://goreportcard.com/report/mattn/go-colorable)
-
-Colorable writer for windows.
-
-For example, most of logger packages doesn't show colors on windows. (I know we can do it with ansicon. But I don't want.)
-This package is possible to handle escape sequence for ansi color on windows.
-
-## Too Bad!
-
-![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/bad.png)
-
-
-## So Good!
-
-![](https://raw.githubusercontent.com/mattn/go-colorable/gh-pages/good.png)
-
-## Usage
-
-```go
-logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true})
-logrus.SetOutput(colorable.NewColorableStdout())
-
-logrus.Info("succeeded")
-logrus.Warn("not correct")
-logrus.Error("something error")
-logrus.Fatal("panic")
-```
-
-You can compile above code on non-windows OSs.
-
-## Installation
-
-```
-$ go get github.com/mattn/go-colorable
-```
-
-# License
-
-MIT
-
-# Author
-
-Yasuhiro Matsumoto (a.k.a mattn)
diff --git a/vendor/github.com/mattn/go-colorable/colorable_appengine.go b/vendor/github.com/mattn/go-colorable/colorable_appengine.go
deleted file mode 100644
index 1f7806fe1..000000000
--- a/vendor/github.com/mattn/go-colorable/colorable_appengine.go
+++ /dev/null
@@ -1,37 +0,0 @@
-// +build appengine
-
-package colorable
-
-import (
- "io"
- "os"
-
- _ "github.com/mattn/go-isatty"
-)
-
-// NewColorable returns new instance of Writer which handles escape sequence.
-func NewColorable(file *os.File) io.Writer {
- if file == nil {
- panic("nil passed instead of *os.File to NewColorable()")
- }
-
- return file
-}
-
-// NewColorableStdout returns new instance of Writer which handles escape sequence for stdout.
-func NewColorableStdout() io.Writer {
- return os.Stdout
-}
-
-// NewColorableStderr returns new instance of Writer which handles escape sequence for stderr.
-func NewColorableStderr() io.Writer {
- return os.Stderr
-}
-
-// EnableColorsStdout enable colors if possible.
-func EnableColorsStdout(enabled *bool) func() {
- if enabled != nil {
- *enabled = true
- }
- return func() {}
-}
diff --git a/vendor/github.com/mattn/go-colorable/colorable_others.go b/vendor/github.com/mattn/go-colorable/colorable_others.go
deleted file mode 100644
index 08cbd1e0f..000000000
--- a/vendor/github.com/mattn/go-colorable/colorable_others.go
+++ /dev/null
@@ -1,38 +0,0 @@
-// +build !windows
-// +build !appengine
-
-package colorable
-
-import (
- "io"
- "os"
-
- _ "github.com/mattn/go-isatty"
-)
-
-// NewColorable returns new instance of Writer which handles escape sequence.
-func NewColorable(file *os.File) io.Writer {
- if file == nil {
- panic("nil passed instead of *os.File to NewColorable()")
- }
-
- return file
-}
-
-// NewColorableStdout returns new instance of Writer which handles escape sequence for stdout.
-func NewColorableStdout() io.Writer {
- return os.Stdout
-}
-
-// NewColorableStderr returns new instance of Writer which handles escape sequence for stderr.
-func NewColorableStderr() io.Writer {
- return os.Stderr
-}
-
-// EnableColorsStdout enable colors if possible.
-func EnableColorsStdout(enabled *bool) func() {
- if enabled != nil {
- *enabled = true
- }
- return func() {}
-}
diff --git a/vendor/github.com/mattn/go-colorable/colorable_windows.go b/vendor/github.com/mattn/go-colorable/colorable_windows.go
deleted file mode 100644
index 41215d7fc..000000000
--- a/vendor/github.com/mattn/go-colorable/colorable_windows.go
+++ /dev/null
@@ -1,1043 +0,0 @@
-// +build windows
-// +build !appengine
-
-package colorable
-
-import (
- "bytes"
- "io"
- "math"
- "os"
- "strconv"
- "strings"
- "sync"
- "syscall"
- "unsafe"
-
- "github.com/mattn/go-isatty"
-)
-
-const (
- foregroundBlue = 0x1
- foregroundGreen = 0x2
- foregroundRed = 0x4
- foregroundIntensity = 0x8
- foregroundMask = (foregroundRed | foregroundBlue | foregroundGreen | foregroundIntensity)
- backgroundBlue = 0x10
- backgroundGreen = 0x20
- backgroundRed = 0x40
- backgroundIntensity = 0x80
- backgroundMask = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity)
- commonLvbUnderscore = 0x8000
-
- cENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4
-)
-
-const (
- genericRead = 0x80000000
- genericWrite = 0x40000000
-)
-
-const (
- consoleTextmodeBuffer = 0x1
-)
-
-type wchar uint16
-type short int16
-type dword uint32
-type word uint16
-
-type coord struct {
- x short
- y short
-}
-
-type smallRect struct {
- left short
- top short
- right short
- bottom short
-}
-
-type consoleScreenBufferInfo struct {
- size coord
- cursorPosition coord
- attributes word
- window smallRect
- maximumWindowSize coord
-}
-
-type consoleCursorInfo struct {
- size dword
- visible int32
-}
-
-var (
- kernel32 = syscall.NewLazyDLL("kernel32.dll")
- procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
- procSetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
- procSetConsoleCursorPosition = kernel32.NewProc("SetConsoleCursorPosition")
- procFillConsoleOutputCharacter = kernel32.NewProc("FillConsoleOutputCharacterW")
- procFillConsoleOutputAttribute = kernel32.NewProc("FillConsoleOutputAttribute")
- procGetConsoleCursorInfo = kernel32.NewProc("GetConsoleCursorInfo")
- procSetConsoleCursorInfo = kernel32.NewProc("SetConsoleCursorInfo")
- procSetConsoleTitle = kernel32.NewProc("SetConsoleTitleW")
- procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
- procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
- procCreateConsoleScreenBuffer = kernel32.NewProc("CreateConsoleScreenBuffer")
-)
-
-// Writer provides colorable Writer to the console
-type Writer struct {
- out io.Writer
- handle syscall.Handle
- althandle syscall.Handle
- oldattr word
- oldpos coord
- rest bytes.Buffer
- mutex sync.Mutex
-}
-
-// NewColorable returns new instance of Writer which handles escape sequence from File.
-func NewColorable(file *os.File) io.Writer {
- if file == nil {
- panic("nil passed instead of *os.File to NewColorable()")
- }
-
- if isatty.IsTerminal(file.Fd()) {
- var mode uint32
- if r, _, _ := procGetConsoleMode.Call(file.Fd(), uintptr(unsafe.Pointer(&mode))); r != 0 && mode&cENABLE_VIRTUAL_TERMINAL_PROCESSING != 0 {
- return file
- }
- var csbi consoleScreenBufferInfo
- handle := syscall.Handle(file.Fd())
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- return &Writer{out: file, handle: handle, oldattr: csbi.attributes, oldpos: coord{0, 0}}
- }
- return file
-}
-
-// NewColorableStdout returns new instance of Writer which handles escape sequence for stdout.
-func NewColorableStdout() io.Writer {
- return NewColorable(os.Stdout)
-}
-
-// NewColorableStderr returns new instance of Writer which handles escape sequence for stderr.
-func NewColorableStderr() io.Writer {
- return NewColorable(os.Stderr)
-}
-
-var color256 = map[int]int{
- 0: 0x000000,
- 1: 0x800000,
- 2: 0x008000,
- 3: 0x808000,
- 4: 0x000080,
- 5: 0x800080,
- 6: 0x008080,
- 7: 0xc0c0c0,
- 8: 0x808080,
- 9: 0xff0000,
- 10: 0x00ff00,
- 11: 0xffff00,
- 12: 0x0000ff,
- 13: 0xff00ff,
- 14: 0x00ffff,
- 15: 0xffffff,
- 16: 0x000000,
- 17: 0x00005f,
- 18: 0x000087,
- 19: 0x0000af,
- 20: 0x0000d7,
- 21: 0x0000ff,
- 22: 0x005f00,
- 23: 0x005f5f,
- 24: 0x005f87,
- 25: 0x005faf,
- 26: 0x005fd7,
- 27: 0x005fff,
- 28: 0x008700,
- 29: 0x00875f,
- 30: 0x008787,
- 31: 0x0087af,
- 32: 0x0087d7,
- 33: 0x0087ff,
- 34: 0x00af00,
- 35: 0x00af5f,
- 36: 0x00af87,
- 37: 0x00afaf,
- 38: 0x00afd7,
- 39: 0x00afff,
- 40: 0x00d700,
- 41: 0x00d75f,
- 42: 0x00d787,
- 43: 0x00d7af,
- 44: 0x00d7d7,
- 45: 0x00d7ff,
- 46: 0x00ff00,
- 47: 0x00ff5f,
- 48: 0x00ff87,
- 49: 0x00ffaf,
- 50: 0x00ffd7,
- 51: 0x00ffff,
- 52: 0x5f0000,
- 53: 0x5f005f,
- 54: 0x5f0087,
- 55: 0x5f00af,
- 56: 0x5f00d7,
- 57: 0x5f00ff,
- 58: 0x5f5f00,
- 59: 0x5f5f5f,
- 60: 0x5f5f87,
- 61: 0x5f5faf,
- 62: 0x5f5fd7,
- 63: 0x5f5fff,
- 64: 0x5f8700,
- 65: 0x5f875f,
- 66: 0x5f8787,
- 67: 0x5f87af,
- 68: 0x5f87d7,
- 69: 0x5f87ff,
- 70: 0x5faf00,
- 71: 0x5faf5f,
- 72: 0x5faf87,
- 73: 0x5fafaf,
- 74: 0x5fafd7,
- 75: 0x5fafff,
- 76: 0x5fd700,
- 77: 0x5fd75f,
- 78: 0x5fd787,
- 79: 0x5fd7af,
- 80: 0x5fd7d7,
- 81: 0x5fd7ff,
- 82: 0x5fff00,
- 83: 0x5fff5f,
- 84: 0x5fff87,
- 85: 0x5fffaf,
- 86: 0x5fffd7,
- 87: 0x5fffff,
- 88: 0x870000,
- 89: 0x87005f,
- 90: 0x870087,
- 91: 0x8700af,
- 92: 0x8700d7,
- 93: 0x8700ff,
- 94: 0x875f00,
- 95: 0x875f5f,
- 96: 0x875f87,
- 97: 0x875faf,
- 98: 0x875fd7,
- 99: 0x875fff,
- 100: 0x878700,
- 101: 0x87875f,
- 102: 0x878787,
- 103: 0x8787af,
- 104: 0x8787d7,
- 105: 0x8787ff,
- 106: 0x87af00,
- 107: 0x87af5f,
- 108: 0x87af87,
- 109: 0x87afaf,
- 110: 0x87afd7,
- 111: 0x87afff,
- 112: 0x87d700,
- 113: 0x87d75f,
- 114: 0x87d787,
- 115: 0x87d7af,
- 116: 0x87d7d7,
- 117: 0x87d7ff,
- 118: 0x87ff00,
- 119: 0x87ff5f,
- 120: 0x87ff87,
- 121: 0x87ffaf,
- 122: 0x87ffd7,
- 123: 0x87ffff,
- 124: 0xaf0000,
- 125: 0xaf005f,
- 126: 0xaf0087,
- 127: 0xaf00af,
- 128: 0xaf00d7,
- 129: 0xaf00ff,
- 130: 0xaf5f00,
- 131: 0xaf5f5f,
- 132: 0xaf5f87,
- 133: 0xaf5faf,
- 134: 0xaf5fd7,
- 135: 0xaf5fff,
- 136: 0xaf8700,
- 137: 0xaf875f,
- 138: 0xaf8787,
- 139: 0xaf87af,
- 140: 0xaf87d7,
- 141: 0xaf87ff,
- 142: 0xafaf00,
- 143: 0xafaf5f,
- 144: 0xafaf87,
- 145: 0xafafaf,
- 146: 0xafafd7,
- 147: 0xafafff,
- 148: 0xafd700,
- 149: 0xafd75f,
- 150: 0xafd787,
- 151: 0xafd7af,
- 152: 0xafd7d7,
- 153: 0xafd7ff,
- 154: 0xafff00,
- 155: 0xafff5f,
- 156: 0xafff87,
- 157: 0xafffaf,
- 158: 0xafffd7,
- 159: 0xafffff,
- 160: 0xd70000,
- 161: 0xd7005f,
- 162: 0xd70087,
- 163: 0xd700af,
- 164: 0xd700d7,
- 165: 0xd700ff,
- 166: 0xd75f00,
- 167: 0xd75f5f,
- 168: 0xd75f87,
- 169: 0xd75faf,
- 170: 0xd75fd7,
- 171: 0xd75fff,
- 172: 0xd78700,
- 173: 0xd7875f,
- 174: 0xd78787,
- 175: 0xd787af,
- 176: 0xd787d7,
- 177: 0xd787ff,
- 178: 0xd7af00,
- 179: 0xd7af5f,
- 180: 0xd7af87,
- 181: 0xd7afaf,
- 182: 0xd7afd7,
- 183: 0xd7afff,
- 184: 0xd7d700,
- 185: 0xd7d75f,
- 186: 0xd7d787,
- 187: 0xd7d7af,
- 188: 0xd7d7d7,
- 189: 0xd7d7ff,
- 190: 0xd7ff00,
- 191: 0xd7ff5f,
- 192: 0xd7ff87,
- 193: 0xd7ffaf,
- 194: 0xd7ffd7,
- 195: 0xd7ffff,
- 196: 0xff0000,
- 197: 0xff005f,
- 198: 0xff0087,
- 199: 0xff00af,
- 200: 0xff00d7,
- 201: 0xff00ff,
- 202: 0xff5f00,
- 203: 0xff5f5f,
- 204: 0xff5f87,
- 205: 0xff5faf,
- 206: 0xff5fd7,
- 207: 0xff5fff,
- 208: 0xff8700,
- 209: 0xff875f,
- 210: 0xff8787,
- 211: 0xff87af,
- 212: 0xff87d7,
- 213: 0xff87ff,
- 214: 0xffaf00,
- 215: 0xffaf5f,
- 216: 0xffaf87,
- 217: 0xffafaf,
- 218: 0xffafd7,
- 219: 0xffafff,
- 220: 0xffd700,
- 221: 0xffd75f,
- 222: 0xffd787,
- 223: 0xffd7af,
- 224: 0xffd7d7,
- 225: 0xffd7ff,
- 226: 0xffff00,
- 227: 0xffff5f,
- 228: 0xffff87,
- 229: 0xffffaf,
- 230: 0xffffd7,
- 231: 0xffffff,
- 232: 0x080808,
- 233: 0x121212,
- 234: 0x1c1c1c,
- 235: 0x262626,
- 236: 0x303030,
- 237: 0x3a3a3a,
- 238: 0x444444,
- 239: 0x4e4e4e,
- 240: 0x585858,
- 241: 0x626262,
- 242: 0x6c6c6c,
- 243: 0x767676,
- 244: 0x808080,
- 245: 0x8a8a8a,
- 246: 0x949494,
- 247: 0x9e9e9e,
- 248: 0xa8a8a8,
- 249: 0xb2b2b2,
- 250: 0xbcbcbc,
- 251: 0xc6c6c6,
- 252: 0xd0d0d0,
- 253: 0xdadada,
- 254: 0xe4e4e4,
- 255: 0xeeeeee,
-}
-
-// `\033]0;TITLESTR\007`
-func doTitleSequence(er *bytes.Reader) error {
- var c byte
- var err error
-
- c, err = er.ReadByte()
- if err != nil {
- return err
- }
- if c != '0' && c != '2' {
- return nil
- }
- c, err = er.ReadByte()
- if err != nil {
- return err
- }
- if c != ';' {
- return nil
- }
- title := make([]byte, 0, 80)
- for {
- c, err = er.ReadByte()
- if err != nil {
- return err
- }
- if c == 0x07 || c == '\n' {
- break
- }
- title = append(title, c)
- }
- if len(title) > 0 {
- title8, err := syscall.UTF16PtrFromString(string(title))
- if err == nil {
- procSetConsoleTitle.Call(uintptr(unsafe.Pointer(title8)))
- }
- }
- return nil
-}
-
-// returns Atoi(s) unless s == "" in which case it returns def
-func atoiWithDefault(s string, def int) (int, error) {
- if s == "" {
- return def, nil
- }
- return strconv.Atoi(s)
-}
-
-// Write writes data on console
-func (w *Writer) Write(data []byte) (n int, err error) {
- w.mutex.Lock()
- defer w.mutex.Unlock()
- var csbi consoleScreenBufferInfo
- procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi)))
-
- handle := w.handle
-
- var er *bytes.Reader
- if w.rest.Len() > 0 {
- var rest bytes.Buffer
- w.rest.WriteTo(&rest)
- w.rest.Reset()
- rest.Write(data)
- er = bytes.NewReader(rest.Bytes())
- } else {
- er = bytes.NewReader(data)
- }
- var bw [1]byte
-loop:
- for {
- c1, err := er.ReadByte()
- if err != nil {
- break loop
- }
- if c1 != 0x1b {
- bw[0] = c1
- w.out.Write(bw[:])
- continue
- }
- c2, err := er.ReadByte()
- if err != nil {
- break loop
- }
-
- switch c2 {
- case '>':
- continue
- case ']':
- w.rest.WriteByte(c1)
- w.rest.WriteByte(c2)
- er.WriteTo(&w.rest)
- if bytes.IndexByte(w.rest.Bytes(), 0x07) == -1 {
- break loop
- }
- er = bytes.NewReader(w.rest.Bytes()[2:])
- err := doTitleSequence(er)
- if err != nil {
- break loop
- }
- w.rest.Reset()
- continue
- // https://github.com/mattn/go-colorable/issues/27
- case '7':
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- w.oldpos = csbi.cursorPosition
- continue
- case '8':
- procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&w.oldpos)))
- continue
- case 0x5b:
- // execute part after switch
- default:
- continue
- }
-
- w.rest.WriteByte(c1)
- w.rest.WriteByte(c2)
- er.WriteTo(&w.rest)
-
- var buf bytes.Buffer
- var m byte
- for i, c := range w.rest.Bytes()[2:] {
- if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
- m = c
- er = bytes.NewReader(w.rest.Bytes()[2+i+1:])
- w.rest.Reset()
- break
- }
- buf.Write([]byte(string(c)))
- }
- if m == 0 {
- break loop
- }
-
- switch m {
- case 'A':
- n, err = atoiWithDefault(buf.String(), 1)
- if err != nil {
- continue
- }
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- csbi.cursorPosition.y -= short(n)
- procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
- case 'B':
- n, err = atoiWithDefault(buf.String(), 1)
- if err != nil {
- continue
- }
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- csbi.cursorPosition.y += short(n)
- procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
- case 'C':
- n, err = atoiWithDefault(buf.String(), 1)
- if err != nil {
- continue
- }
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- csbi.cursorPosition.x += short(n)
- procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
- case 'D':
- n, err = atoiWithDefault(buf.String(), 1)
- if err != nil {
- continue
- }
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- csbi.cursorPosition.x -= short(n)
- if csbi.cursorPosition.x < 0 {
- csbi.cursorPosition.x = 0
- }
- procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
- case 'E':
- n, err = strconv.Atoi(buf.String())
- if err != nil {
- continue
- }
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- csbi.cursorPosition.x = 0
- csbi.cursorPosition.y += short(n)
- procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
- case 'F':
- n, err = strconv.Atoi(buf.String())
- if err != nil {
- continue
- }
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- csbi.cursorPosition.x = 0
- csbi.cursorPosition.y -= short(n)
- procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
- case 'G':
- n, err = strconv.Atoi(buf.String())
- if err != nil {
- continue
- }
- if n < 1 {
- n = 1
- }
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- csbi.cursorPosition.x = short(n - 1)
- procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
- case 'H', 'f':
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- if buf.Len() > 0 {
- token := strings.Split(buf.String(), ";")
- switch len(token) {
- case 1:
- n1, err := strconv.Atoi(token[0])
- if err != nil {
- continue
- }
- csbi.cursorPosition.y = short(n1 - 1)
- case 2:
- n1, err := strconv.Atoi(token[0])
- if err != nil {
- continue
- }
- n2, err := strconv.Atoi(token[1])
- if err != nil {
- continue
- }
- csbi.cursorPosition.x = short(n2 - 1)
- csbi.cursorPosition.y = short(n1 - 1)
- }
- } else {
- csbi.cursorPosition.y = 0
- }
- procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition)))
- case 'J':
- n := 0
- if buf.Len() > 0 {
- n, err = strconv.Atoi(buf.String())
- if err != nil {
- continue
- }
- }
- var count, written dword
- var cursor coord
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- switch n {
- case 0:
- cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y}
- count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.size.y-csbi.cursorPosition.y)*dword(csbi.size.x)
- case 1:
- cursor = coord{x: csbi.window.left, y: csbi.window.top}
- count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.window.top-csbi.cursorPosition.y)*dword(csbi.size.x)
- case 2:
- cursor = coord{x: csbi.window.left, y: csbi.window.top}
- count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.size.y-csbi.cursorPosition.y)*dword(csbi.size.x)
- }
- procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
- procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
- case 'K':
- n := 0
- if buf.Len() > 0 {
- n, err = strconv.Atoi(buf.String())
- if err != nil {
- continue
- }
- }
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- var cursor coord
- var count, written dword
- switch n {
- case 0:
- cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y}
- count = dword(csbi.size.x - csbi.cursorPosition.x)
- case 1:
- cursor = coord{x: csbi.window.left, y: csbi.cursorPosition.y}
- count = dword(csbi.size.x - csbi.cursorPosition.x)
- case 2:
- cursor = coord{x: csbi.window.left, y: csbi.cursorPosition.y}
- count = dword(csbi.size.x)
- }
- procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
- procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
- case 'X':
- n := 0
- if buf.Len() > 0 {
- n, err = strconv.Atoi(buf.String())
- if err != nil {
- continue
- }
- }
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- var cursor coord
- var written dword
- cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y}
- procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(n), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
- procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(n), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written)))
- case 'm':
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- attr := csbi.attributes
- cs := buf.String()
- if cs == "" {
- procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(w.oldattr))
- continue
- }
- token := strings.Split(cs, ";")
- for i := 0; i < len(token); i++ {
- ns := token[i]
- if n, err = strconv.Atoi(ns); err == nil {
- switch {
- case n == 0 || n == 100:
- attr = w.oldattr
- case n == 4:
- attr |= commonLvbUnderscore
- case (1 <= n && n <= 3) || n == 5:
- attr |= foregroundIntensity
- case n == 7 || n == 27:
- attr =
- (attr &^ (foregroundMask | backgroundMask)) |
- ((attr & foregroundMask) << 4) |
- ((attr & backgroundMask) >> 4)
- case n == 22:
- attr &^= foregroundIntensity
- case n == 24:
- attr &^= commonLvbUnderscore
- case 30 <= n && n <= 37:
- attr &= backgroundMask
- if (n-30)&1 != 0 {
- attr |= foregroundRed
- }
- if (n-30)&2 != 0 {
- attr |= foregroundGreen
- }
- if (n-30)&4 != 0 {
- attr |= foregroundBlue
- }
- case n == 38: // set foreground color.
- if i < len(token)-2 && (token[i+1] == "5" || token[i+1] == "05") {
- if n256, err := strconv.Atoi(token[i+2]); err == nil {
- if n256foreAttr == nil {
- n256setup()
- }
- attr &= backgroundMask
- attr |= n256foreAttr[n256%len(n256foreAttr)]
- i += 2
- }
- } else if len(token) == 5 && token[i+1] == "2" {
- var r, g, b int
- r, _ = strconv.Atoi(token[i+2])
- g, _ = strconv.Atoi(token[i+3])
- b, _ = strconv.Atoi(token[i+4])
- i += 4
- if r > 127 {
- attr |= foregroundRed
- }
- if g > 127 {
- attr |= foregroundGreen
- }
- if b > 127 {
- attr |= foregroundBlue
- }
- } else {
- attr = attr & (w.oldattr & backgroundMask)
- }
- case n == 39: // reset foreground color.
- attr &= backgroundMask
- attr |= w.oldattr & foregroundMask
- case 40 <= n && n <= 47:
- attr &= foregroundMask
- if (n-40)&1 != 0 {
- attr |= backgroundRed
- }
- if (n-40)&2 != 0 {
- attr |= backgroundGreen
- }
- if (n-40)&4 != 0 {
- attr |= backgroundBlue
- }
- case n == 48: // set background color.
- if i < len(token)-2 && token[i+1] == "5" {
- if n256, err := strconv.Atoi(token[i+2]); err == nil {
- if n256backAttr == nil {
- n256setup()
- }
- attr &= foregroundMask
- attr |= n256backAttr[n256%len(n256backAttr)]
- i += 2
- }
- } else if len(token) == 5 && token[i+1] == "2" {
- var r, g, b int
- r, _ = strconv.Atoi(token[i+2])
- g, _ = strconv.Atoi(token[i+3])
- b, _ = strconv.Atoi(token[i+4])
- i += 4
- if r > 127 {
- attr |= backgroundRed
- }
- if g > 127 {
- attr |= backgroundGreen
- }
- if b > 127 {
- attr |= backgroundBlue
- }
- } else {
- attr = attr & (w.oldattr & foregroundMask)
- }
- case n == 49: // reset foreground color.
- attr &= foregroundMask
- attr |= w.oldattr & backgroundMask
- case 90 <= n && n <= 97:
- attr = (attr & backgroundMask)
- attr |= foregroundIntensity
- if (n-90)&1 != 0 {
- attr |= foregroundRed
- }
- if (n-90)&2 != 0 {
- attr |= foregroundGreen
- }
- if (n-90)&4 != 0 {
- attr |= foregroundBlue
- }
- case 100 <= n && n <= 107:
- attr = (attr & foregroundMask)
- attr |= backgroundIntensity
- if (n-100)&1 != 0 {
- attr |= backgroundRed
- }
- if (n-100)&2 != 0 {
- attr |= backgroundGreen
- }
- if (n-100)&4 != 0 {
- attr |= backgroundBlue
- }
- }
- procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(attr))
- }
- }
- case 'h':
- var ci consoleCursorInfo
- cs := buf.String()
- if cs == "5>" {
- procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
- ci.visible = 0
- procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
- } else if cs == "?25" {
- procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
- ci.visible = 1
- procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
- } else if cs == "?1049" {
- if w.althandle == 0 {
- h, _, _ := procCreateConsoleScreenBuffer.Call(uintptr(genericRead|genericWrite), 0, 0, uintptr(consoleTextmodeBuffer), 0, 0)
- w.althandle = syscall.Handle(h)
- if w.althandle != 0 {
- handle = w.althandle
- }
- }
- }
- case 'l':
- var ci consoleCursorInfo
- cs := buf.String()
- if cs == "5>" {
- procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
- ci.visible = 1
- procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
- } else if cs == "?25" {
- procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
- ci.visible = 0
- procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci)))
- } else if cs == "?1049" {
- if w.althandle != 0 {
- syscall.CloseHandle(w.althandle)
- w.althandle = 0
- handle = w.handle
- }
- }
- case 's':
- procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi)))
- w.oldpos = csbi.cursorPosition
- case 'u':
- procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&w.oldpos)))
- }
- }
-
- return len(data), nil
-}
-
-type consoleColor struct {
- rgb int
- red bool
- green bool
- blue bool
- intensity bool
-}
-
-func (c consoleColor) foregroundAttr() (attr word) {
- if c.red {
- attr |= foregroundRed
- }
- if c.green {
- attr |= foregroundGreen
- }
- if c.blue {
- attr |= foregroundBlue
- }
- if c.intensity {
- attr |= foregroundIntensity
- }
- return
-}
-
-func (c consoleColor) backgroundAttr() (attr word) {
- if c.red {
- attr |= backgroundRed
- }
- if c.green {
- attr |= backgroundGreen
- }
- if c.blue {
- attr |= backgroundBlue
- }
- if c.intensity {
- attr |= backgroundIntensity
- }
- return
-}
-
-var color16 = []consoleColor{
- {0x000000, false, false, false, false},
- {0x000080, false, false, true, false},
- {0x008000, false, true, false, false},
- {0x008080, false, true, true, false},
- {0x800000, true, false, false, false},
- {0x800080, true, false, true, false},
- {0x808000, true, true, false, false},
- {0xc0c0c0, true, true, true, false},
- {0x808080, false, false, false, true},
- {0x0000ff, false, false, true, true},
- {0x00ff00, false, true, false, true},
- {0x00ffff, false, true, true, true},
- {0xff0000, true, false, false, true},
- {0xff00ff, true, false, true, true},
- {0xffff00, true, true, false, true},
- {0xffffff, true, true, true, true},
-}
-
-type hsv struct {
- h, s, v float32
-}
-
-func (a hsv) dist(b hsv) float32 {
- dh := a.h - b.h
- switch {
- case dh > 0.5:
- dh = 1 - dh
- case dh < -0.5:
- dh = -1 - dh
- }
- ds := a.s - b.s
- dv := a.v - b.v
- return float32(math.Sqrt(float64(dh*dh + ds*ds + dv*dv)))
-}
-
-func toHSV(rgb int) hsv {
- r, g, b := float32((rgb&0xFF0000)>>16)/256.0,
- float32((rgb&0x00FF00)>>8)/256.0,
- float32(rgb&0x0000FF)/256.0
- min, max := minmax3f(r, g, b)
- h := max - min
- if h > 0 {
- if max == r {
- h = (g - b) / h
- if h < 0 {
- h += 6
- }
- } else if max == g {
- h = 2 + (b-r)/h
- } else {
- h = 4 + (r-g)/h
- }
- }
- h /= 6.0
- s := max - min
- if max != 0 {
- s /= max
- }
- v := max
- return hsv{h: h, s: s, v: v}
-}
-
-type hsvTable []hsv
-
-func toHSVTable(rgbTable []consoleColor) hsvTable {
- t := make(hsvTable, len(rgbTable))
- for i, c := range rgbTable {
- t[i] = toHSV(c.rgb)
- }
- return t
-}
-
-func (t hsvTable) find(rgb int) consoleColor {
- hsv := toHSV(rgb)
- n := 7
- l := float32(5.0)
- for i, p := range t {
- d := hsv.dist(p)
- if d < l {
- l, n = d, i
- }
- }
- return color16[n]
-}
-
-func minmax3f(a, b, c float32) (min, max float32) {
- if a < b {
- if b < c {
- return a, c
- } else if a < c {
- return a, b
- } else {
- return c, b
- }
- } else {
- if a < c {
- return b, c
- } else if b < c {
- return b, a
- } else {
- return c, a
- }
- }
-}
-
-var n256foreAttr []word
-var n256backAttr []word
-
-func n256setup() {
- n256foreAttr = make([]word, 256)
- n256backAttr = make([]word, 256)
- t := toHSVTable(color16)
- for i, rgb := range color256 {
- c := t.find(rgb)
- n256foreAttr[i] = c.foregroundAttr()
- n256backAttr[i] = c.backgroundAttr()
- }
-}
-
-// EnableColorsStdout enable colors if possible.
-func EnableColorsStdout(enabled *bool) func() {
- var mode uint32
- h := os.Stdout.Fd()
- if r, _, _ := procGetConsoleMode.Call(h, uintptr(unsafe.Pointer(&mode))); r != 0 {
- if r, _, _ = procSetConsoleMode.Call(h, uintptr(mode|cENABLE_VIRTUAL_TERMINAL_PROCESSING)); r != 0 {
- if enabled != nil {
- *enabled = true
- }
- return func() {
- procSetConsoleMode.Call(h, uintptr(mode))
- }
- }
- }
- if enabled != nil {
- *enabled = true
- }
- return func() {}
-}
diff --git a/vendor/github.com/mattn/go-colorable/go.mod b/vendor/github.com/mattn/go-colorable/go.mod
deleted file mode 100644
index 1e590b819..000000000
--- a/vendor/github.com/mattn/go-colorable/go.mod
+++ /dev/null
@@ -1,8 +0,0 @@
-module github.com/mattn/go-colorable
-
-require (
- github.com/mattn/go-isatty v0.0.12
- golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae // indirect
-)
-
-go 1.13
diff --git a/vendor/github.com/mattn/go-colorable/go.sum b/vendor/github.com/mattn/go-colorable/go.sum
deleted file mode 100644
index cf5b95d97..000000000
--- a/vendor/github.com/mattn/go-colorable/go.sum
+++ /dev/null
@@ -1,5 +0,0 @@
-github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
-github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
-golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
-golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/vendor/github.com/mattn/go-colorable/go.test.sh b/vendor/github.com/mattn/go-colorable/go.test.sh
deleted file mode 100644
index 012162b07..000000000
--- a/vendor/github.com/mattn/go-colorable/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-colorable/noncolorable.go b/vendor/github.com/mattn/go-colorable/noncolorable.go
deleted file mode 100644
index 95f2c6be2..000000000
--- a/vendor/github.com/mattn/go-colorable/noncolorable.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package colorable
-
-import (
- "bytes"
- "io"
-)
-
-// NonColorable holds writer but removes escape sequence.
-type NonColorable struct {
- out io.Writer
-}
-
-// NewNonColorable returns new instance of Writer which removes escape sequence from Writer.
-func NewNonColorable(w io.Writer) io.Writer {
- return &NonColorable{out: w}
-}
-
-// Write writes data on console
-func (w *NonColorable) Write(data []byte) (n int, err error) {
- er := bytes.NewReader(data)
- var bw [1]byte
-loop:
- for {
- c1, err := er.ReadByte()
- if err != nil {
- break loop
- }
- if c1 != 0x1b {
- bw[0] = c1
- w.out.Write(bw[:])
- continue
- }
- c2, err := er.ReadByte()
- if err != nil {
- break loop
- }
- if c2 != 0x5b {
- continue
- }
-
- var buf bytes.Buffer
- for {
- c, err := er.ReadByte()
- if err != nil {
- break loop
- }
- if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
- break
- }
- buf.Write([]byte(string(c)))
- }
- }
-
- return len(data), 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/modern-go/reflect2/.travis.yml b/vendor/github.com/modern-go/reflect2/.travis.yml
index fbb43744d..b097728db 100644
--- a/vendor/github.com/modern-go/reflect2/.travis.yml
+++ b/vendor/github.com/modern-go/reflect2/.travis.yml
@@ -1,7 +1,7 @@
language: go
go:
- - 1.8.x
+ - 1.9.x
- 1.x
before_install:
diff --git a/vendor/github.com/modern-go/reflect2/Gopkg.lock b/vendor/github.com/modern-go/reflect2/Gopkg.lock
index 2a3a69893..10ef81118 100644
--- a/vendor/github.com/modern-go/reflect2/Gopkg.lock
+++ b/vendor/github.com/modern-go/reflect2/Gopkg.lock
@@ -1,15 +1,9 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
-[[projects]]
- name = "github.com/modern-go/concurrent"
- packages = ["."]
- revision = "e0a39a4cb4216ea8db28e22a69f4ec25610d513a"
- version = "1.0.0"
-
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
- inputs-digest = "daee8a88b3498b61c5640056665b8b9eea062006f5e596bbb6a3ed9119a11ec7"
+ input-imports = []
solver-name = "gps-cdcl"
solver-version = 1
diff --git a/vendor/github.com/modern-go/reflect2/Gopkg.toml b/vendor/github.com/modern-go/reflect2/Gopkg.toml
index 2f4f4dbdc..a9bc5061b 100644
--- a/vendor/github.com/modern-go/reflect2/Gopkg.toml
+++ b/vendor/github.com/modern-go/reflect2/Gopkg.toml
@@ -26,10 +26,6 @@
ignored = []
-[[constraint]]
- name = "github.com/modern-go/concurrent"
- version = "1.0.0"
-
[prune]
go-tests = true
unused-packages = true
diff --git a/vendor/github.com/modern-go/reflect2/go.mod b/vendor/github.com/modern-go/reflect2/go.mod
new file mode 100644
index 000000000..9057e9b33
--- /dev/null
+++ b/vendor/github.com/modern-go/reflect2/go.mod
@@ -0,0 +1,3 @@
+module github.com/modern-go/reflect2
+
+go 1.12
diff --git a/vendor/github.com/modern-go/reflect2/go_above_118.go b/vendor/github.com/modern-go/reflect2/go_above_118.go
new file mode 100644
index 000000000..2b4116f6c
--- /dev/null
+++ b/vendor/github.com/modern-go/reflect2/go_above_118.go
@@ -0,0 +1,23 @@
+//+build go1.18
+
+package reflect2
+
+import (
+ "unsafe"
+)
+
+// m escapes into the return value, but the caller of mapiterinit
+// doesn't let the return value escape.
+//go:noescape
+//go:linkname mapiterinit reflect.mapiterinit
+func mapiterinit(rtype unsafe.Pointer, m unsafe.Pointer, it *hiter)
+
+func (type2 *UnsafeMapType) UnsafeIterate(obj unsafe.Pointer) MapIterator {
+ var it hiter
+ mapiterinit(type2.rtype, *(*unsafe.Pointer)(obj), &it)
+ return &UnsafeMapIterator{
+ hiter: &it,
+ pKeyRType: type2.pKeyRType,
+ pElemRType: type2.pElemRType,
+ }
+} \ No newline at end of file
diff --git a/vendor/github.com/modern-go/reflect2/go_above_17.go b/vendor/github.com/modern-go/reflect2/go_above_17.go
deleted file mode 100644
index 5c1cea868..000000000
--- a/vendor/github.com/modern-go/reflect2/go_above_17.go
+++ /dev/null
@@ -1,8 +0,0 @@
-//+build go1.7
-
-package reflect2
-
-import "unsafe"
-
-//go:linkname resolveTypeOff reflect.resolveTypeOff
-func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer
diff --git a/vendor/github.com/modern-go/reflect2/go_above_19.go b/vendor/github.com/modern-go/reflect2/go_above_19.go
index c7e3b7801..974f7685e 100644
--- a/vendor/github.com/modern-go/reflect2/go_above_19.go
+++ b/vendor/github.com/modern-go/reflect2/go_above_19.go
@@ -6,6 +6,9 @@ import (
"unsafe"
)
+//go:linkname resolveTypeOff reflect.resolveTypeOff
+func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer
+
//go:linkname makemap reflect.makemap
func makemap(rtype unsafe.Pointer, cap int) (m unsafe.Pointer)
diff --git a/vendor/github.com/modern-go/reflect2/go_below_118.go b/vendor/github.com/modern-go/reflect2/go_below_118.go
new file mode 100644
index 000000000..00003dbd7
--- /dev/null
+++ b/vendor/github.com/modern-go/reflect2/go_below_118.go
@@ -0,0 +1,21 @@
+//+build !go1.18
+
+package reflect2
+
+import (
+ "unsafe"
+)
+
+// m escapes into the return value, but the caller of mapiterinit
+// doesn't let the return value escape.
+//go:noescape
+//go:linkname mapiterinit reflect.mapiterinit
+func mapiterinit(rtype unsafe.Pointer, m unsafe.Pointer) (val *hiter)
+
+func (type2 *UnsafeMapType) UnsafeIterate(obj unsafe.Pointer) MapIterator {
+ return &UnsafeMapIterator{
+ hiter: mapiterinit(type2.rtype, *(*unsafe.Pointer)(obj)),
+ pKeyRType: type2.pKeyRType,
+ pElemRType: type2.pElemRType,
+ }
+} \ No newline at end of file
diff --git a/vendor/github.com/modern-go/reflect2/go_below_17.go b/vendor/github.com/modern-go/reflect2/go_below_17.go
deleted file mode 100644
index 65a93c889..000000000
--- a/vendor/github.com/modern-go/reflect2/go_below_17.go
+++ /dev/null
@@ -1,9 +0,0 @@
-//+build !go1.7
-
-package reflect2
-
-import "unsafe"
-
-func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer {
- return nil
-}
diff --git a/vendor/github.com/modern-go/reflect2/go_below_19.go b/vendor/github.com/modern-go/reflect2/go_below_19.go
deleted file mode 100644
index b050ef70c..000000000
--- a/vendor/github.com/modern-go/reflect2/go_below_19.go
+++ /dev/null
@@ -1,14 +0,0 @@
-//+build !go1.9
-
-package reflect2
-
-import (
- "unsafe"
-)
-
-//go:linkname makemap reflect.makemap
-func makemap(rtype unsafe.Pointer) (m unsafe.Pointer)
-
-func makeMapWithSize(rtype unsafe.Pointer, cap int) unsafe.Pointer {
- return makemap(rtype)
-}
diff --git a/vendor/github.com/modern-go/reflect2/reflect2.go b/vendor/github.com/modern-go/reflect2/reflect2.go
index 63b49c799..c43c8b9d6 100644
--- a/vendor/github.com/modern-go/reflect2/reflect2.go
+++ b/vendor/github.com/modern-go/reflect2/reflect2.go
@@ -1,8 +1,9 @@
package reflect2
import (
- "github.com/modern-go/concurrent"
"reflect"
+ "runtime"
+ "sync"
"unsafe"
)
@@ -130,13 +131,13 @@ var ConfigSafe = Config{UseSafeImplementation: true}.Froze()
type frozenConfig struct {
useSafeImplementation bool
- cache *concurrent.Map
+ cache *sync.Map
}
func (cfg Config) Froze() *frozenConfig {
return &frozenConfig{
useSafeImplementation: cfg.UseSafeImplementation,
- cache: concurrent.NewMap(),
+ cache: new(sync.Map),
}
}
@@ -288,11 +289,12 @@ func NoEscape(p unsafe.Pointer) unsafe.Pointer {
}
func UnsafeCastString(str string) []byte {
+ bytes := make([]byte, 0)
stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&str))
- sliceHeader := &reflect.SliceHeader{
- Data: stringHeader.Data,
- Cap: stringHeader.Len,
- Len: stringHeader.Len,
- }
- return *(*[]byte)(unsafe.Pointer(sliceHeader))
+ sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&bytes))
+ sliceHeader.Data = stringHeader.Data
+ sliceHeader.Cap = stringHeader.Len
+ sliceHeader.Len = stringHeader.Len
+ runtime.KeepAlive(str)
+ return bytes
}
diff --git a/vendor/github.com/modern-go/reflect2/test.sh b/vendor/github.com/modern-go/reflect2/test.sh
deleted file mode 100644
index 3d2b9768c..000000000
--- a/vendor/github.com/modern-go/reflect2/test.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-echo "" > coverage.txt
-
-for d in $(go list github.com/modern-go/reflect2-tests/... | grep -v vendor); do
- go test -coverprofile=profile.out -coverpkg=github.com/modern-go/reflect2 $d
- if [ -f profile.out ]; then
- cat profile.out >> coverage.txt
- rm profile.out
- fi
-done
diff --git a/vendor/github.com/modern-go/reflect2/type_map.go b/vendor/github.com/modern-go/reflect2/type_map.go
index 3acfb5580..4b13c3155 100644
--- a/vendor/github.com/modern-go/reflect2/type_map.go
+++ b/vendor/github.com/modern-go/reflect2/type_map.go
@@ -1,17 +1,13 @@
+// +build !gccgo
+
package reflect2
import (
"reflect"
- "runtime"
- "strings"
"sync"
"unsafe"
)
-// typelinks1 for 1.5 ~ 1.6
-//go:linkname typelinks1 reflect.typelinks
-func typelinks1() [][]unsafe.Pointer
-
// typelinks2 for 1.7 ~
//go:linkname typelinks2 reflect.typelinks
func typelinks2() (sections []unsafe.Pointer, offset [][]int32)
@@ -27,49 +23,10 @@ func discoverTypes() {
types = make(map[string]reflect.Type)
packages = make(map[string]map[string]reflect.Type)
- ver := runtime.Version()
- if ver == "go1.5" || strings.HasPrefix(ver, "go1.5.") {
- loadGo15Types()
- } else if ver == "go1.6" || strings.HasPrefix(ver, "go1.6.") {
- loadGo15Types()
- } else {
- loadGo17Types()
- }
-}
-
-func loadGo15Types() {
- var obj interface{} = reflect.TypeOf(0)
- typePtrss := typelinks1()
- for _, typePtrs := range typePtrss {
- for _, typePtr := range typePtrs {
- (*emptyInterface)(unsafe.Pointer(&obj)).word = typePtr
- typ := obj.(reflect.Type)
- if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct {
- loadedType := typ.Elem()
- pkgTypes := packages[loadedType.PkgPath()]
- if pkgTypes == nil {
- pkgTypes = map[string]reflect.Type{}
- packages[loadedType.PkgPath()] = pkgTypes
- }
- types[loadedType.String()] = loadedType
- pkgTypes[loadedType.Name()] = loadedType
- }
- if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Ptr &&
- typ.Elem().Elem().Kind() == reflect.Struct {
- loadedType := typ.Elem().Elem()
- pkgTypes := packages[loadedType.PkgPath()]
- if pkgTypes == nil {
- pkgTypes = map[string]reflect.Type{}
- packages[loadedType.PkgPath()] = pkgTypes
- }
- types[loadedType.String()] = loadedType
- pkgTypes[loadedType.Name()] = loadedType
- }
- }
- }
+ loadGoTypes()
}
-func loadGo17Types() {
+func loadGoTypes() {
var obj interface{} = reflect.TypeOf(0)
sections, offset := typelinks2()
for i, offs := range offset {
diff --git a/vendor/github.com/modern-go/reflect2/unsafe_link.go b/vendor/github.com/modern-go/reflect2/unsafe_link.go
index 57229c8db..b49f614ef 100644
--- a/vendor/github.com/modern-go/reflect2/unsafe_link.go
+++ b/vendor/github.com/modern-go/reflect2/unsafe_link.go
@@ -19,18 +19,12 @@ func typedslicecopy(elemType unsafe.Pointer, dst, src sliceHeader) int
//go:linkname mapassign reflect.mapassign
//go:noescape
-func mapassign(rtype unsafe.Pointer, m unsafe.Pointer, key, val unsafe.Pointer)
+func mapassign(rtype unsafe.Pointer, m unsafe.Pointer, key unsafe.Pointer, val unsafe.Pointer)
//go:linkname mapaccess reflect.mapaccess
//go:noescape
func mapaccess(rtype unsafe.Pointer, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer)
-// m escapes into the return value, but the caller of mapiterinit
-// doesn't let the return value escape.
-//go:noescape
-//go:linkname mapiterinit reflect.mapiterinit
-func mapiterinit(rtype unsafe.Pointer, m unsafe.Pointer) *hiter
-
//go:noescape
//go:linkname mapiternext reflect.mapiternext
func mapiternext(it *hiter)
@@ -42,9 +36,21 @@ func ifaceE2I(rtype unsafe.Pointer, src interface{}, dst unsafe.Pointer)
// If you modify hiter, also change cmd/internal/gc/reflect.go to indicate
// the layout of this structure.
type hiter struct {
- key unsafe.Pointer // Must be in first position. Write nil to indicate iteration end (see cmd/internal/gc/range.go).
- value unsafe.Pointer // Must be in second position (see cmd/internal/gc/range.go).
- // rest fields are ignored
+ key unsafe.Pointer
+ value unsafe.Pointer
+ t unsafe.Pointer
+ h unsafe.Pointer
+ buckets unsafe.Pointer
+ bptr unsafe.Pointer
+ overflow *[]unsafe.Pointer
+ oldoverflow *[]unsafe.Pointer
+ startBucket uintptr
+ offset uint8
+ wrapped bool
+ B uint8
+ i uint8
+ bucket uintptr
+ checkBucket uintptr
}
// add returns p+x.
diff --git a/vendor/github.com/modern-go/reflect2/unsafe_map.go b/vendor/github.com/modern-go/reflect2/unsafe_map.go
index f2e76e6bb..37872da81 100644
--- a/vendor/github.com/modern-go/reflect2/unsafe_map.go
+++ b/vendor/github.com/modern-go/reflect2/unsafe_map.go
@@ -107,14 +107,6 @@ func (type2 *UnsafeMapType) Iterate(obj interface{}) MapIterator {
return type2.UnsafeIterate(objEFace.data)
}
-func (type2 *UnsafeMapType) UnsafeIterate(obj unsafe.Pointer) MapIterator {
- return &UnsafeMapIterator{
- hiter: mapiterinit(type2.rtype, *(*unsafe.Pointer)(obj)),
- pKeyRType: type2.pKeyRType,
- pElemRType: type2.pElemRType,
- }
-}
-
type UnsafeMapIterator struct {
*hiter
pKeyRType unsafe.Pointer
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_linux.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_linux.go
index 14e1e38c2..12de0ae5d 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_linux.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_linux.go
@@ -103,9 +103,11 @@ func SetFileCreateLabel(fileLabel string) error {
return selinux.SetFSCreateLabel(fileLabel)
}
-// Relabel changes the label of path to the filelabel string.
+// Relabel changes the label of path and all the entries beneath the path.
// It changes the MCS label to s0 if shared is true.
// This will allow all containers to share the content.
+//
+// The path itself is guaranteed to be relabeled last.
func Relabel(path string, fileLabel string, shared bool) error {
if !selinux.GetEnabled() || fileLabel == "" {
return nil
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go
index 0eedcaa78..cad467507 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux.go
@@ -255,6 +255,8 @@ func CopyLevel(src, dest string) (string, error) {
// Chcon changes the fpath file object to the SELinux label label.
// If fpath is a directory and recurse is true, then Chcon walks the
// directory tree setting the label.
+//
+// The fpath itself is guaranteed to be relabeled last.
func Chcon(fpath string, label string, recurse bool) error {
return chcon(fpath, label, recurse)
}
diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
index 295b2bc4e..b045843ad 100644
--- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
+++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go
@@ -9,6 +9,7 @@ import (
"fmt"
"io"
"io/ioutil"
+ "math/big"
"os"
"path"
"path/filepath"
@@ -16,7 +17,6 @@ import (
"strings"
"sync"
- "github.com/bits-and-blooms/bitset"
"golang.org/x/sys/unix"
)
@@ -44,7 +44,7 @@ type selinuxState struct {
type level struct {
sens uint
- cats *bitset.BitSet
+ cats *big.Int
}
type mlsRange struct {
@@ -455,8 +455,8 @@ func computeCreateContext(source string, target string, class string) (string, e
}
// catsToBitset stores categories in a bitset.
-func catsToBitset(cats string) (*bitset.BitSet, error) {
- bitset := &bitset.BitSet{}
+func catsToBitset(cats string) (*big.Int, error) {
+ bitset := new(big.Int)
catlist := strings.Split(cats, ",")
for _, r := range catlist {
@@ -471,14 +471,14 @@ func catsToBitset(cats string) (*bitset.BitSet, error) {
return nil, err
}
for i := catstart; i <= catend; i++ {
- bitset.Set(i)
+ bitset.SetBit(bitset, int(i), 1)
}
} else {
cat, err := parseLevelItem(ranges[0], category)
if err != nil {
return nil, err
}
- bitset.Set(cat)
+ bitset.SetBit(bitset, int(cat), 1)
}
}
@@ -548,37 +548,30 @@ func rangeStrToMLSRange(rangeStr string) (*mlsRange, error) {
// bitsetToStr takes a category bitset and returns it in the
// canonical selinux syntax
-func bitsetToStr(c *bitset.BitSet) string {
+func bitsetToStr(c *big.Int) string {
var str string
- i, e := c.NextSet(0)
- len := 0
- for e {
- if len == 0 {
+
+ length := 0
+ for i := int(c.TrailingZeroBits()); i < c.BitLen(); i++ {
+ if c.Bit(i) == 0 {
+ continue
+ }
+ if length == 0 {
if str != "" {
str += ","
}
- str += "c" + strconv.Itoa(int(i))
- }
-
- next, e := c.NextSet(i + 1)
- if e {
- // consecutive cats
- if next == i+1 {
- len++
- i = next
- continue
- }
+ str += "c" + strconv.Itoa(i)
}
- if len == 1 {
- str += ",c" + strconv.Itoa(int(i))
- } else if len > 1 {
- str += ".c" + strconv.Itoa(int(i))
+ if c.Bit(i+1) == 1 {
+ length++
+ continue
}
- if !e {
- break
+ if length == 1 {
+ str += ",c" + strconv.Itoa(i)
+ } else if length > 1 {
+ str += ".c" + strconv.Itoa(i)
}
- len = 0
- i = next
+ length = 0
}
return str
@@ -591,13 +584,16 @@ func (l1 *level) equal(l2 *level) bool {
if l1.sens != l2.sens {
return false
}
- return l1.cats.Equal(l2.cats)
+ if l2.cats == nil || l1.cats == nil {
+ return l2.cats == l1.cats
+ }
+ return l1.cats.Cmp(l2.cats) == 0
}
// String returns an mlsRange as a string.
func (m mlsRange) String() string {
low := "s" + strconv.Itoa(int(m.low.sens))
- if m.low.cats != nil && m.low.cats.Count() > 0 {
+ if m.low.cats != nil && m.low.cats.BitLen() > 0 {
low += ":" + bitsetToStr(m.low.cats)
}
@@ -606,7 +602,7 @@ func (m mlsRange) String() string {
}
high := "s" + strconv.Itoa(int(m.high.sens))
- if m.high.cats != nil && m.high.cats.Count() > 0 {
+ if m.high.cats != nil && m.high.cats.BitLen() > 0 {
high += ":" + bitsetToStr(m.high.cats)
}
@@ -656,10 +652,12 @@ func calculateGlbLub(sourceRange, targetRange string) (string, error) {
/* find the intersecting categories */
if s.low.cats != nil && t.low.cats != nil {
- outrange.low.cats = s.low.cats.Intersection(t.low.cats)
+ outrange.low.cats = new(big.Int)
+ outrange.low.cats.And(s.low.cats, t.low.cats)
}
if s.high.cats != nil && t.high.cats != nil {
- outrange.high.cats = s.high.cats.Intersection(t.high.cats)
+ outrange.high.cats = new(big.Int)
+ outrange.high.cats.And(s.high.cats, t.high.cats)
}
return outrange.String(), nil
diff --git a/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go b/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go
index 011fe862a..202c80da5 100644
--- a/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go
+++ b/vendor/github.com/opencontainers/selinux/pkg/pwalk/pwalk.go
@@ -51,6 +51,9 @@ func WalkN(root string, walkFn WalkFunc, num int) error {
var (
err error
wg sync.WaitGroup
+
+ rootLen = len(root)
+ rootEntry *walkArgs
)
wg.Add(1)
go func() {
@@ -59,6 +62,11 @@ func WalkN(root string, walkFn WalkFunc, num int) error {
close(files)
return err
}
+ if len(p) == rootLen {
+ // Root entry is processed separately below.
+ rootEntry = &walkArgs{path: p, info: &info}
+ return nil
+ }
// add a file to the queue unless a callback sent an error
select {
case e := <-errCh:
@@ -92,6 +100,10 @@ func WalkN(root string, walkFn WalkFunc, num int) error {
wg.Wait()
+ if err == nil {
+ err = walkFn(rootEntry.path, *rootEntry.info, nil)
+ }
+
return err
}
diff --git a/vendor/github.com/opencontainers/selinux/pkg/pwalkdir/pwalkdir.go b/vendor/github.com/opencontainers/selinux/pkg/pwalkdir/pwalkdir.go
index 222820750..a5796b2c4 100644
--- a/vendor/github.com/opencontainers/selinux/pkg/pwalkdir/pwalkdir.go
+++ b/vendor/github.com/opencontainers/selinux/pkg/pwalkdir/pwalkdir.go
@@ -1,3 +1,4 @@
+//go:build go1.16
// +build go1.16
package pwalkdir
@@ -51,6 +52,9 @@ func WalkN(root string, walkFn fs.WalkDirFunc, num int) error {
var (
err error
wg sync.WaitGroup
+
+ rootLen = len(root)
+ rootEntry *walkArgs
)
wg.Add(1)
go func() {
@@ -59,6 +63,11 @@ func WalkN(root string, walkFn fs.WalkDirFunc, num int) error {
close(files)
return err
}
+ if len(p) == rootLen {
+ // Root entry is processed separately below.
+ rootEntry = &walkArgs{path: p, entry: entry}
+ return nil
+ }
// Add a file to the queue unless a callback sent an error.
select {
case e := <-errCh:
@@ -92,6 +101,10 @@ func WalkN(root string, walkFn fs.WalkDirFunc, num int) error {
wg.Wait()
+ if err == nil {
+ err = walkFn(rootEntry.path, rootEntry.entry, nil)
+ }
+
return err
}
diff --git a/vendor/github.com/vbauerster/mpb/v7/bar.go b/vendor/github.com/vbauerster/mpb/v7/bar.go
index 22f608317..dabe1a475 100644
--- a/vendor/github.com/vbauerster/mpb/v7/bar.go
+++ b/vendor/github.com/vbauerster/mpb/v7/bar.go
@@ -268,15 +268,19 @@ func (b *Bar) SetPriority(priority int) {
// if bar is already in complete state. If drop is true bar will be
// removed as well.
func (b *Bar) Abort(drop bool) {
+ done := make(chan struct{})
select {
case b.operateState <- func(s *bState) {
if s.completed == true {
+ close(done)
return
}
- if drop {
- go b.container.dropBar(b)
- } else {
- go func() {
+ // container must be run during lifetime of this inner goroutine
+ // we control this by done channel declared above
+ go func() {
+ if drop {
+ b.container.dropBar(b)
+ } else {
var uncompleted int
b.container.traverseBars(func(bar *Bar) bool {
if b != bar && !bar.Completed() {
@@ -286,16 +290,15 @@ func (b *Bar) Abort(drop bool) {
return true
})
if uncompleted == 0 {
- select {
- case b.container.refreshCh <- time.Now():
- case <-b.container.done:
- }
+ b.container.refreshCh <- time.Now()
}
- }()
- }
+ }
+ close(done) // release hold of Abort
+ }()
b.cancel()
}:
- <-b.done
+ // guarantee: container is alive during lifetime of this hold
+ <-done
case <-b.done:
}
}
diff --git a/vendor/github.com/vbauerster/mpb/v7/go.mod b/vendor/github.com/vbauerster/mpb/v7/go.mod
index 1ecbbe062..fe10588ef 100644
--- a/vendor/github.com/vbauerster/mpb/v7/go.mod
+++ b/vendor/github.com/vbauerster/mpb/v7/go.mod
@@ -4,7 +4,7 @@ require (
github.com/VividCortex/ewma v1.2.0
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
github.com/mattn/go-runewidth v0.0.13
- golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34
+ golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0
)
go 1.14
diff --git a/vendor/github.com/vbauerster/mpb/v7/go.sum b/vendor/github.com/vbauerster/mpb/v7/go.sum
index a964dcccd..ce769eaef 100644
--- a/vendor/github.com/vbauerster/mpb/v7/go.sum
+++ b/vendor/github.com/vbauerster/mpb/v7/go.sum
@@ -6,5 +6,5 @@ github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
-golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 h1:GkvMjFtXUmahfDtashnc1mnrCtuBVcwse5QV2lUk/tI=
-golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0 h1:xrCZDmdtoloIiooiA9q0OQb9r8HejIHYoHGhGCe1pGg=
+golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=