diff --git a/v2/file/info.go b/v2/file/info.go index 45ae835..90acb8c 100644 --- a/v2/file/info.go +++ b/v2/file/info.go @@ -6,11 +6,11 @@ import ( ) type info struct { - Path string - Contents []byte - size int64 - modTime time.Time - isDir bool + Path string + Contents []byte + size int64 + modTime time.Time + isDir bool } func (f info) Name() string { diff --git a/v2/file/resolver/disk.go b/v2/file/resolver/disk.go index 8c3c1e7..52da9c1 100644 --- a/v2/file/resolver/disk.go +++ b/v2/file/resolver/disk.go @@ -8,8 +8,8 @@ import ( "sync" "github.com/gobuffalo/packr/v2/file" + "github.com/gobuffalo/packr/v2/internal/takeon/github.com/karrick/godirwalk" "github.com/gobuffalo/packr/v2/plog" - "github.com/karrick/godirwalk" ) var _ Resolver = &Disk{} diff --git a/v2/file/resolver/encoding/hex/hex.go b/v2/file/resolver/encoding/hex/hex.go index aad1f0d..f4fda4e 100644 --- a/v2/file/resolver/encoding/hex/hex.go +++ b/v2/file/resolver/encoding/hex/hex.go @@ -15,7 +15,7 @@ const hextable = "0123456789abcdef" // EncodedLen returns the length of an encoding of n source bytes. // Specifically, it returns n * 2. -func EncodedLen(n int) int { return n * 2 } +func EncodedLen(n int) int { return n * 2 } // Encode encodes src into EncodedLen(len(src)) // bytes of dst. As a convenience, it returns the number @@ -44,7 +44,7 @@ func (e InvalidByteError) Error() string { // DecodedLen returns the length of a decoding of x source bytes. // Specifically, it returns x / 2. -func DecodedLen(x int) int { return x / 2 } +func DecodedLen(x int) int { return x / 2 } // Decode decodes src into DecodedLen(len(src)) bytes, // returning the actual number of bytes written to dst. @@ -126,9 +126,9 @@ func Dump(data []byte) string { const bufferSize = 1024 type encoder struct { - w io.Writer - err error - out [bufferSize]byte // output buffer + w io.Writer + err error + out [bufferSize]byte // output buffer } // NewEncoder returns an io.Writer that writes lowercase hexadecimal characters to w. @@ -153,10 +153,10 @@ func (e *encoder) Write(p []byte) (n int, err error) { } type decoder struct { - r io.Reader - err error - in []byte // input buffer (encoded form) - arr [bufferSize]byte // backing array for in + r io.Reader + err error + in []byte // input buffer (encoded form) + arr [bufferSize]byte // backing array for in } // NewDecoder returns an io.Reader that decodes hexadecimal characters from r. @@ -169,7 +169,7 @@ func (d *decoder) Read(p []byte) (n int, err error) { // Fill internal buffer with sufficient bytes to decode if len(d.in) < 2 && d.err == nil { var numCopy, numRead int - numCopy = copy(d.arr[:], d.in) // Copies either 0 or 1 bytes + numCopy = copy(d.arr[:], d.in) // Copies either 0 or 1 bytes numRead, d.err = d.r.Read(d.arr[numCopy:]) d.in = d.arr[:numCopy+numRead] if d.err == io.EOF && len(d.in)%2 != 0 { @@ -188,11 +188,11 @@ func (d *decoder) Read(p []byte) (n int, err error) { numDec, err := Decode(p, d.in[:len(p)*2]) d.in = d.in[2*numDec:] if err != nil { - d.in, d.err = nil, err // Decode error; discard input remainder + d.in, d.err = nil, err // Decode error; discard input remainder } if len(d.in) < 2 { - return numDec, d.err // Only expose errors when buffer fully consumed + return numDec, d.err // Only expose errors when buffer fully consumed } return numDec, nil } @@ -205,12 +205,12 @@ func Dumper(w io.Writer) io.WriteCloser { } type dumper struct { - w io.Writer - rightChars [18]byte - buf [14]byte - used int // number of bytes in the current line - n uint // number of bytes, total - closed bool + w io.Writer + rightChars [18]byte + buf [14]byte + used int // number of bytes in the current line + n uint // number of bytes, total + closed bool } func toChar(b byte) byte { diff --git a/v2/file/resolver/hex_gzip.go b/v2/file/resolver/hex_gzip.go index 251b2dd..b72de0e 100644 --- a/v2/file/resolver/hex_gzip.go +++ b/v2/file/resolver/hex_gzip.go @@ -18,9 +18,9 @@ import ( var _ Resolver = &HexGzip{} type HexGzip struct { - packed map[string]string - unpacked map[string]string - moot *sync.RWMutex + packed map[string]string + unpacked map[string]string + moot *sync.RWMutex } func (hg HexGzip) String() string { @@ -77,9 +77,9 @@ func NewHexGzip(files map[string]string) (*HexGzip, error) { } hg := &HexGzip{ - packed: files, - unpacked: map[string]string{}, - moot: &sync.RWMutex{}, + packed: files, + unpacked: map[string]string{}, + moot: &sync.RWMutex{}, } return hg, nil diff --git a/v2/file/resolver/ident_test.go b/v2/file/resolver/ident_test.go index ef0a97f..298123b 100644 --- a/v2/file/resolver/ident_test.go +++ b/v2/file/resolver/ident_test.go @@ -9,8 +9,8 @@ import ( func Test_Ident_OsPath(t *testing.T) { table := map[string]string{ - "foo/bar/baz": "foo/bar/baz", - "foo\\bar\\baz": "foo/bar/baz", + "foo/bar/baz": "foo/bar/baz", + "foo\\bar\\baz": "foo/bar/baz", } if runtime.GOOS == "windows" { @@ -27,7 +27,7 @@ func Test_Ident_OsPath(t *testing.T) { func ident_OsPath_Windows_Table() map[string]string { return map[string]string{ - "foo/bar/baz": "foo\\bar\\baz", - "foo\\bar\\baz": "foo\\bar\\baz", + "foo/bar/baz": "foo\\bar\\baz", + "foo\\bar\\baz": "foo\\bar\\baz", } } diff --git a/v2/go.mod b/v2/go.mod index 079c8a3..2568354 100644 --- a/v2/go.mod +++ b/v2/go.mod @@ -6,11 +6,10 @@ require ( github.com/gobuffalo/envy v1.7.1 github.com/gobuffalo/logger v1.0.1 github.com/gobuffalo/packd v0.3.0 - github.com/karrick/godirwalk v1.11.3 github.com/rogpeppe/go-internal v1.4.0 github.com/sirupsen/logrus v1.4.2 github.com/spf13/cobra v0.0.5 github.com/stretchr/testify v1.4.0 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e - golang.org/x/tools v0.0.0-20190930152728-90aeebe84374 + golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3 ) diff --git a/v2/go.sum b/v2/go.sum index cd301e1..5778e95 100644 --- a/v2/go.sum +++ b/v2/go.sum @@ -20,8 +20,6 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/karrick/godirwalk v1.11.3 h1:ZrtYOzzHRzItdU1MvkK3CLlhC4m3YTWFgGyiBuSCQSY= -github.com/karrick/godirwalk v1.11.3/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -65,7 +63,6 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4 h1:ydJNl0ENAG67pFbB+9tfhiL2pYqLhfoaZFw/cjLhY4A= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= @@ -77,8 +74,8 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190515120540-06a5c4944438 h1:khxRGsvPk4n2y8I/mLLjp7e5dMTJmH75wvqS6nMwUtY= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20190930152728-90aeebe84374 h1:gtmDBXipY3qmHzbMZV3Y7rPqd9/Y+p7kvA6JxRsBQO0= -golang.org/x/tools v0.0.0-20190930152728-90aeebe84374/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3 h1:2AmBLzhAfXj+2HCW09VCkJtHIYgHTIPcTeYqgP7Bwt0= +golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= diff --git a/v2/helpers.go b/v2/helpers.go index 072afcb..3654dff 100644 --- a/v2/helpers.go +++ b/v2/helpers.go @@ -12,11 +12,11 @@ import ( func construct(name string, path string) *Box { return &Box{ - Path: path, - Name: name, - ResolutionDir: resolutionDir(path), - resolvers: resolversMap{}, - dirs: dirsMap{}, + Path: path, + Name: name, + ResolutionDir: resolutionDir(path), + resolvers: resolversMap{}, + dirs: dirsMap{}, } } diff --git a/v2/internal/takeon/github.com/karrick/godirwalk/LICENSE b/v2/internal/takeon/github.com/karrick/godirwalk/LICENSE new file mode 100644 index 0000000..01ce194 --- /dev/null +++ b/v2/internal/takeon/github.com/karrick/godirwalk/LICENSE @@ -0,0 +1,25 @@ +BSD 2-Clause License + +Copyright (c) 2017, Karrick McDermott +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. + +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 HOLDER 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/v2/internal/takeon/github.com/karrick/godirwalk/README.md b/v2/internal/takeon/github.com/karrick/godirwalk/README.md new file mode 100644 index 0000000..e2ba74c --- /dev/null +++ b/v2/internal/takeon/github.com/karrick/godirwalk/README.md @@ -0,0 +1,215 @@ +# godirwalk + +`godirwalk` is a library for traversing a directory tree on a file +system. + +[![GoDoc](https://godoc.org/github.com/karrick/godirwalk?status.svg)](https://godoc.org/github.com/karrick/godirwalk) [![Build Status](https://dev.azure.com/microsoft0235/microsoft/_apis/build/status/karrick.godirwalk?branchName=master)](https://dev.azure.com/microsoft0235/microsoft/_build/latest?definitionId=1&branchName=master) + +In short, why do I use this library? + +1. It's faster than `filepath.Walk`. +1. It's more correct on Windows than `filepath.Walk`. +1. It's more easy to use than `filepath.Walk`. +1. It's more flexible than `filepath.Walk`. + +## Usage Example + +Additional examples are provided in the `examples/` subdirectory. + +This library will normalize the provided top level directory name +based on the os-specific path separator by calling `filepath.Clean` on +its first argument. However it always provides the pathname created by +using the correct os-specific path separator when invoking the +provided callback function. + +```Go + dirname := "some/directory/root" + err := godirwalk.Walk(dirname, &godirwalk.Options{ + Callback: func(osPathname string, de *godirwalk.Dirent) error { + fmt.Printf("%s %s\n", de.ModeType(), osPathname) + return nil + }, + Unsorted: true, // (optional) set true for faster yet non-deterministic enumeration (see godoc) + }) +``` + +This library not only provides functions for traversing a file system +directory tree, but also for obtaining a list of immediate descendants +of a particular directory, typically much more quickly than using +`os.ReadDir` or `os.ReadDirnames`. + +## Description + +Here's why I use `godirwalk` in preference to `filepath.Walk`, +`os.ReadDir`, and `os.ReadDirnames`. + +### It's faster than `filepath.Walk` + +When compared against `filepath.Walk` in benchmarks, it has been +observed to run between five and ten times the speed on darwin, at +speeds comparable to the that of the unix `find` utility; about twice +the speed on linux; and about four times the speed on Windows. + +How does it obtain this performance boost? It does less work to give +you nearly the same output. This library calls the same `syscall` +functions to do the work, but it makes fewer calls, does not throw +away information that it might need, and creates less memory churn +along the way by reusing the same scratch buffer for reading from a +directory rather than reallocating a new buffer every time it reads +file system entry data from the operating system. + +While traversing a file system directory tree, `filepath.Walk` obtains +the list of immediate descendants of a directory, and throws away the +file system node type information provided by the operating system +that comes with the node's name. Then, immediately prior to invoking +the callback function, `filepath.Walk` invokes `os.Stat` for each +node, and passes the returned `os.FileInfo` information to the +callback. + +While the `os.FileInfo` information provided by `os.Stat` is extremely +helpful--and even includes the `os.FileMode` data--providing it +requires an additional system call for each node. + +Because most callbacks only care about what the node type is, this +library does not throw the type information away, but rather provides +that information to the callback function in the form of a +`os.FileMode` value. Note that the provided `os.FileMode` value that +this library provides only has the node type information, and does not +have the permission bits, sticky bits, or other information from the +file's mode. If the callback does care about a particular node's +entire `os.FileInfo` data structure, the callback can easiy invoke +`os.Stat` when needed, and only when needed. + +#### Benchmarks + +##### macOS + +```Bash +$ go test -bench=. -benchmem +goos: darwin +goarch: amd64 +pkg: github.com/karrick/godirwalk +BenchmarkReadDirnamesStandardLibrary-12 50000 26250 ns/op 10360 B/op 16 allocs/op +BenchmarkReadDirnamesThisLibrary-12 50000 24372 ns/op 5064 B/op 20 allocs/op +BenchmarkFilepathWalk-12 1 1099524875 ns/op 228415912 B/op 416952 allocs/op +BenchmarkGodirwalk-12 2 526754589 ns/op 103110464 B/op 451442 allocs/op +BenchmarkGodirwalkUnsorted-12 3 509219296 ns/op 100751400 B/op 378800 allocs/op +BenchmarkFlameGraphFilepathWalk-12 1 7478618820 ns/op 2284138176 B/op 4169453 allocs/op +BenchmarkFlameGraphGodirwalk-12 1 4977264058 ns/op 1031105328 B/op 4514423 allocs/op +PASS +ok github.com/karrick/godirwalk 21.219s +``` + +##### Linux + +```Bash +$ go test -bench=. -benchmem +goos: linux +goarch: amd64 +pkg: github.com/karrick/godirwalk +BenchmarkReadDirnamesStandardLibrary-12 100000 15458 ns/op 10360 B/op 16 allocs/op +BenchmarkReadDirnamesThisLibrary-12 100000 14646 ns/op 5064 B/op 20 allocs/op +BenchmarkFilepathWalk-12 2 631034745 ns/op 228210216 B/op 416939 allocs/op +BenchmarkGodirwalk-12 3 358714883 ns/op 102988664 B/op 451437 allocs/op +BenchmarkGodirwalkUnsorted-12 3 355363915 ns/op 100629234 B/op 378796 allocs/op +BenchmarkFlameGraphFilepathWalk-12 1 6086913991 ns/op 2282104720 B/op 4169417 allocs/op +BenchmarkFlameGraphGodirwalk-12 1 3456398824 ns/op 1029886400 B/op 4514373 allocs/op +PASS +ok github.com/karrick/godirwalk 19.179s +``` + +### It's more correct on Windows than `filepath.Walk` + +I did not previously care about this either, but humor me. We all love +how we can write once and run everywhere. It is essential for the +language's adoption, growth, and success, that the software we create +can run unmodified on all architectures and operating systems +supported by Go. + +When the traversed file system has a logical loop caused by symbolic +links to directories, on unix `filepath.Walk` ignores symbolic links +and traverses the entire directory tree without error. On Windows +however, `filepath.Walk` will continue following directory symbolic +links, even though it is not supposed to, eventually causing +`filepath.Walk` to terminate early and return an error when the +pathname gets too long from concatenating endless loops of symbolic +links onto the pathname. This error comes from Windows, passes through +`filepath.Walk`, and to the upstream client running `filepath.Walk`. + +The takeaway is that behavior is different based on which platform +`filepath.Walk` is running. While this is clearly not intentional, +until it is fixed in the standard library, it presents a compatibility +problem. + +This library correctly identifies symbolic links that point to +directories and will only follow them when `FollowSymbolicLinks` is +set to true. Behavior on Windows and other operating systems is +identical. + +### It's more easy to use than `filepath.Walk` + +Since this library does not invoke `os.Stat` on every file system node +it encounters, there is no possible error event for the callback +function to filter on. The third argument in the `filepath.WalkFunc` +function signature to pass the error from `os.Stat` to the callback +function is no longer necessary, and thus eliminated from signature of +the callback function from this library. + +Also, `filepath.Walk` invokes the callback function with a solidus +delimited pathname regardless of the os-specific path separator. This +library invokes the callback function with the os-specific pathname +separator, obviating a call to `filepath.Clean` in the callback +function for each node prior to actually using the provided pathname. + +In other words, even on Windows, `filepath.Walk` will invoke the +callback with `some/path/to/foo.txt`, requiring well written clients +to perform pathname normalization for every file prior to working with +the specified file. In truth, many clients developed on unix and not +tested on Windows neglect this subtlety, and will result in software +bugs when running on Windows. This library would invoke the callback +function with `some\path\to\foo.txt` for the same file when running on +Windows, eliminating the need to normalize the pathname by the client, +and lessen the likelyhood that a client will work on unix but not on +Windows. + +### It's more flexible than `filepath.Walk` + +#### Configurable Handling of Symbolic Links + +The default behavior of this library is to ignore symbolic links to +directories when walking a directory tree, just like `filepath.Walk` +does. However, it does invoke the callback function with each node it +finds, including symbolic links. If a particular use case exists to +follow symbolic links when traversing a directory tree, this library +can be invoked in manner to do so, by setting the +`FollowSymbolicLinks` parameter to true. + +#### Configurable Sorting of Directory Children + +The default behavior of this library is to always sort the immediate +descendants of a directory prior to visiting each node, just like +`filepath.Walk` does. This is usually the desired behavior. However, +this does come at slight performance and memory penalties required to +sort the names when a directory node has many entries. Additionally if +caller specifies `Unsorted` enumeration, reading directories is lazily +performed as the caller consumes entries. If a particular use case +exists that does not require sorting the directory's immediate +descendants prior to visiting its nodes, this library will skip the +sorting step when the `Unsorted` parameter is set to true. + +#### Configurable Post Children Callback + +This library provides upstream code with the ability to specify a +callback to be invoked for each directory after its children are +processed. This has been used to recursively delete empty directories +after traversing the file system in a more efficient manner. See the +`examples/clean-empties` directory for an example of this usage. + +#### Configurable Error Callback + +This library provides upstream code with the ability to specify a +callback to be invoked for errors that the operating system returns, +allowing the upstream code to determine the next course of action to +take, whether to halt walking the hierarchy, as it would do were no +error callback provided, or skip the node that caused the error. See +the `examples/walk-fast` directory for an example of this usage. diff --git a/v2/internal/takeon/github.com/karrick/godirwalk/debug_development.go b/v2/internal/takeon/github.com/karrick/godirwalk/debug_development.go new file mode 100644 index 0000000..6e1cb0b --- /dev/null +++ b/v2/internal/takeon/github.com/karrick/godirwalk/debug_development.go @@ -0,0 +1,14 @@ +// +build godirwalk_debug + +package godirwalk + +import ( + "fmt" + "os" +) + +// debug formats and prints arguments to stderr for development builds +func debug(f string, a ...interface{}) { + // fmt.Fprintf(os.Stderr, f, a...) + os.Stderr.Write([]byte("godirwalk: " + fmt.Sprintf(f, a...))) +} diff --git a/v2/internal/takeon/github.com/karrick/godirwalk/debug_release.go b/v2/internal/takeon/github.com/karrick/godirwalk/debug_release.go new file mode 100644 index 0000000..9861787 --- /dev/null +++ b/v2/internal/takeon/github.com/karrick/godirwalk/debug_release.go @@ -0,0 +1,6 @@ +// +build !godirwalk_debug + +package godirwalk + +// debug is a no-op for release builds +func debug(_ string, _ ...interface{}) {} diff --git a/v2/internal/takeon/github.com/karrick/godirwalk/dirent.go b/v2/internal/takeon/github.com/karrick/godirwalk/dirent.go new file mode 100644 index 0000000..3bee8b2 --- /dev/null +++ b/v2/internal/takeon/github.com/karrick/godirwalk/dirent.go @@ -0,0 +1,90 @@ +package godirwalk + +import ( + "os" + "path/filepath" +) + +// Dirent stores the name and file system mode type of discovered file system +// entries. +type Dirent struct { + name string // name is the basename of the file system entry. + modeType os.FileMode // modeType is the type of file system entry. +} + +// NewDirent returns a newly initialized Dirent structure, or an error. This +// function does not follow symbolic links. +// +// This function is rarely used, as Dirent structures are provided by other +// functions in this library that read and walk directories, but is provided, +// however, for the occasion when a program needs to create a Dirent. +func NewDirent(osPathname string) (*Dirent, error) { + modeType, err := modeType(osPathname) + if err != nil { + return nil, err + } + return &Dirent{ + name: filepath.Base(osPathname), + modeType: modeType, + }, nil +} + +// // dup returns a duplicate of the directory entry. +// func (de Dirent) dup() *Dirent { +// return &Dirent{ +// name: de.name, +// modeType: de.modeType, +// } +// } + +// Name returns the basename of the file system entry. +func (de Dirent) Name() string { return de.name } + +// ModeType returns the mode bits that specify the file system node type. We +// could make our own enum-like data type for encoding the file type, but Go's +// runtime already gives us architecture independent file modes, as discussed in +// `os/types.go`: +// +// Go's runtime FileMode type has same definition on all systems, so that +// information about files can be moved from one system to another portably. +func (de Dirent) ModeType() os.FileMode { return de.modeType } + +// IsDir returns true if and only if the Dirent represents a file system +// directory. Note that on some operating systems, more than one file mode bit +// may be set for a node. For instance, on Windows, a symbolic link that points +// to a directory will have both the directory and the symbolic link bits set. +func (de Dirent) IsDir() bool { return de.modeType&os.ModeDir != 0 } + +// IsRegular returns true if and only if the Dirent represents a regular file. +// That is, it ensures that no mode type bits are set. +func (de Dirent) IsRegular() bool { return de.modeType&os.ModeType == 0 } + +// IsSymlink returns true if and only if the Dirent represents a file system +// symbolic link. Note that on some operating systems, more than one file mode +// bit may be set for a node. For instance, on Windows, a symbolic link that +// points to a directory will have both the directory and the symbolic link bits +// set. +func (de Dirent) IsSymlink() bool { return de.modeType&os.ModeSymlink != 0 } + +// IsDevice returns true if and only if the Dirent represents a device file. +func (de Dirent) IsDevice() bool { return de.modeType&os.ModeDevice != 0 } + +// reset releases memory held by entry err and name, and resets mode type to 0. +func (de *Dirent) reset() { + de.name = "" + de.modeType = 0 +} + +// Dirents represents a slice of Dirent pointers, which are sortable by +// name. This type satisfies the `sort.Interface` interface. +type Dirents []*Dirent + +// Len returns the count of Dirent structures in the slice. +func (l Dirents) Len() int { return len(l) } + +// Less returns true if and only if the Name of the element specified by the +// first index is lexicographically less than that of the second index. +func (l Dirents) Less(i, j int) bool { return l[i].name < l[j].name } + +// Swap exchanges the two Dirent entries specified by the two provided indexes. +func (l Dirents) Swap(i, j int) { l[i], l[j] = l[j], l[i] } diff --git a/v2/internal/takeon/github.com/karrick/godirwalk/doc.go b/v2/internal/takeon/github.com/karrick/godirwalk/doc.go new file mode 100644 index 0000000..1197482 --- /dev/null +++ b/v2/internal/takeon/github.com/karrick/godirwalk/doc.go @@ -0,0 +1,37 @@ +/* +Package godirwalk provides functions to read and traverse directory trees. + +In short, why do I use this library? + +* It's faster than `filepath.Walk`. + +* It's more correct on Windows than `filepath.Walk`. + +* It's more easy to use than `filepath.Walk`. + +* It's more flexible than `filepath.Walk`. + +USAGE + +This library will normalize the provided top level directory name based on the +os-specific path separator by calling `filepath.Clean` on its first +argument. However it always provides the pathname created by using the correct +os-specific path separator when invoking the provided callback function. + + dirname := "some/directory/root" + err := godirwalk.Walk(dirname, &godirwalk.Options{ + Callback: func(osPathname string, de *godirwalk.Dirent) error { + fmt.Printf("%s %s\n", de.ModeType(), osPathname) + return nil + }, + }) + +This library not only provides functions for traversing a file system directory +tree, but also for obtaining a list of immediate descendants of a particular +directory, typically much more quickly than using `os.ReadDir` or +`os.ReadDirnames`. + + dirname := "some/directory" + names, err := godirwalk.ReadDirnames() +*/ +package godirwalk diff --git a/v2/internal/takeon/github.com/karrick/godirwalk/inoWithFileno.go b/v2/internal/takeon/github.com/karrick/godirwalk/inoWithFileno.go new file mode 100644 index 0000000..1dc04a7 --- /dev/null +++ b/v2/internal/takeon/github.com/karrick/godirwalk/inoWithFileno.go @@ -0,0 +1,9 @@ +// +build dragonfly freebsd openbsd netbsd + +package godirwalk + +import "syscall" + +func inoFromDirent(de *syscall.Dirent) uint64 { + return uint64(de.Fileno) +} diff --git a/v2/internal/takeon/github.com/karrick/godirwalk/inoWithIno.go b/v2/internal/takeon/github.com/karrick/godirwalk/inoWithIno.go new file mode 100644 index 0000000..0ec7c52 --- /dev/null +++ b/v2/internal/takeon/github.com/karrick/godirwalk/inoWithIno.go @@ -0,0 +1,10 @@ +// +build aix darwin linux nacl solaris + +package godirwalk + +import "syscall" + +func inoFromDirent(de *syscall.Dirent) uint64 { + // cast necessary on file systems that store ino as different type + return uint64(de.Ino) +} diff --git a/v2/internal/takeon/github.com/karrick/godirwalk/modeType.go b/v2/internal/takeon/github.com/karrick/godirwalk/modeType.go new file mode 100644 index 0000000..6427a68 --- /dev/null +++ b/v2/internal/takeon/github.com/karrick/godirwalk/modeType.go @@ -0,0 +1,22 @@ +package godirwalk + +import ( + "os" +) + +// modeType returns the mode type of the file system entry identified by +// osPathname by calling os.LStat function, to intentionally not follow symbolic +// links. +// +// Even though os.LStat provides all file mode bits, we want to ensure same +// values returned to caller regardless of whether we obtained file mode bits +// from syscall or stat call. Therefore mask out the additional file mode bits +// that are provided by stat but not by the syscall, so users can rely on their +// values. +func modeType(osPathname string) (os.FileMode, error) { + fi, err := os.Lstat(osPathname) + if err == nil { + return fi.Mode() & os.ModeType, nil + } + return 0, err +} diff --git a/v2/internal/takeon/github.com/karrick/godirwalk/modeTypeWithType.go b/v2/internal/takeon/github.com/karrick/godirwalk/modeTypeWithType.go new file mode 100644 index 0000000..7890e77 --- /dev/null +++ b/v2/internal/takeon/github.com/karrick/godirwalk/modeTypeWithType.go @@ -0,0 +1,37 @@ +// +build darwin dragonfly freebsd linux netbsd openbsd + +package godirwalk + +import ( + "os" + "path/filepath" + "syscall" +) + +// modeTypeFromDirent converts a syscall defined constant, which is in purview +// of OS, to a constant defined by Go, assumed by this project to be stable. +// +// When the syscall constant is not recognized, this function falls back to a +// Stat on the file system. +func modeTypeFromDirent(de *syscall.Dirent, osDirname, osBasename string) (os.FileMode, error) { + switch de.Type { + case syscall.DT_REG: + return 0, nil + case syscall.DT_DIR: + return os.ModeDir, nil + case syscall.DT_LNK: + return os.ModeSymlink, nil + case syscall.DT_CHR: + return os.ModeDevice | os.ModeCharDevice, nil + case syscall.DT_BLK: + return os.ModeDevice, nil + case syscall.DT_FIFO: + return os.ModeNamedPipe, nil + case syscall.DT_SOCK: + return os.ModeSocket, nil + default: + // If syscall returned unknown type (e.g., DT_UNKNOWN, DT_WHT), then + // resolve actual mode by reading file information. + return modeType(filepath.Join(osDirname, osBasename)) + } +} diff --git a/v2/internal/takeon/github.com/karrick/godirwalk/modeTypeWithoutType.go b/v2/internal/takeon/github.com/karrick/godirwalk/modeTypeWithoutType.go new file mode 100644 index 0000000..5299392 --- /dev/null +++ b/v2/internal/takeon/github.com/karrick/godirwalk/modeTypeWithoutType.go @@ -0,0 +1,18 @@ +// +build aix js nacl solaris + +package godirwalk + +import ( + "os" + "path/filepath" + "syscall" +) + +// modeTypeFromDirent converts a syscall defined constant, which is in purview +// of OS, to a constant defined by Go, assumed by this project to be stable. +// +// Because some operating system syscall.Dirent structures do not include a Type +// field, fall back on Stat of the file system. +func modeTypeFromDirent(_ *syscall.Dirent, osDirname, osBasename string) (os.FileMode, error) { + return modeType(filepath.Join(osDirname, osBasename)) +} diff --git a/v2/internal/takeon/github.com/karrick/godirwalk/nameWithNamlen.go b/v2/internal/takeon/github.com/karrick/godirwalk/nameWithNamlen.go new file mode 100644 index 0000000..2c0231e --- /dev/null +++ b/v2/internal/takeon/github.com/karrick/godirwalk/nameWithNamlen.go @@ -0,0 +1,29 @@ +// +build aix darwin dragonfly freebsd netbsd openbsd + +package godirwalk + +import ( + "reflect" + "syscall" + "unsafe" +) + +func nameFromDirent(de *syscall.Dirent) []byte { + // Because this GOOS' syscall.Dirent provides a Namlen field that says how + // long the name is, this function does not need to search for the NULL + // byte. + ml := int(de.Namlen) + + // Convert syscall.Dirent.Name, which is array of int8, to []byte, by + // overwriting Cap, Len, and Data slice header fields to values from + // syscall.Dirent fields. Setting the Cap, Len, and Data field values for + // the slice header modifies what the slice header points to, and in this + // case, the name buffer. + var name []byte + sh := (*reflect.SliceHeader)(unsafe.Pointer(&name)) + sh.Cap = ml + sh.Len = ml + sh.Data = uintptr(unsafe.Pointer(&de.Name[0])) + + return name +} diff --git a/v2/internal/takeon/github.com/karrick/godirwalk/nameWithoutNamlen.go b/v2/internal/takeon/github.com/karrick/godirwalk/nameWithoutNamlen.go new file mode 100644 index 0000000..f776fbc --- /dev/null +++ b/v2/internal/takeon/github.com/karrick/godirwalk/nameWithoutNamlen.go @@ -0,0 +1,42 @@ +// +build nacl linux js solaris + +package godirwalk + +import ( + "bytes" + "reflect" + "syscall" + "unsafe" +) + +// nameOffset is a compile time constant +const nameOffset = int(unsafe.Offsetof(syscall.Dirent{}.Name)) + +func nameFromDirent(de *syscall.Dirent) (name []byte) { + // Because this GOOS' syscall.Dirent does not provide a field that specifies + // the name length, this function must first calculate the max possible name + // length, and then search for the NULL byte. + ml := int(de.Reclen) - nameOffset + + // Convert syscall.Dirent.Name, which is array of int8, to []byte, by + // overwriting Cap, Len, and Data slice header fields to the max possible + // name length computed above, and finding the terminating NULL byte. + sh := (*reflect.SliceHeader)(unsafe.Pointer(&name)) + sh.Cap = ml + sh.Len = ml + sh.Data = uintptr(unsafe.Pointer(&de.Name[0])) + + if index := bytes.IndexByte(name, 0); index >= 0 { + // Found NULL byte; set slice's cap and len accordingly. + sh.Cap = index + sh.Len = index + return + } + + // NOTE: This branch is not expected, but included for defensive + // programming, and provides a hard stop on the name based on the structure + // field array size. + sh.Cap = len(de.Name) + sh.Len = sh.Cap + return +} diff --git a/v2/internal/takeon/github.com/karrick/godirwalk/readdir.go b/v2/internal/takeon/github.com/karrick/godirwalk/readdir.go new file mode 100644 index 0000000..33cdbe3 --- /dev/null +++ b/v2/internal/takeon/github.com/karrick/godirwalk/readdir.go @@ -0,0 +1,73 @@ +package godirwalk + +// ReadDirents returns a sortable slice of pointers to Dirent structures, each +// representing the file system name and mode type for one of the immediate +// descendant of the specified directory. If the specified directory is a +// symbolic link, it will be resolved. +// +// The second parameter was an optional scratch buffer, but is no longer used +// because ReadDirents invokes Scanner to enumerate the contents of the +// directory. +// +// children, err := godirwalk.ReadDirents(osDirname, nil) +// if err != nil { +// return nil, errors.Wrap(err, "cannot get list of directory children") +// } +// sort.Sort(children) +// for _, child := range children { +// fmt.Printf("%s %s\n", child.ModeType, child.Name) +// } +func ReadDirents(osDirname string, _ []byte) (Dirents, error) { + var entries Dirents + scanner, err := NewScanner(osDirname) + if err != nil { + return nil, err + } + for scanner.Scan() { + if dirent, err := scanner.Dirent(); err == nil { + entries = append(entries, dirent) + } + } + if err = scanner.Err(); err != nil { + return nil, err + } + return entries, nil +} + +// ReadDirnames returns a slice of strings, representing the immediate +// descendants of the specified directory. If the specified directory is a +// symbolic link, it will be resolved. +// +// The second parameter was an optional scratch buffer, but is no longer used +// because ReadDirents invokes Scanner to enumerate the contents of the +// directory. +// +// Note that this function, depending on operating system, may or may not invoke +// the ReadDirents function, in order to prepare the list of immediate +// descendants. Therefore, if your program needs both the names and the file +// system mode types of descendants, it will always be faster to invoke +// ReadDirents directly, rather than calling this function, then looping over +// the results and calling os.Stat or os.LStat for each entry. +// +// children, err := godirwalk.ReadDirnames(osDirname, nil) +// if err != nil { +// return nil, errors.Wrap(err, "cannot get list of directory children") +// } +// sort.Strings(children) +// for _, child := range children { +// fmt.Printf("%s\n", child) +// } +func ReadDirnames(osDirname string, _ []byte) ([]string, error) { + var entries []string + scanner, err := NewScanner(osDirname) + if err != nil { + return nil, err + } + for scanner.Scan() { + entries = append(entries, scanner.Name()) + } + if err = scanner.Err(); err != nil { + return nil, err + } + return entries, nil +} diff --git a/v2/internal/takeon/github.com/karrick/godirwalk/scandir_unix.go b/v2/internal/takeon/github.com/karrick/godirwalk/scandir_unix.go new file mode 100644 index 0000000..f9a4f7e --- /dev/null +++ b/v2/internal/takeon/github.com/karrick/godirwalk/scandir_unix.go @@ -0,0 +1,140 @@ +// +build !windows + +package godirwalk + +import ( + "io" + "os" + "syscall" + "unsafe" +) + +// MinimumScratchBufferSize specifies the minimum size of the scratch buffer +// that Walk, ReadDirents, ReadDirnames, and Scandir will use when reading file +// entries from the operating system. It is initialized to the result from +// calling `os.Getpagesize()` during program startup. +var MinimumScratchBufferSize = os.Getpagesize() + +// Scanner is an iterator to enumerate the contents of a directory. +type Scanner struct { + scratchBuffer []byte // read directory bytes from file system into this buffer + workBuffer []byte // points into scratchBuffer, from which we chunk out directory entries + osDirname string + childName string + err error // err is the error associated with scanning directory + statErr error // statErr is any error return while attempting to stat an entry + dh *os.File // used to close directory after done reading + de *Dirent // most recently decoded directory entry + sde *syscall.Dirent + fd int // file descriptor used to read entries from directory +} + +// NewScanner returns a new directory Scanner. +func NewScanner(osDirname string) (*Scanner, error) { + dh, err := os.Open(osDirname) + if err != nil { + return nil, err + } + scanner := &Scanner{ + scratchBuffer: make([]byte, MinimumScratchBufferSize), + osDirname: osDirname, + dh: dh, + fd: int(dh.Fd()), + } + return scanner, nil +} + +// Dirent returns the current directory entry while scanning a directory. +func (s *Scanner) Dirent() (*Dirent, error) { + if s.de == nil { + s.de = &Dirent{name: s.childName} + s.de.modeType, s.statErr = modeTypeFromDirent(s.sde, s.osDirname, s.childName) + } + return s.de, s.statErr +} + +// done is called when directory scanner unable to continue, with either the +// triggering error, or nil when there are simply no more entries to read from +// the directory. +func (s *Scanner) done(err error) { + if s.dh == nil { + return + } + cerr := s.dh.Close() + s.dh = nil + + if err == nil { + s.err = cerr + } else { + s.err = err + } + + s.osDirname, s.childName = "", "" + s.scratchBuffer, s.workBuffer = nil, nil + s.statErr, s.de, s.sde = nil, nil, nil + s.fd = 0 +} + +// Err returns the error associated with scanning a directory. +func (s *Scanner) Err() error { + s.done(s.err) + if s.err == io.EOF { + return nil + } + return s.err +} + +// Name returns the name of the current directory entry while scanning a +// directory. +func (s *Scanner) Name() string { return s.childName } + +// Scan potentially reads and then decodes the next directory entry from the +// file system. +// +// When it returns false, this releases resources used by the Scanner then +// returns any error associated with closing the file system directory resource. +func (s *Scanner) Scan() bool { + if s.err != nil { + return false + } + + for { + // When the work buffer has nothing remaining to decode, we need to load + // more data from disk. + if len(s.workBuffer) == 0 { + n, err := syscall.ReadDirent(s.fd, s.scratchBuffer) + if err != nil { + s.done(err) + return false + } + if n <= 0 { // end of directory + s.done(io.EOF) + return false + } + s.workBuffer = s.scratchBuffer[:n] // trim work buffer to number of bytes read + } + + // Loop until we have a usable file system entry, or we run out of data + // in the work buffer. + for len(s.workBuffer) > 0 { + s.sde = (*syscall.Dirent)(unsafe.Pointer(&s.workBuffer[0])) // point entry to first syscall.Dirent in buffer + s.workBuffer = s.workBuffer[s.sde.Reclen:] // advance buffer for next iteration through loop + + if inoFromDirent(s.sde) == 0 { + continue // inode set to 0 indicates an entry that was marked as deleted + } + + nameSlice := nameFromDirent(s.sde) + namlen := len(nameSlice) + if namlen == 0 || (nameSlice[0] == '.' && (namlen == 1 || (namlen == 2 && nameSlice[1] == '.'))) { + continue + } + + s.de = nil + s.childName = string(nameSlice) + return true + } + // No more data in the work buffer, so loop around in the outside loop + // to fetch more data. + } +} diff --git a/v2/internal/takeon/github.com/karrick/godirwalk/scandir_windows.go b/v2/internal/takeon/github.com/karrick/godirwalk/scandir_windows.go new file mode 100644 index 0000000..c91e279 --- /dev/null +++ b/v2/internal/takeon/github.com/karrick/godirwalk/scandir_windows.go @@ -0,0 +1,92 @@ +// +build windows + +package godirwalk + +import ( + "fmt" + "io" + "os" +) + +// Scanner is an iterator to enumerate the contents of a directory. +type Scanner struct { + osDirname string + dh *os.File // dh is handle to open directory + de *Dirent + err error // err is the error associated with scanning directory +} + +// NewScanner returns a new directory Scanner. +func NewScanner(osDirname string) (*Scanner, error) { + dh, err := os.Open(osDirname) + if err != nil { + return nil, err + } + scanner := &Scanner{ + osDirname: osDirname, + dh: dh, + } + return scanner, nil +} + +// Dirent returns the current directory entry while scanning a directory. +func (s *Scanner) Dirent() (*Dirent, error) { return s.de, nil } + +// done is called when directory scanner unable to continue, with either the +// triggering error, or nil when there are simply no more entries to read from +// the directory. +func (s *Scanner) done(err error) { + if s.dh == nil { + return + } + cerr := s.dh.Close() + s.dh = nil + + if err == nil { + s.err = cerr + } else { + s.err = err + } + + s.osDirname = "" + s.de = nil +} + +// Err returns the error associated with scanning a directory. +func (s *Scanner) Err() error { + s.done(s.err) + if s.err == io.EOF { + return nil + } + return s.err +} + +// Name returns the name of the current directory entry while scanning a +// directory. +func (s *Scanner) Name() string { return s.de.name } + +// Scan potentially reads and then decodes the next directory entry from the +// file system. +func (s *Scanner) Scan() bool { + if s.err != nil { + return false + } + + fileinfos, err := s.dh.Readdir(1) + if err != nil { + s.err = err + return false + } + + if l := len(fileinfos); l != 1 { + s.err = fmt.Errorf("expected a single entry rather than %d", l) + return false + } + + fi := fileinfos[0] + s.de = &Dirent{ + name: fi.Name(), + modeType: fi.Mode() & os.ModeType, + } + return true +} diff --git a/v2/internal/takeon/github.com/karrick/godirwalk/scanner.go b/v2/internal/takeon/github.com/karrick/godirwalk/scanner.go new file mode 100644 index 0000000..1abf383 --- /dev/null +++ b/v2/internal/takeon/github.com/karrick/godirwalk/scanner.go @@ -0,0 +1,44 @@ +package godirwalk + +import "sort" + +type scanner interface { + Dirent() (*Dirent, error) + Err() error + Name() string + Scan() bool +} + +// sortedScanner enumerates through a directory's contents after reading the +// entire directory and sorting the entries by name. Used by walk to simplify +// its implementation. +type sortedScanner struct { + dd []*Dirent + de *Dirent +} + +func newSortedScanner(osPathname string) (*sortedScanner, error) { + deChildren, err := ReadDirents(osPathname, nil) + if err != nil { + return nil, err + } + sort.Sort(deChildren) + return &sortedScanner{dd: deChildren}, nil +} + +func (d *sortedScanner) Err() error { + d.dd, d.de = nil, nil + return nil +} + +func (d *sortedScanner) Dirent() (*Dirent, error) { return d.de, nil } + +func (d *sortedScanner) Name() string { return d.de.name } + +func (d *sortedScanner) Scan() bool { + if len(d.dd) > 0 { + d.de, d.dd = d.dd[0], d.dd[1:] + return true + } + return false +} diff --git a/v2/internal/takeon/github.com/karrick/godirwalk/symdir.go b/v2/internal/takeon/github.com/karrick/godirwalk/symdir.go new file mode 100644 index 0000000..d3f7eb0 --- /dev/null +++ b/v2/internal/takeon/github.com/karrick/godirwalk/symdir.go @@ -0,0 +1,22 @@ +package godirwalk + +import "os" + +func isDirectoryOrSymlinkToDirectory(de *Dirent, osPathname string) (bool, error) { + if de.IsDir() { + return true, nil + } + return isSymlinkToDirectory(de, osPathname) +} + +func isSymlinkToDirectory(de *Dirent, osPathname string) (bool, error) { + if !de.IsSymlink() { + return false, nil + } + // Need to resolve the symbolic link's referent in order to respond. + info, err := os.Stat(osPathname) + if err != nil { + return false, err + } + return info.IsDir(), nil +} diff --git a/v2/internal/takeon/github.com/karrick/godirwalk/walk.go b/v2/internal/takeon/github.com/karrick/godirwalk/walk.go new file mode 100644 index 0000000..7f4fcd9 --- /dev/null +++ b/v2/internal/takeon/github.com/karrick/godirwalk/walk.go @@ -0,0 +1,316 @@ +package godirwalk + +import ( + "errors" + "fmt" + "os" + "path/filepath" +) + +// DefaultScratchBuffer is a deprecated config parameter, whose usage was +// obsoleted by the introduction of the Scanner struct, and migrating +// ReadDirents, ReadDirnames, and Walk to use Scanner for enumerating directory +// contents. +const DefaultScratchBufferSize = 0 + +// Options provide parameters for how the Walk function operates. +type Options struct { + // ErrorCallback specifies a function to be invoked in the case of an error + // that could potentially be ignored while walking a file system + // hierarchy. When set to nil or left as its zero-value, any error condition + // causes Walk to immediately return the error describing what took + // place. When non-nil, this user supplied function is invoked with the OS + // pathname of the file system object that caused the error along with the + // error that took place. The return value of the supplied ErrorCallback + // function determines whether the error will cause Walk to halt immediately + // as it would were no ErrorCallback value provided, or skip this file + // system node yet continue on with the remaining nodes in the file system + // hierarchy. + // + // ErrorCallback is invoked both for errors that are returned by the + // runtime, and for errors returned by other user supplied callback + // functions. + ErrorCallback func(string, error) ErrorAction + + // FollowSymbolicLinks specifies whether Walk will follow symbolic links + // that refer to directories. When set to false or left as its zero-value, + // Walk will still invoke the callback function with symbolic link nodes, + // but if the symbolic link refers to a directory, it will not recurse on + // that directory. When set to true, Walk will recurse on symbolic links + // that refer to a directory. + FollowSymbolicLinks bool + + // Unsorted controls whether or not Walk will sort the immediate descendants + // of a directory by their relative names prior to visiting each of those + // entries. + // + // When set to false or left at its zero-value, Walk will get the list of + // immediate descendants of a particular directory, sort that list by + // lexical order of their names, and then visit each node in the list in + // sorted order. This will cause Walk to always traverse the same directory + // tree in the same order, however may be inefficient for directories with + // many immediate descendants. + // + // When set to true, Walk skips sorting the list of immediate descendants + // for a directory, and simply visits each node in the order the operating + // system enumerated them. This will be more fast, but with the side effect + // that the traversal order may be different from one invocation to the + // next. + Unsorted bool + + // Callback is a required function that Walk will invoke for every file + // system node it encounters. + Callback WalkFunc + + // PostChildrenCallback is an option function that Walk will invoke for + // every file system directory it encounters after its children have been + // processed. + PostChildrenCallback WalkFunc + + // ScratchBuffer is a deprecated config parameter, whose usage was obsoleted + // by the introduction of the Scanner struct, and migrating ReadDirents, + // ReadDirnames, and Walk to use Scanner for enumerating directory contents. + ScratchBuffer []byte +} + +// ErrorAction defines a set of actions the Walk function could take based on +// the occurrence of an error while walking the file system. See the +// documentation for the ErrorCallback field of the Options structure for more +// information. +type ErrorAction int + +const ( + // Halt is the ErrorAction return value when the upstream code wants to halt + // the walk process when a runtime error takes place. It matches the default + // action the Walk function would take were no ErrorCallback provided. + Halt ErrorAction = iota + + // SkipNode is the ErrorAction return value when the upstream code wants to + // ignore the runtime error for the current file system node, skip + // processing of the node that caused the error, and continue walking the + // file system hierarchy with the remaining nodes. + SkipNode +) + +// WalkFunc is the type of the function called for each file system node visited +// by Walk. The pathname argument will contain the argument to Walk as a prefix; +// that is, if Walk is called with "dir", which is a directory containing the +// file "a", the provided WalkFunc will be invoked with the argument "dir/a", +// using the correct os.PathSeparator for the Go Operating System architecture, +// GOOS. The directory entry argument is a pointer to a Dirent for the node, +// providing access to both the basename and the mode type of the file system +// node. +// +// If an error is returned by the Callback or PostChildrenCallback functions, +// and no ErrorCallback function is provided, processing stops. If an +// ErrorCallback function is provided, then it is invoked with the OS pathname +// of the node that caused the error along along with the error. The return +// value of the ErrorCallback function determines whether to halt processing, or +// skip this node and continue processing remaining file system nodes. +// +// The exception is when the function returns the special value +// filepath.SkipDir. If the function returns filepath.SkipDir when invoked on a +// directory, Walk skips the directory's contents entirely. If the function +// returns filepath.SkipDir when invoked on a non-directory file system node, +// Walk skips the remaining files in the containing directory. Note that any +// supplied ErrorCallback function is not invoked with filepath.SkipDir when the +// Callback or PostChildrenCallback functions return that special value. +type WalkFunc func(osPathname string, directoryEntry *Dirent) error + +// Walk walks the file tree rooted at the specified directory, calling the +// specified callback function for each file system node in the tree, including +// root, symbolic links, and other node types. The nodes are walked in lexical +// order, which makes the output deterministic but means that for very large +// directories this function can be inefficient. +// +// This function is often much faster than filepath.Walk because it does not +// invoke os.Stat for every node it encounters, but rather obtains the file +// system node type when it reads the parent directory. +// +// If a runtime error occurs, either from the operating system or from the +// upstream Callback or PostChildrenCallback functions, processing typically +// halts. However, when an ErrorCallback function is provided in the provided +// Options structure, that function is invoked with the error along with the OS +// pathname of the file system node that caused the error. The ErrorCallback +// function's return value determines the action that Walk will then take. +// +// func main() { +// dirname := "." +// if len(os.Args) > 1 { +// dirname = os.Args[1] +// } +// err := godirwalk.Walk(dirname, &godirwalk.Options{ +// Callback: func(osPathname string, de *godirwalk.Dirent) error { +// fmt.Printf("%s %s\n", de.ModeType(), osPathname) +// return nil +// }, +// ErrorCallback: func(osPathname string, err error) godirwalk.ErrorAction { +// // Your program may want to log the error somehow. +// fmt.Fprintf(os.Stderr, "ERROR: %s\n", err) +// +// // For the purposes of this example, a simple SkipNode will suffice, +// // although in reality perhaps additional logic might be called for. +// return godirwalk.SkipNode +// }, +// }) +// if err != nil { +// fmt.Fprintf(os.Stderr, "%s\n", err) +// os.Exit(1) +// } +// } +func Walk(pathname string, options *Options) error { + if options.Callback == nil { + return errors.New("cannot walk without a specified Callback function") + } + + pathname = filepath.Clean(pathname) + + var fi os.FileInfo + var err error + + if options.FollowSymbolicLinks { + fi, err = os.Stat(pathname) + if err != nil { + return err + } + } else { + fi, err = os.Lstat(pathname) + if err != nil { + return err + } + } + + mode := fi.Mode() + if mode&os.ModeDir == 0 { + return fmt.Errorf("cannot Walk non-directory: %s", pathname) + } + + // If ErrorCallback is nil, set to a default value that halts the walk + // process on all operating system errors. This is done to allow error + // handling to be more succinct in the walk code. + if options.ErrorCallback == nil { + options.ErrorCallback = defaultErrorCallback + } + + dirent := &Dirent{ + name: filepath.Base(pathname), + modeType: mode & os.ModeType, + } + + err = walk(pathname, dirent, options) + if err == filepath.SkipDir { + return nil // silence SkipDir for top level + } + return err +} + +// defaultErrorCallback always returns Halt because if the upstream code did not +// provide an ErrorCallback function, walking the file system hierarchy ought to +// halt upon any operating system error. +func defaultErrorCallback(_ string, _ error) ErrorAction { return Halt } + +// walk recursively traverses the file system node specified by pathname and the +// Dirent. +func walk(osPathname string, dirent *Dirent, options *Options) error { + err := options.Callback(osPathname, dirent) + if err != nil { + if err == filepath.SkipDir { + return err + } + if action := options.ErrorCallback(osPathname, err); action == SkipNode { + return nil + } + return err + } + + if dirent.IsSymlink() { + if !options.FollowSymbolicLinks { + return nil + } + isDir, err := isSymlinkToDirectory(dirent, osPathname) + if err != nil { + if action := options.ErrorCallback(osPathname, err); action == SkipNode { + return nil + } + return err + } + if !isDir { + return nil + } + } else if !dirent.IsDir() { + return nil + } + + // If get here, then specified pathname refers to a directory or a + // symbolic link to a directory. + + var ds scanner + + if options.Unsorted { + // When upstream does not request a sorted iteration, it's more memory + // efficient to read a single child at a time from the file system. + ds, err = NewScanner(osPathname) + } else { + // When upstream wants a sorted iteration, we must read the entire + // directory and sort through the child names, and then iterate on each + // child. + ds, err = newSortedScanner(osPathname) + } + if err != nil { + if action := options.ErrorCallback(osPathname, err); action == SkipNode { + return nil + } + return err + } + + for ds.Scan() { + deChild, err := ds.Dirent() + osChildname := filepath.Join(osPathname, deChild.name) + if err != nil { + if action := options.ErrorCallback(osChildname, err); action == SkipNode { + return nil + } + return err + } + err = walk(osChildname, deChild, options) + debug("osChildname: %q; error: %v\n", osChildname, err) + if err == nil { + continue + } + if err != filepath.SkipDir { + return err + } + // When received SkipDir on a directory or a symbolic link to a + // directory, stop processing that directory but continue processing + // siblings. When received on a non-directory, stop processing + // remaining siblings. + isDir, err := isDirectoryOrSymlinkToDirectory(deChild, osChildname) + if err != nil { + if action := options.ErrorCallback(osChildname, err); action == SkipNode { + continue // ignore and continue with next sibling + } + return err // caller does not approve of this error + } + if !isDir { + break // stop processing remaining siblings, but allow post children callback + } + // continue processing remaining siblings + } + if err = ds.Err(); err != nil { + return err + } + + if options.PostChildrenCallback == nil { + return nil + } + + err = options.PostChildrenCallback(osPathname, dirent) + if err == nil || err == filepath.SkipDir { + return err + } + + if action := options.ErrorCallback(osPathname, err); action == SkipNode { + return nil + } + return err +} diff --git a/v2/jam/pack.go b/v2/jam/pack.go index 71191a5..d38c8e7 100644 --- a/v2/jam/pack.go +++ b/v2/jam/pack.go @@ -15,11 +15,11 @@ import ( // PackOptions ... type PackOptions struct { - IgnoreImports bool - Legacy bool - StoreCmd string - Roots []string - RootsOptions *parser.RootsOptions + IgnoreImports bool + Legacy bool + StoreCmd string + Roots []string + RootsOptions *parser.RootsOptions } // Pack the roots given + PWD diff --git a/v2/jam/parser/box.go b/v2/jam/parser/box.go index 1e64a58..b294191 100644 --- a/v2/jam/parser/box.go +++ b/v2/jam/parser/box.go @@ -8,12 +8,12 @@ import ( // Box found while parsing a file type Box struct { - Name string // name of the box - Path string // relative path of folder NewBox("./templates") - AbsPath string // absolute path of Path - Package string // the package name the box was found in - PWD string // the PWD when the parser was run - PackageDir string // the absolute path of the package where the box was found + Name string // name of the box + Path string // relative path of folder NewBox("./templates") + AbsPath string // absolute path of Path + Package string // the package name the box was found in + PWD string // the PWD when the parser was run + PackageDir string // the absolute path of the package where the box was found } type Boxes []*Box @@ -32,9 +32,9 @@ func NewBox(name string, path string) *Box { name = strings.Replace(name, "\"", "", -1) pwd, _ := os.Getwd() box := &Box{ - Name: name, - Path: path, - PWD: pwd, + Name: name, + Path: path, + PWD: pwd, } return box } diff --git a/v2/jam/parser/file.go b/v2/jam/parser/file.go index 742da48..3bf49cd 100644 --- a/v2/jam/parser/file.go +++ b/v2/jam/parser/file.go @@ -10,8 +10,8 @@ import ( // File that is to be parsed type File struct { io.Reader - Path string - AbsPath string + Path string + AbsPath string } // Name of the file "app.go" @@ -47,8 +47,8 @@ func NewFile(path string, r io.Reader) *File { abs, _ = filepath.Abs(path) } return &File{ - Reader: r, - Path: path, - AbsPath: abs, + Reader: r, + Path: path, + AbsPath: abs, } } diff --git a/v2/jam/parser/finder.go b/v2/jam/parser/finder.go index 76d2621..cdbb413 100644 --- a/v2/jam/parser/finder.go +++ b/v2/jam/parser/finder.go @@ -8,10 +8,10 @@ import ( "strings" "time" + "github.com/gobuffalo/packr/v2/internal/takeon/github.com/karrick/godirwalk" "github.com/gobuffalo/packr/v2/internal/takeon/github.com/markbates/errx" "github.com/gobuffalo/packr/v2/internal/takeon/github.com/markbates/oncer" "github.com/gobuffalo/packr/v2/plog" - "github.com/karrick/godirwalk" ) type finder struct { diff --git a/v2/jam/parser/gogen.go b/v2/jam/parser/gogen.go index e579645..436fb1f 100644 --- a/v2/jam/parser/gogen.go +++ b/v2/jam/parser/gogen.go @@ -13,17 +13,17 @@ import ( // ParsedFile ... type ParsedFile struct { - File packd.SimpleFile - FileSet *token.FileSet - Ast *ast.File - Lines []string + File packd.SimpleFile + FileSet *token.FileSet + Ast *ast.File + Lines []string } // ParseFileMode ... func ParseFileMode(gf packd.SimpleFile, mode parser.Mode) (ParsedFile, error) { pf := ParsedFile{ - FileSet: token.NewFileSet(), - File: gf, + FileSet: token.NewFileSet(), + File: gf, } src := gf.String() diff --git a/v2/jam/parser/parser.go b/v2/jam/parser/parser.go index eb1af75..fd5681d 100644 --- a/v2/jam/parser/parser.go +++ b/v2/jam/parser/parser.go @@ -10,8 +10,8 @@ import ( // Parser to find boxes type Parser struct { - Prospects []*File // a list of files to check for boxes - IgnoreImports bool + Prospects []*File // a list of files to check for boxes + IgnoreImports bool } // Run the parser and run any boxes found diff --git a/v2/jam/parser/parser_test.go b/v2/jam/parser/parser_test.go index 217fcc2..045aa58 100644 --- a/v2/jam/parser/parser_test.go +++ b/v2/jam/parser/parser_test.go @@ -5,9 +5,9 @@ import ( "strings" "testing" + "github.com/gobuffalo/packr/v2/internal/takeon/github.com/markbates/oncer" "github.com/gobuffalo/packr/v2/jam/parser" "github.com/gobuffalo/packr/v2/jam/store" - "github.com/gobuffalo/packr/v2/internal/takeon/github.com/markbates/oncer" "github.com/stretchr/testify/require" ) diff --git a/v2/jam/parser/prospect_test.go b/v2/jam/parser/prospect_test.go index e3f6233..f023f81 100644 --- a/v2/jam/parser/prospect_test.go +++ b/v2/jam/parser/prospect_test.go @@ -8,8 +8,8 @@ import ( func Test_IsProspect(t *testing.T) { table := []struct { - path string - pass bool + path string + pass bool }{ {"foo/.git/config", false}, {"foo/.git/baz.go", false}, diff --git a/v2/jam/parser/roots.go b/v2/jam/parser/roots.go index ad4e09f..8f44d64 100644 --- a/v2/jam/parser/roots.go +++ b/v2/jam/parser/roots.go @@ -8,13 +8,13 @@ import ( "path/filepath" "time" + "github.com/gobuffalo/packr/v2/internal/takeon/github.com/karrick/godirwalk" "github.com/gobuffalo/packr/v2/plog" - "github.com/karrick/godirwalk" ) type RootsOptions struct { - IgnoreImports bool - Ignores []string + IgnoreImports bool + Ignores []string } func (r RootsOptions) String() string { @@ -49,8 +49,8 @@ func NewFromRoots(roots []string, opts *RootsOptions) (*Parser, error) { return nil } wopts := &godirwalk.Options{ - FollowSymbolicLinks: true, - Callback: callback, + FollowSymbolicLinks: true, + Callback: callback, } for _, root := range roots { plog.Debug(p, "NewFromRoots", "walking", root) diff --git a/v2/jam/parser/visitor.go b/v2/jam/parser/visitor.go index bc96244..d41ac49 100644 --- a/v2/jam/parser/visitor.go +++ b/v2/jam/parser/visitor.go @@ -12,17 +12,17 @@ import ( ) type Visitor struct { - File packd.SimpleFile - Package string - boxes map[string]*Box - errors []error + File packd.SimpleFile + Package string + boxes map[string]*Box + errors []error } func NewVisitor(f *File) *Visitor { return &Visitor{ - File: f, - boxes: map[string]*Box{}, - errors: []error{}, + File: f, + boxes: map[string]*Box{}, + errors: []error{}, } } diff --git a/v2/jam/store/disk.go b/v2/jam/store/disk.go index 50ac912..8d27d68 100644 --- a/v2/jam/store/disk.go +++ b/v2/jam/store/disk.go @@ -22,8 +22,8 @@ import ( "github.com/gobuffalo/packr/v2/plog" "github.com/rogpeppe/go-internal/modfile" + "github.com/gobuffalo/packr/v2/internal/takeon/github.com/karrick/godirwalk" "github.com/gobuffalo/packr/v2/jam/parser" - "github.com/karrick/godirwalk" "golang.org/x/sync/errgroup" ) @@ -32,11 +32,11 @@ var _ Store = &Disk{} const DISK_GLOBAL_KEY = "__packr_global__" type Disk struct { - DBPath string - DBPackage string - global map[string]string - boxes map[string]*parser.Box - moot *sync.RWMutex + DBPath string + DBPackage string + global map[string]string + boxes map[string]*parser.Box + moot *sync.RWMutex } func NewDisk(path string, pkg string) *Disk { @@ -50,11 +50,11 @@ func NewDisk(path string, pkg string) *Disk { path, _ = filepath.Abs(path) } return &Disk{ - DBPath: path, - DBPackage: pkg, - global: map[string]string{}, - boxes: map[string]*parser.Box{}, - moot: &sync.RWMutex{}, + DBPath: path, + DBPackage: pkg, + global: map[string]string{}, + boxes: map[string]*parser.Box{}, + moot: &sync.RWMutex{}, } } @@ -68,7 +68,7 @@ func (d *Disk) FileNames(box *parser.Box) ([]string, error) { return names, nil } err := godirwalk.Walk(path, &godirwalk.Options{ - FollowSymbolicLinks: true, + FollowSymbolicLinks: true, Callback: func(path string, de *godirwalk.Dirent) error { if !de.IsRegular() { return nil @@ -126,15 +126,15 @@ func (d *Disk) Clean(box *parser.Box) error { } type options struct { - Package string - GlobalFiles map[string]string - Boxes []optsBox - GK string + Package string + GlobalFiles map[string]string + Boxes []optsBox + GK string } type optsBox struct { - Name string - Path string + Name string + Path string } // Close ... @@ -145,9 +145,9 @@ func (d *Disk) Close() error { xb := &parser.Box{Name: DISK_GLOBAL_KEY} opts := options{ - Package: d.DBPackage, - GlobalFiles: map[string]string{}, - GK: makeKey(xb, d.DBPath), + Package: d.DBPackage, + GlobalFiles: map[string]string{}, + GK: makeKey(xb, d.DBPath), } wg := errgroup.Group{} @@ -204,8 +204,8 @@ func (d *Disk) Close() error { } type file struct { - Resolver string - ForwardPath string + Resolver string + ForwardPath string } tmpl, err := template.New("box.go").Parse(diskGlobalBoxTmpl) @@ -218,13 +218,13 @@ func (d *Disk) Close() error { p := strings.TrimPrefix(s, box.AbsPath) p = strings.TrimPrefix(p, string(filepath.Separator)) files = append(files, file{ - Resolver: strings.Replace(p, "\\", "/", -1), - ForwardPath: makeKey(box, s), + Resolver: strings.Replace(p, "\\", "/", -1), + ForwardPath: makeKey(box, s), }) } opts := map[string]interface{}{ - "Box": box, - "Files": files, + "Box": box, + "Files": files, } bb := &bytes.Buffer{} @@ -312,11 +312,11 @@ func (d *Disk) Close() error { defer f.Close() o := struct { - Package string - Import string + Package string + Import string }{ - Package: b.Package, - Import: ip, + Package: b.Package, + Import: ip, } tmpl, err := template.New(p).Parse(diskImportTmpl) diff --git a/v2/jam/store/disk_packed_test.go b/v2/jam/store/disk_packed_test.go index 67f8a34..08b0c41 100644 --- a/v2/jam/store/disk_packed_test.go +++ b/v2/jam/store/disk_packed_test.go @@ -10,11 +10,11 @@ var _ = func() error { g := packr.New(gk, "") hgr, err := resolver.NewHexGzip(map[string]string{ - "4abf3a9b652ecec6b347eb6acb7ce363": "1f8b08000000000000fff2750c72775508cecc2d28cecfe302040000fffffb1d273b0e000000", - "5cfc8f95f98237a10affc14a76e3e20b": "1f8b08000000000000fff2757477f7745508cecc2d28cecfe302040000ffffb09167470f000000", - "6d8be986fa35821e7e869fbb118e51ba": "1f8b08000000000000fff2f0f7750d5208cecc2d28cecfe302040000fffffb2ef0a60e000000", - "99e5497ae5f5988fafafbcd15ed74d22": "1f8b08000000000000fff2f10c765408cecc2d28cecfe302040000ffffab9bc93e0d000000", - "bb006aa6261a80f6c52c640f713659c1": "1f8b08000000000000ff72720c0a5108cecc2d28cecfe302040000ffff89742ac20d000000", + "4abf3a9b652ecec6b347eb6acb7ce363": "1f8b08000000000000fff2750c72775508cecc2d28cecfe302040000fffffb1d273b0e000000", + "5cfc8f95f98237a10affc14a76e3e20b": "1f8b08000000000000fff2757477f7745508cecc2d28cecfe302040000ffffb09167470f000000", + "6d8be986fa35821e7e869fbb118e51ba": "1f8b08000000000000fff2f0f7750d5208cecc2d28cecfe302040000fffffb2ef0a60e000000", + "99e5497ae5f5988fafafbcd15ed74d22": "1f8b08000000000000fff2f10c765408cecc2d28cecfe302040000ffffab9bc93e0d000000", + "bb006aa6261a80f6c52c640f713659c1": "1f8b08000000000000ff72720c0a5108cecc2d28cecfe302040000ffff89742ac20d000000", }) if err != nil { return err diff --git a/v2/jam/store/fn.go b/v2/jam/store/fn.go index c9f5ea9..e16e466 100644 --- a/v2/jam/store/fn.go +++ b/v2/jam/store/fn.go @@ -9,10 +9,10 @@ import ( var _ Store = &FnStore{} type FnStore struct { - FileNamesFn func(*parser.Box) ([]string, error) - FilesFn func(*parser.Box) ([]*parser.File, error) - PackFn func(*parser.Box) error - CleanFn func(*parser.Box) error + FileNamesFn func(*parser.Box) ([]string, error) + FilesFn func(*parser.Box) ([]*parser.File, error) + PackFn func(*parser.Box) error + CleanFn func(*parser.Box) error } func (f *FnStore) FileNames(box *parser.Box) ([]string, error) { diff --git a/v2/packr2/cmd/build.go b/v2/packr2/cmd/build.go index 747c460..47c2b44 100644 --- a/v2/packr2/cmd/build.go +++ b/v2/packr2/cmd/build.go @@ -8,9 +8,9 @@ import ( ) var buildCmd = &cobra.Command{ - Use: "build", - Short: "Wraps the go build command with packr", - DisableFlagParsing: true, + Use: "build", + Short: "Wraps the go build command with packr", + DisableFlagParsing: true, RunE: func(cmd *cobra.Command, args []string) error { cargs := parseArgs(args) if globalOptions.Verbose { diff --git a/v2/packr2/cmd/clean.go b/v2/packr2/cmd/clean.go index 7d08855..0834b5d 100644 --- a/v2/packr2/cmd/clean.go +++ b/v2/packr2/cmd/clean.go @@ -6,8 +6,8 @@ import ( ) var cleanCmd = &cobra.Command{ - Use: "clean", - Short: "removes any *-packr.go files", + Use: "clean", + Short: "removes any *-packr.go files", RunE: func(cmd *cobra.Command, args []string) error { return jam.Clean(args...) }, diff --git a/v2/packr2/cmd/fix.go b/v2/packr2/cmd/fix.go index f7d3a98..8496900 100644 --- a/v2/packr2/cmd/fix.go +++ b/v2/packr2/cmd/fix.go @@ -10,8 +10,8 @@ import ( // fixCmd represents the info command var fixCmd = &cobra.Command{ - Use: "fix", - Short: fmt.Sprintf("will attempt to fix a application's API to match packr version %s", packr.Version), + Use: "fix", + Short: fmt.Sprintf("will attempt to fix a application's API to match packr version %s", packr.Version), RunE: func(cmd *cobra.Command, args []string) error { return fix.Run() }, diff --git a/v2/packr2/cmd/install.go b/v2/packr2/cmd/install.go index 1924614..ca8efe8 100644 --- a/v2/packr2/cmd/install.go +++ b/v2/packr2/cmd/install.go @@ -23,9 +23,9 @@ $ go build/install ` var installCmd = &cobra.Command{ - Use: "install", - Short: "Don't. ru", - DisableFlagParsing: true, + Use: "install", + Short: "Don't. ru", + DisableFlagParsing: true, RunE: func(cmd *cobra.Command, args []string) error { cargs := parseArgs(args) if globalOptions.Verbose { diff --git a/v2/packr2/cmd/root.go b/v2/packr2/cmd/root.go index 409a9b0..a4cdf6f 100644 --- a/v2/packr2/cmd/root.go +++ b/v2/packr2/cmd/root.go @@ -12,15 +12,15 @@ import ( var globalOptions = struct { jam.PackOptions - Verbose bool - Silent bool + Verbose bool + Silent bool }{ PackOptions: jam.PackOptions{}, } var rootCmd = &cobra.Command{ - Use: "packr2", - Short: "Packr is a simple solution for bundling static assets inside of Go binaries.", + Use: "packr2", + Short: "Packr is a simple solution for bundling static assets inside of Go binaries.", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { for _, a := range args { if a == "--legacy" { diff --git a/v2/packr2/cmd/version.go b/v2/packr2/cmd/version.go index e8b80be..6cb14b7 100644 --- a/v2/packr2/cmd/version.go +++ b/v2/packr2/cmd/version.go @@ -8,8 +8,8 @@ import ( ) var versionCmd = &cobra.Command{ - Use: "version", - Short: "shows packr version", + Use: "version", + Short: "shows packr version", RunE: func(cmd *cobra.Command, args []string) error { fmt.Print(packr.Version) return nil diff --git a/v2/pointer.go b/v2/pointer.go index d342fe6..6e839dc 100644 --- a/v2/pointer.go +++ b/v2/pointer.go @@ -9,8 +9,8 @@ import ( // Pointer is a resolvr which resolves // a file from a different box. type Pointer struct { - ForwardBox string - ForwardPath string + ForwardBox string + ForwardPath string } var _ resolver.Resolver = Pointer{} diff --git a/v2/pointer_test.go b/v2/pointer_test.go index 4a69d54..62e82d6 100644 --- a/v2/pointer_test.go +++ b/v2/pointer_test.go @@ -15,8 +15,8 @@ func Test_Pointer_Find(t *testing.T) { b2 := New("b2", "") b2.SetResolver("bar.txt", &Pointer{ - ForwardBox: "b1", - ForwardPath: "foo.txt", + ForwardBox: "b1", + ForwardPath: "foo.txt", }) s, err := b2.FindString("bar.txt")