pax_global_header00006660000000000000000000000064150256043620014515gustar00rootroot0000000000000052 comment=15a3a0649da2bd81488adb432cdae4c459c0d8a4 zfind-0.4.7/000077500000000000000000000000001502560436200126375ustar00rootroot00000000000000zfind-0.4.7/.github/000077500000000000000000000000001502560436200141775ustar00rootroot00000000000000zfind-0.4.7/.github/FUNDING.yml000066400000000000000000000000171502560436200160120ustar00rootroot00000000000000github: laktak zfind-0.4.7/.github/workflows/000077500000000000000000000000001502560436200162345ustar00rootroot00000000000000zfind-0.4.7/.github/workflows/ci.yml000066400000000000000000000010731502560436200173530ustar00rootroot00000000000000name: ci on: push: branches: [] pull_request: jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: "1.22" - name: chkfmt run: scripts/chkfmt - name: prep-test run: scripts/run_test_prep - name: tests run: | scripts/tests scripts/run_tests - name: xbuild run: scripts/xbuild - name: artifacts uses: actions/upload-artifact@v4 with: name: prerelease-artifacts path: dist/* zfind-0.4.7/.github/workflows/release.yml000066400000000000000000000011121502560436200203720ustar00rootroot00000000000000name: release on: push: tags: ["v*"] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: "1.22" - name: chkfmt run: scripts/chkfmt - name: prep-test run: scripts/run_test_prep - name: tests run: | scripts/tests scripts/run_tests - name: xbuild run: version=${GITHUB_REF#$"refs/tags/v"} scripts/xbuild - name: release uses: softprops/action-gh-release@v2 with: draft: true files: dist/* zfind-0.4.7/.gitignore000066400000000000000000000000151502560436200146230ustar00rootroot00000000000000/zfind /dist zfind-0.4.7/LICENSE000066400000000000000000000020601502560436200136420ustar00rootroot00000000000000MIT License Copyright (c) 2024 Christian Zangl 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. zfind-0.4.7/README.md000066400000000000000000000205521502560436200141220ustar00rootroot00000000000000 # zfind `zfind` allows you to search for files, including inside `tar`, `zip`, `7z` and `rar` archives. It makes finding files easy with a filter syntax that is similar to an SQL-WHERE clause. This means, if you know SQL, you don't have to learn or remember any new syntax just for this tool. - [Basic Usage & Examples](#basic-usage--examples) - [Where Syntax](#where-syntax) - [Properties](#properties) - [Supported archives](#supported-archives) - [Actions](#actions) - [Configuration](#configuration) - [Installation](#installation) - [Install/Update Binaries](#installupdate-binaries) - [Homebrew (macOS and Linux)](#homebrew-macos-and-linux) - [Arch Linux](#arch-linux) - [Build from Source](#build-from-source) - [zfind as a Go module](#zfind-as-a-go-module) ## Basic Usage & Examples ```shell zfind [...] ``` Examples ```console # find files smaller than 10KB, in the current path zfind 'size<10k' # find files in the given range in /some/path zfind 'size between 1M and 1G' /some/path # find files modified before 2010 inside a tar zfind 'date<"2010" and archive="tar"' # find files named foo* and modified today zfind 'name like "foo%" and date=today' # find files that contain two dashes using a regex zfind 'name rlike "(.*-){2}"' # find files that have the extension .jpg or .jpeg zfind 'ext in ("jpg","jpeg")' # find directories named foo and bar zfind 'name in ("foo", "bar") and type="dir"' # search for all README.md files and show in long listing format zfind 'name="README.md"' -l # show results in csv format zfind --csv zfind --csv-no-head ``` ## Where Syntax - `AND`, `OR` and `()` parentheses are logical operators used to combine multiple conditions. `AND` means that both conditions must be true for a row to be included in the results. `OR` means that if either condition is true, the row will be included. Parentheses are used to group conditions, just like in mathematics. Example: `'(size > 20M OR name = "temp") AND type="file"'` selects all files that are either greater than 20 MB in size or are named temp. - Operators `=`, `<>`, `!=`, `<`, `>`, `<=`, `>=` are comparison operators used to compare values and file properties. The types must match, meaning don't compare a date to a file size. Example: `'date > "2020-10-01"'` selects all files that were modified after the specified date. - `LIKE`, `ILIKE` and `RLIKE` are used for pattern matching in strings. - `LIKE` is case-sensitive, while `ILIKE` is case-insensitive. - The `%` symbol is used as a wildcard character that matches any sequence of characters. - The `_` symbol matches any single character. - `RLIKE` allows matching a regular expression. Example: `'"name like "z%"'` selects all files whose name starts with 'z'. - `IN` allows you to specify multiple values to match. A file will be included if the value of the property matches any of the values in the list. Example: `'"type in ("file", "link")'` selects all files of type file or link. - `BETWEEN` selects values within a given range (inclusive). Example: `'"date between "2010" and "2011-01-15"'` means that all files that were modified from 2010 to 2011-01-15 will be included. - `NOT` is a logical operator used to negate a condition. It returns true if the condition is false and vice versa. Example: `'"name not like "z%"'`, `'"date not between "2010" and "2011-01-15"'`, `'"type not in ("file", "link")'` - Values can be numbers, text, date and time, `TRUE` and `FALSE` - dates have to be specified in `YYYY-MM-DD` format - times have to be specified in 24h `HH:MM:SS` format - numbers can be written as sizes by appending `B`, `K`, `M`, `G` and `T` to specify bytes, KB, MB, GB, and TB. - empty strings and `0` evaluate to `false` ## Properties The following file properties are available: | name | description | |-------------|-------------------------------------------------------------------| | name | name of the file | | path | full path of the file | | container | path of the container (if inside an archive) | | size | file size (uncompressed) | | date | modified date in YYYY-MM-DD format | | time | modified time in HH-MM-SS format | | ext | short file extension (e.g., `txt`) | | ext2 | long file extension (two parts, e.g., `tar.gz`) | | type | `file`, `dir`, or `link` | | archive | archive type: `tar`, `zip`, `7z`, `rar` or empty | Helper properties | name | description | |-------------|-------------------------------------------------------------------| | today | today's date | | mo | last monday's date | | tu | last tuesday's date | | we | last wednesday's date | | th | last thursday's date | | fr | last friday's date | | sa | last saturday's date | | su | last sunday's date | ## Supported archives | name | extensions | |-------------|-------------------------------------------------------------------| | tar | `.tar`, `.tar.gz`, `.tgz`, `.tar.bz2`, `.tbz2`, `.tar.xz`, `.txz` | | zip | `.zip` | | 7zip | `.7z` | | rar | `.rar` | > Note: use the flag -n (or --no-archive) to disable archive support. You can also use `'not archive'` in your query but this still requires zfind to open the archive. ## Actions zfind does not implement actions like `find`, instead use `xargs -0` to execute commands: ```shell zfind --no-archive 'name like "%.txt"' -0 | xargs -0 -L1 echo ``` zfind can also produce `--csv` (or `--csv-no-head`) that can be piped to other commands. ## Configuration Set the environment variable `NO_COLOR` to disable color output. ## Installation ### Install/Update Binaries ``` curl https://laktak.github.io/zfind.sh|bash ``` This will download the zfind binary for your OS/Platform from the GitHub releases page and install it to `~/.local/bin`. You will get a message if that's not in your `PATH`. You probably want to download or view the [setup script](https://laktak.github.io/zfind.sh) before piping it to bash. If you prefer you can download a binary from [github.com/laktak/zfind/releases](https://github.com/laktak/zfind/releases) manually and place it in your `PATH`. Prereleased versions can be found directly on the [GitHub Action](https://github.com/laktak/zfind/actions). Click on the latest `ci` action and look for `prerelease-artifacts` at the bottom. ### Homebrew (macOS and Linux) For macOS and Linux it can also be installed via [Homebrew](https://formulae.brew.sh/formula/zfind): ```shell brew install zfind ``` ### Arch Linux zfind is available in the AUR as [zfind](https://aur.archlinux.org/packages/zfind/): ```shell paru -S zfind ``` ### Build from Source Building from the source requires Go. - Either install it directly ```shell go install github.com/laktak/zfind/cmd/zfind@latest ``` - or clone and build ```shell git clone https://github.com/laktak/zfind zfind/scripts/build # output is here: zfind/zfind ``` ## zfind as a Go module zfind is can also be used in other Go programs. ``` go get github.com/laktak/zfind ``` The library consists of two main packages: - [filter](https://pkg.go.dev/github.com/laktak/zfind/filter): provides functionality for parsing and evaluating SQL-where filter expressions - [find](https://pkg.go.dev/github.com/laktak/zfind/find): implements searching for files and directories. For more information see the linked documentation on pkg.go.dev. zfind-0.4.7/cmd/000077500000000000000000000000001502560436200134025ustar00rootroot00000000000000zfind-0.4.7/cmd/zfind/000077500000000000000000000000001502560436200145145ustar00rootroot00000000000000zfind-0.4.7/cmd/zfind/help.go000066400000000000000000000036641502560436200160040ustar00rootroot00000000000000package main var headerHelp = `Search for files, including inside tar, zip, 7z and rar archives. zfind makes finding files easy with a filter syntax that is similar to an SQL-WHERE clause. For examples run "zfind -H" or go to https://github.com/laktak/zfind ` var filterHelp = ` zfind uses a filter syntax that is very similar to an SQL-WHERE clause. Examples: # find files smaller than 10KB, in the current path zfind 'size<10k' # find files in the given range in /some/path zfind 'size between 1M and 1G' /some/path # find files modified before 2010 inside a tar zfind 'date<"2010" and archive="tar"' # find files named foo* and modified today zfind 'name like "foo%" and date=today' # find files that contain two dashes using a regex zfind 'name rlike "(.*-){2}"' # find files that have the extension .jpg or .jpeg zfind 'ext in ("jpg","jpeg")' # find directories named foo and bar zfind 'name in ("foo", "bar") and type="dir"' # search for all README.md files and show in long listing format zfind 'name="README.md"' -l # show results in csv format zfind --csv zfind --csv-no-head The following file properties are available: name name of the file path full path of the file size file size (uncompressed) date modified date in YYYY-MM-DD format time modified time in HH-MM-SS format ext short file extension (e.g. 'txt') ext2 long file extension (two parts, e.g. 'tar.gz') type file|dir|link archive archive type tar|zip|7z|rar if inside a container container path of container (if any) Helper properties today todays date mo last monday's date tu last tuesday's date we last wednesday's date th last thursday's date fr last friday's date sa last saturday's date su last sunday's date For more details go to https://github.com/laktak/zfind ` zfind-0.4.7/cmd/zfind/main.go000066400000000000000000000070731502560436200157760ustar00rootroot00000000000000package main import ( "encoding/csv" "fmt" "os" "github.com/alecthomas/kong" "github.com/fatih/color" "github.com/laktak/zfind/filter" "github.com/laktak/zfind/find" ) var appVersion = "vdev" func printFiles(ch chan find.FileInfo, long bool, archSep string, lineSep []byte) { for file := range ch { name := "" if file.Container != "" { name = file.Container + archSep } name += file.Path if long { size := filter.FormatSize(file.Size) fmt.Fprintf(os.Stdout, "%s %10s %s", file.ModTime.Format("2006-01-02 15:04:05"), size, name) } else { fmt.Fprint(os.Stdout, name) } os.Stdout.Write(lineSep) } } func printCsv(header bool, ch chan find.FileInfo) error { writer := csv.NewWriter(os.Stdout) if header { if err := writer.Write(find.Fields[:]); err != nil { return err } } for file := range ch { var record []string getter := file.Context() for _, field := range find.Fields { value := getter(field) record = append(record, (*value).String()) } if err := writer.Write(record); err != nil { return err } } writer.Flush() if err := writer.Error(); err != nil { return err } return nil } func main() { var cli struct { FilterHelp bool `short:"H" help:"Show where-filter help."` Long bool `short:"l" help:"Show long listing format."` Csv bool `help:"Show listing as CSV."` CsvNoHead bool `help:"Show listing as CSV without header."` ArchiveSeparator string `help:"Separator between the archive name and the file inside" default:"//"` FollowSymlinks bool `short:"L" help:"Follow symbolic links."` NoArchive bool `short:"n" help:"Disables archive support."` Print0 bool `name:"print0" short:"0" help:"Use a null character instead of the newline character, to be used with the -0 option of xargs."` Version bool `short:"V" help:"Show version."` Where string `arg:"" name:"where" optional:"" help:"The filter using SQL-where syntax (see -H). Use '-' to skip when providing a path."` Paths []string `arg:"" name:"path" optional:"" help:"Paths to search."` } arg := kong.Parse(&cli, kong.Name("zfind"), kong.Description(headerHelp), kong.UsageOnError()) if cli.FilterHelp { fmt.Println(filterHelp) os.Exit(0) } if cli.Version { fmt.Println(appVersion) os.Exit(0) } if cli.Where == "" || cli.Where == "-" { cli.Where = "1" } lineSep := []byte("\n") if cli.Print0 { lineSep = []byte{0} } if len(cli.Paths) == 0 { cli.Paths = []string{"."} } filter, err := filter.CreateFilter(cli.Where) arg.FatalIfErrorf(err) done := make(chan bool) ch := make(chan find.FileInfo) errChan := make(chan string) // start search go func() { for _, searchPath := range cli.Paths { find.Walk(searchPath, find.WalkParams{ Chan: ch, Err: errChan, Filter: filter, FollowSymlinks: cli.FollowSymlinks, NoArchive: cli.NoArchive}) } close(ch) close(errChan) }() // print results go func() { if cli.Csv { arg.FatalIfErrorf(printCsv(true, ch)) } else if cli.CsvNoHead { arg.FatalIfErrorf(printCsv(false, ch)) } else { printFiles(ch, cli.Long, cli.ArchiveSeparator, lineSep) } done <- true }() // print errors hasErr := false var errCol = color.New(color.FgRed).SprintFunc() for errmsg := range errChan { fmt.Fprintln(color.Error, errCol("error: "+errmsg)) hasErr = true } // wait for output to finish <-done if hasErr { fmt.Fprintln(color.Error, errCol("errors were encountered!")) os.Exit(1) } } zfind-0.4.7/filter/000077500000000000000000000000001502560436200141245ustar00rootroot00000000000000zfind-0.4.7/filter/filter.go000066400000000000000000000152411502560436200157430ustar00rootroot00000000000000package filter import ( "errors" "fmt" "regexp" "strings" ) type context struct { get VariableGetter } // VariableGetter is a function type that is used to retrieve the value of a variable // by its name. It takes a single string argument (the name of the variable) and // returns a pointer to a Value instance that represents the value of the variable. type VariableGetter func(name string) *Value var ErrInvalidOperatorOrOperands = errors.New("invalid operator or operands") func (x *term) eval(ctx context) (*value, error) { switch { case x.Value != nil: return x.Value, nil case x.SymbolRef != nil: return ctx.get(x.SymbolRef.Symbol).tovalue(x.SymbolRef.Symbol) default: return x.SubExpression.eval(ctx) } } func (x *compare) eval(t *term, ctx context) (*value, error) { v1, err := t.eval(ctx) if err != nil { return nil, err } v2, err := x.Operand.eval(ctx) if err != nil { return nil, err } op := x.Operator r := false switch { case v1.Num() != nil && v2.Num() != nil: n1, n2 := *v1.Num(), *v2.Num() switch op { case "!=", "<>": r = n1 != n2 case "<=": r = n1 <= n2 case ">=": r = n1 >= n2 case "=": r = n1 == n2 case "<": r = n1 < n2 case ">": r = n1 > n2 default: return nil, ErrInvalidOperatorOrOperands } return boolValue(r), nil case v1.Text != nil && v2.Text != nil: t1, t2 := *v1.Text, *v2.Text switch op { case "!=", "<>": r = t1 != t2 case "<=": r = t1 <= t2 case ">=": r = t1 >= t2 case "=": r = t1 == t2 case "<": r = t1 < t2 case ">": r = t1 > t2 default: return nil, ErrInvalidOperatorOrOperands } return boolValue(r), nil case v1.Boolean != nil && v2.Boolean != nil: b1, b2 := *v1.Boolean, *v2.Boolean switch op { case "!=", "<>": r = b1 != b2 case "=": r = b1 == b2 default: return nil, ErrInvalidOperatorOrOperands } return boolValue(r), nil } return nil, ErrInvalidOperatorOrOperands } func (x *between) eval(t *term, ctx context) (*value, error) { v1, err := t.eval(ctx) if err != nil { return nil, err } v2, err := x.Start.eval(ctx) if err != nil { return nil, err } v3, err := x.End.eval(ctx) if err != nil { return nil, err } switch { case v1.Num() != nil && v2.Num() != nil && v3.Num() != nil: n1, n2, n3 := *v1.Num(), *v2.Num(), *v3.Num() return boolValue(n1 >= n2 && n1 <= n3), nil case v1.Text != nil && v2.Text != nil && v3.Text != nil: t1, t2, t3 := *v1.Text, *v2.Text, *v3.Text return boolValue(t1 >= t2 && t1 <= t3), nil } return nil, ErrInvalidOperatorOrOperands } func (x *in) eval(t *term, ctx context) (*value, error) { v1, err := t.eval(ctx) if err != nil { return nil, err } for _, o := range x.Expressions { if v2, err := o.eval(ctx); err != nil { return nil, err } else { switch { case v1.Num() != nil && v2.Num() != nil: n1, n2 := *v1.Num(), *v2.Num() if n1 == n2 { return boolValue(true), nil } case v1.Text != nil && v2.Text != nil: t1, t2 := *v1.Text, *v2.Text if t1 == t2 { return boolValue(true), nil } case v1.Boolean != nil && v2.Boolean != nil: b1, b2 := v1.Bool(), v2.Bool() if b1 == b2 { return boolValue(true), nil } default: fmt.Println(v1, v2) return nil, ErrInvalidOperatorOrOperands } } } return boolValue(false), nil } func not(value *value, err error) (*value, error) { return boolValue(!value.Bool()), err } func likeToRegex(text string, caseInsensitive bool) *regexp.Regexp { ex := regexp.QuoteMeta(text) ex = strings.ReplaceAll(ex, "%", ".*") ex = strings.ReplaceAll(ex, "_", ".") ex = "^" + ex + "$" if caseInsensitive { ex = "(?i)^" + ex } return regexp.MustCompile(ex) } func (x *conditionRHS) eval(t *term, ctx context) (*value, error) { r := false switch { case x.Compare != nil: return x.Compare.eval(t, ctx) case x.Between != nil: if x.Not { return not(x.Between.eval(t, ctx)) } else { return x.Between.eval(t, ctx) } case x.In != nil: if x.Not { return not(x.In.eval(t, ctx)) } else { return x.In.eval(t, ctx) } } // *like // assume regex is static if x.likeCache == nil { switch { case x.Like != nil: v2, err := x.Like.eval(ctx) if err != nil { return nil, err } x.likeCache = likeToRegex(v2.String(), false) case x.Ilike != nil: v2, err := x.Ilike.eval(ctx) if err != nil { return nil, err } x.likeCache = likeToRegex(v2.String(), true) case x.Rlike != nil: v2, err := x.Rlike.eval(ctx) if err != nil { return nil, err } x.likeCache = regexp.MustCompile(v2.String()) } } v1, err := t.eval(ctx) if err != nil { return nil, err } r = x.likeCache.MatchString(v1.String()) if x.Not { r = !r } return boolValue(r), nil } func (x *conditionOperand) eval(ctx context) (*value, error) { if x.ConditionRHS != nil { return x.ConditionRHS.eval(x.Operand, ctx) } else { return x.Operand.eval(ctx) } } func (x *condition) eval(ctx context) (*value, error) { switch { case x.Operand != nil: return x.Operand.eval(ctx) default: if v, err := x.Not.eval(ctx); err != nil { return nil, err } else { return boolValue(!v.Bool()), nil } } } func (x *andCondition) eval(ctx context) (*value, error) { r := true for _, o := range x.And { if v, err := o.eval(ctx); err != nil { return nil, err } else { r = r && v.Bool() } } return boolValue(r), nil } func (x *expression) eval(ctx context) (*value, error) { r := false for _, o := range x.Or { if v, err := o.eval(ctx); err != nil { return nil, err } else { r = r || v.Bool() } } return boolValue(r), nil } // FilterExpression is a parsed and compiled representation of a filter string. // It can be used to efficiently test whether a set of variables matches the filter. type FilterExpression struct { expression *expression } // Test tests whether the set of variables provided by the getter function matches // the filter expression. It returns a boolean value indicating whether the variables // match the filter, as well as an error value if there was a problem evaluating the // expression, like a type mismatch or a missing variable. func (x *FilterExpression) Test(getter VariableGetter) (bool, error) { ctx := context{get: getter} if r, err := x.expression.eval(ctx); err != nil { return false, err } else { return r.Bool(), nil } } // CreateFilter parses the given filter string and returns a compiled FilterExpression // that can be used to efficiently test the filter. If the filter string is not valid, // an error is returned. func CreateFilter(filter string) (*FilterExpression, error) { if expr, err := parser.ParseString("", filter); err != nil { return nil, err } else { return &FilterExpression{expression: expr}, nil } } zfind-0.4.7/filter/filter_test.go000066400000000000000000000042041502560436200167770ustar00rootroot00000000000000package filter import ( "fmt" "testing" ) type example struct { expected bool errmsg string w string } var examples = []example{ {true, "", "name like \"foo%\""}, {true, "", "name like \"fo__ar\""}, {true, "", "name like \"%oo%\""}, {true, "", "name like \"%bar\""}, {false, "", "name like \"oo%\""}, {false, "", "name like \"Foo%\""}, {true, "", "name ilike \"Foo%\""}, {false, "", "name ilike \"oo%\""}, {true, "", "name rlike \"^foo.*$\""}, {true, "", "name rlike \"foo\""}, {false, "", "name not like \"foo%\""}, {true, "", "name not like \"test%\""}, {true, "", "x=3"}, {true, "", "x=3 and y=40000"}, {false, "", "x like \"x\""}, {false, "", "x=5"}, {true, "", "x in (3, 5)"}, {false, "", "x not in (3, 5)"}, {false, "", "x in (4, 6, 5)"}, {true, "", "x not in (4, 6, 5)"}, {true, "", "x between 3 and 5"}, {false, "", "x not between 3 and 5"}, {false, "", "x between 4 and 5"}, {true, "", "x=3 and y<70K"}, {true, "", "x=5 and y=40000 or name=\"foobar\""}, {false, "", "x=5 and (y=40000 or name=\"foobar\")"}, {false, "\"noname\" is unknown", "noname like \"hug%\""}, {true, "\"i\" is unknown", "x=5 and (i=7 or foo='foo')"}, {false, "invalid operator or operands", "x=\"x\""}, } func check(t *testing.T, w string, expect bool, errmsg string) string { test := func(name string) *Value { switch name { case "x": return NumberValue(3) case "y": return NumberValue(40000) case "name": return TextValue("foobar") default: return nil } } chkerr := func(err error) string { serr := fmt.Sprintf("%v", err) if serr != errmsg { return fmt.Sprintf("Err %s vs %s", serr, errmsg) } else { return "" } } if filter, err := CreateFilter(w); err == nil { if r, err := filter.Test(test); err == nil { if errmsg != "" { return "missing error: " + errmsg } if r != expect { return fmt.Sprintf("result=%t expected=%t", r, expect) } return "" } else { return chkerr(err) } } else { return chkerr(err) } } func TestFilters(t *testing.T) { for _, ex := range examples { r := check(t, ex.w, ex.expected, ex.errmsg) if r != "" { t.Error(ex.w + ": " + r) } } } zfind-0.4.7/filter/lang.go000066400000000000000000000051251502560436200153770ustar00rootroot00000000000000package filter import ( "fmt" "regexp" "github.com/alecthomas/participle/v2" "github.com/alecthomas/participle/v2/lexer" ) type boolean bool type expression struct { Or []*andCondition `@@ ( "OR" @@ )*` } type andCondition struct { And []*condition `@@ ( "AND" @@ )*` } type condition struct { Operand *conditionOperand ` @@` Not *condition `| "NOT" @@` } type conditionOperand struct { Operand *term `@@` ConditionRHS *conditionRHS `@@?` } type conditionRHS struct { Compare *compare ` @@` Not bool `| [ @"NOT" ] (` Between *between ` "BETWEEN" @@` In *in ` | "IN" "(" @@ ")"` Ilike *term ` | "ILIKE" @@` Rlike *term ` | "RLIKE" @@` Like *term ` | "LIKE" @@ )` likeCache *regexp.Regexp } type compare struct { Operator string `@( "<>" | "<=" | ">=" | "=" | "<" | ">" | "!=" )` Operand *term `@@` } type between struct { Start *term `@@` End *term `"AND" @@` } type in struct { Expressions []*term `@@ ( "," @@ )*` } type term struct { Value *value ` @@` SymbolRef *symbolRef `| @@` SubExpression *expression `| "(" @@ ")"` } type symbolRef struct { Symbol string `@Ident` } type size int64 func (s *size) Capture(v []string) error { n, err := ParseSize(v[0]); *s = size(n); return err } type value struct { Size *size ` ( @Size` Number *int64 ` | @Number` Text *string ` | @Text` Boolean *boolean ` | @("TRUE" | "FALSE") )` } func boolValue(v bool) *value { b := boolean(v) return &value{ Boolean: &b, } } func (v value) Num() *int64 { if v.Size != nil { return (*int64)(v.Size) } return v.Number } func (v value) String() string { switch { case v.Num() != nil: return fmt.Sprintf("%d", *v.Num()) case v.Text != nil: return *v.Text case v.Boolean != nil: return fmt.Sprintf("%t", *v.Boolean) default: return "(empty)" } } func (x *value) Bool() bool { switch { case x.Num() != nil: return *x.Num() != 0 case x.Text != nil: return *x.Text != "" case x.Boolean != nil: return bool(*x.Boolean) default: return false } } var ( exprLexer = lexer.MustSimple([]lexer.SimpleRule{ {`Keyword`, `(?i)\b(TRUE|FALSE|NOT|BETWEEN|AND|OR|LIKE|ILIKE|RLIKE|IN)\b`}, {`Ident`, `[a-zA-Z_][a-zA-Z0-9_]*`}, {`Size`, `\d*\.?\d+[BKMGTbkmgt]`}, {`Number`, `[-+]?\d*\.?\d+([eE][-+]?\d+)?`}, {`Text`, `'[^']*'|"[^"]*"`}, {`Operators`, `<>|!=|<=|>=|[,.()=<>]`}, {"whitespace", `\s+`}, }) parser = participle.MustBuild[expression]( participle.Lexer(exprLexer), participle.Unquote("Text"), participle.CaseInsensitive("Keyword"), ) ) zfind-0.4.7/filter/size.go000066400000000000000000000025031502560436200154250ustar00rootroot00000000000000package filter import ( "fmt" "math" "strconv" "strings" ) // ParseSize takes a string representation of a size (e.g. "1G", "10M") and returns // the size in bytes as an int64. If the input string is not a valid size // representation, an error is returned. func ParseSize(sizeStr string) (int64, error) { units := map[string]int64{"B": 1, "K": 1 << 10, "M": 1 << 20, "G": 1 << 30, "T": 1 << 40} sizeStr = strings.ToUpper(sizeStr) unit := sizeStr[len(sizeStr)-1:] size, err := strconv.ParseFloat(sizeStr[:len(sizeStr)-1], 64) if err != nil { return 0, err } return int64(size * float64(units[unit])), nil } // FormatSize takes an int64 representation of a size in bytes and returns a string // representation of the size with a unit (e.g. "1G", "10M"). The size is rounded to // the nearest whole number if it is an integer, otherwise it is rounded to one // decimal place. func FormatSize(size int64) string { units := []string{"", "K", "M", "G", "T", "P"} unitIndex := int(math.Log(float64(size)) / math.Log(1024)) value := float64(size) / math.Pow(1024, float64(unitIndex)) if unitIndex >= 0 && unitIndex < len(units) { if value == math.Floor(value) { return fmt.Sprintf("%d%s", int64(value), units[unitIndex]) } return fmt.Sprintf("%.1f%s", value, units[unitIndex]) } else { return fmt.Sprintf("%d", size) } } zfind-0.4.7/filter/value.go000066400000000000000000000024041502560436200155670ustar00rootroot00000000000000package filter import ( "errors" "fmt" ) // Value is a type that can represent a number, a string, or a boolean value. type Value struct { Number *int64 Text *string Boolean *bool } // String returns a string representation of the value. If the value is nil, an empty // string is returned. func (v *Value) String() string { if v == nil { return "" } switch { case v.Number != nil: return fmt.Sprintf("%d", *v.Number) case v.Text != nil: return *v.Text case v.Boolean != nil: return fmt.Sprintf("%t", *v.Boolean) default: return "" } } func (v *Value) tovalue(name string) (*value, error) { if v != nil { return &value{ Number: v.Number, Text: v.Text, Boolean: (*boolean)(v.Boolean), }, nil } else { return &value{}, errors.New(fmt.Sprintf("\"%s\" is unknown", name)) } } // NumberValue creates a new Value instance that represents the given number. func NumberValue(f int64) *Value { return &Value{ Number: &f, } } // TextValue creates a new Value instance that represents the given string. func TextValue(s string) *Value { return &Value{ Text: &s, } } // BoolValue creates a new Value instance that represents the given boolean value. func BoolValue(v bool) *Value { b := bool(v) return &Value{ Boolean: &b, } } zfind-0.4.7/find/000077500000000000000000000000001502560436200135575ustar00rootroot00000000000000zfind-0.4.7/find/find.go000066400000000000000000000216571502560436200150410ustar00rootroot00000000000000package find import ( "archive/tar" "archive/zip" "compress/bzip2" "compress/gzip" "fmt" "io" "os" "path/filepath" "sort" "strings" "time" "github.com/bodgit/sevenzip" "github.com/laktak/zfind/filter" "github.com/nwaples/rardecode" "github.com/ulikunitz/xz" ) // FileInfo is a type that represents information about a file or directory. type FileInfo struct { Name string Path string ModTime time.Time Size int64 Type string Container string Archive string } // IsDir returns a boolean value indicating if the FileInfo instance is a // directory. func (fi FileInfo) IsDir() bool { return fi.Type == "dir" } func (fi FileInfo) fromSymlink(fi2 FileInfo) FileInfo { return FileInfo{ Name: fi.Name, Path: fi.Path, ModTime: fi2.ModTime, Size: fi2.Size, Type: fi2.Type, } } // FindError is a type that represents an error that occurred during a file search. type FindError struct { Path string Err error } func (e *FindError) Error() string { return e.Path + ": " + e.Err.Error() } const ( fieldName = "name" fieldPath = "path" fieldContainer = "container" fieldSize = "size" fieldDate = "date" fieldTime = "time" fieldExt = "ext" fieldExt2 = "ext2" fieldType = "type" fieldArchive = "archive" ) // Fields is a slice of the constants that address fields in the FileInfo type. var Fields = [...]string{ fieldName, fieldPath, fieldContainer, fieldSize, fieldDate, fieldTime, fieldExt, fieldExt2, fieldType, fieldArchive, } // Context is a method of the FileInfo type that returns a VariableGetter function // that can be used to retrieve the values of the fields of the file or directory // represented by the FileInfo instance. // // It also generates helper properties like "today". func (file FileInfo) Context() filter.VariableGetter { return func(name string) *filter.Value { switch strings.ToLower(name) { case fieldName: return filter.TextValue(file.Name) case fieldPath: return filter.TextValue(file.Path) case fieldDate: return filter.TextValue(file.ModTime.Format(time.DateOnly)) case fieldTime: return filter.TextValue(file.ModTime.Format(time.TimeOnly)) case fieldSize: return filter.NumberValue(file.Size) case fieldExt: return filter.TextValue(strings.TrimPrefix(filepath.Ext(file.Name), ".")) case fieldExt2: return filter.TextValue(strings.TrimPrefix(ext2(file.Name), ".")) case fieldType: return filter.TextValue(file.Type) case fieldContainer: return filter.TextValue(file.Container) case fieldArchive: return filter.TextValue(file.Archive) case "today": return filter.TextValue(time.Now().Format(time.DateOnly)) case "mo": return getLastWeekday(time.Monday) case "tu": return getLastWeekday(time.Tuesday) case "we": return getLastWeekday(time.Wednesday) case "th": return getLastWeekday(time.Thursday) case "fr": return getLastWeekday(time.Friday) case "sa": return getLastWeekday(time.Saturday) case "su": return getLastWeekday(time.Sunday) default: return nil } } } func getLastWeekday(weekday time.Weekday) *filter.Value { now := time.Now() offs := int(weekday - now.Weekday()) if offs >= 0 { offs -= 7 } day := now.AddDate(0, 0, offs) return filter.TextValue(day.Format(time.DateOnly)) } func listFilesInTar(fullpath string) ([]FileInfo, error) { f, err := os.Open(fullpath) if err != nil { return nil, &FindError{Path: fullpath, Err: err} } defer f.Close() var fr io.Reader = f switch { case strings.HasSuffix(fullpath, ".gz") || strings.HasSuffix(fullpath, ".tgz"): if fr, err = gzip.NewReader(f); err != nil { return nil, &FindError{Path: fullpath, Err: err} } case strings.HasSuffix(fullpath, ".bz2") || strings.HasSuffix(fullpath, ".tbz2"): fr = bzip2.NewReader(f) case strings.HasSuffix(fullpath, ".xz") || strings.HasSuffix(fullpath, ".txz"): if fr, err = xz.NewReader(f); err != nil { return nil, &FindError{Path: fullpath, Err: err} } } r := tar.NewReader(fr) var files []FileInfo for { h, err := r.Next() if err == io.EOF { break } if err != nil { return nil, &FindError{Path: fullpath, Err: err} } switch h.Typeflag { case tar.TypeReg, tar.TypeDir, tar.TypeSymlink: t := "file" if h.Typeflag == tar.TypeDir { t = "dir" } else if h.Typeflag == tar.TypeSymlink { t = "link" } files = append(files, FileInfo{ Name: filepath.Base(h.Name), Path: h.Name, ModTime: h.ModTime, Size: h.Size, Type: t, Container: fullpath, Archive: "tar"}) } } return files, nil } func getZipNameAndType(path string) (string, string) { if strings.HasSuffix(path, "/") { return path[:len(path)-1], "dir" } else { return path, "file" } } func listFilesInZip(fullpath string) ([]FileInfo, error) { f, err := os.Open(fullpath) if err != nil { return nil, &FindError{Path: fullpath, Err: err} } defer f.Close() fi, err := f.Stat() if err != nil { return nil, &FindError{Path: fullpath, Err: err} } zr, err := zip.NewReader(f, fi.Size()) if err != nil { return nil, &FindError{Path: fullpath, Err: err} } var files []FileInfo for _, zf := range zr.File { rc, err := zf.Open() if err != nil { return nil, &FindError{Path: fullpath, Err: err} } defer rc.Close() name, t := getZipNameAndType(zf.Name) files = append(files, FileInfo{ Name: filepath.Base(name), Path: name, ModTime: zf.Modified, Size: int64(zf.UncompressedSize), Type: t, Container: fullpath, Archive: "zip"}) } return files, nil } func listFilesIn7Zip(fullpath string) ([]FileInfo, error) { r, err := sevenzip.OpenReader(fullpath) if err != nil { return nil, &FindError{Path: fullpath, Err: err} } defer r.Close() var files []FileInfo for _, h := range r.File { name, t := getZipNameAndType(h.Name) files = append(files, FileInfo{ Name: filepath.Base(name), Path: name, ModTime: h.Modified, Size: h.FileInfo().Size(), Type: t, Container: fullpath, Archive: "7z"}) } return files, nil } func listFilesInRar(fullpath string) ([]FileInfo, error) { r, err := rardecode.OpenReader(fullpath, "") if err != nil { return nil, &FindError{Path: fullpath, Err: err} } defer r.Close() var files []FileInfo for { h, err := r.Next() if err == io.EOF { break } t := "file" if h.IsDir { t = "dir" } files = append(files, FileInfo{ Name: filepath.Base(h.Name), Path: h.Name, ModTime: h.ModificationTime, Size: h.UnPackedSize, Type: t, Container: fullpath, Archive: "rar"}) } return files, nil } func findIn(param WalkParams, fi FileInfo) { fullpath := fi.Path if ok, err := param.Filter.Test(fi.Context()); err != nil { param.sendErr(&FindError{Path: fullpath, Err: err}) return } else if ok { param.Chan <- fi } var files []FileInfo var err error = nil if fi.IsDir() || param.NoArchive { return } if strings.HasSuffix(fullpath, ".tar") || strings.HasSuffix(fullpath, ".tar.gz") || strings.HasSuffix(fullpath, ".tgz") || strings.HasSuffix(fullpath, ".tar.bz2") || strings.HasSuffix(fullpath, ".tbz2") || strings.HasSuffix(fullpath, ".tar.xz") || strings.HasSuffix(fullpath, ".txz") { files, err = listFilesInTar(fullpath) } else if strings.HasSuffix(fullpath, ".zip") { files, err = listFilesInZip(fullpath) } else if strings.HasSuffix(fullpath, ".7z") { files, err = listFilesIn7Zip(fullpath) } else if strings.HasSuffix(fullpath, ".rar") { files, err = listFilesInRar(fullpath) } sort.Slice(files, func(i, j int) bool { return files[i].Path < files[j].Path }) if err != nil { param.sendErr(err) } else { for _, fi2 := range files { if ok, err := param.Filter.Test(fi2.Context()); err != nil { param.sendErr(&FindError{Path: fullpath, Err: err}) return } else if ok { param.Chan <- fi2 } } } } // WalkParams is used to specify the parameters for a file search. type WalkParams struct { // Chan is the channel that is used to send the results of the search. Chan chan FileInfo // Err is the channel that is used to send error messages. Err chan string // Filter is the filter expression that is used to filter the results of the search. Filter *filter.FilterExpression // FollowSymlinks specifies whether symbolic links should be followed during the search. FollowSymlinks bool // NoArchive specifies whether archives should be skipped during the search. NoArchive bool } // Sends an error message to the error channel of the WalkParams instance. func (wp WalkParams) sendErr(err error) { serr := fmt.Sprintf("%v", err) wp.Err <- serr } // Walk is a function that performs a file search starting at the given root // directory. See WalkParams to control the behavior of the search. func Walk(root string, param WalkParams) { fsWalk(root, param.FollowSymlinks, func(fi *FileInfo, err error) { if err == nil { findIn(param, *fi) } else { param.sendErr(err) } }) } zfind-0.4.7/find/walk.go000066400000000000000000000041301502560436200150420ustar00rootroot00000000000000package find import ( "os" "path/filepath" "sort" ) type WalkFunc func(file *FileInfo, err error) type WalkError struct { Path string Err error } func (e *WalkError) Error() string { return e.Path + ": " + e.Err.Error() } func fsWalk(root string, followSymlinks bool, report WalkFunc) { walk(root, root, followSymlinks, report) } func makeFileInfo(fullpath string, file os.FileInfo) FileInfo { ft := file.Mode().Type() t := "file" if ft&os.ModeDir != 0 { t = "dir" } else if ft&os.ModeSymlink != 0 { t = "link" } return FileInfo{ Name: file.Name(), Path: fullpath, ModTime: file.ModTime(), Size: file.Size(), Type: t, } } func readDirNames(dirname string) ([]string, error) { f, err := os.Open(dirname) if err != nil { return nil, err } names, err := f.Readdirnames(-1) f.Close() if err != nil { return nil, err } sort.Strings(names) return names, nil } func walk(path string, virtPath string, followSymlinks bool, report WalkFunc) { osFileInfo, err := os.Lstat(path) if err != nil { report(nil, &WalkError{Path: path, Err: err}) } else { fi := makeFileInfo(virtPath, osFileInfo) if fi.IsDir() { report(&fi, nil) } else if fi.Type == "link" && followSymlinks { rpath, err := filepath.EvalSymlinks(path) if err == nil { osFileInfo, err = os.Lstat(rpath) } if err != nil { report(nil, &WalkError{Path: path, Err: err}) return } fi2 := makeFileInfo(virtPath, osFileInfo) fi = fi.fromSymlink(fi2) path = rpath report(&fi, nil) if !fi2.IsDir() { return } } else { // file report(&fi, nil) return } names, err := readDirNames(path) if err != nil { report(nil, &WalkError{Path: path, Err: err}) } else { for _, name := range names { rfilename := filepath.Join(path, name) filename := filepath.Join(virtPath, name) walk(rfilename, filename, followSymlinks, report) } } } } func ext2(path string) string { for i, n := len(path)-1, 0; i >= 0 && !os.IsPathSeparator(path[i]); i-- { if path[i] == '.' { n += 1 if n == 2 { return path[i:] } } } return "" } zfind-0.4.7/go.mod000066400000000000000000000015551502560436200137530ustar00rootroot00000000000000module github.com/laktak/zfind go 1.23.0 toolchain go1.24.4 require ( github.com/alecthomas/kong v1.11.0 github.com/alecthomas/participle/v2 v2.1.4 github.com/bodgit/sevenzip v1.6.1 github.com/fatih/color v1.18.0 github.com/nwaples/rardecode v1.1.3 github.com/ulikunitz/xz v0.5.12 ) require ( github.com/andybalholm/brotli v1.1.1 // indirect github.com/bodgit/plumbing v1.3.0 // indirect github.com/bodgit/windows v1.0.1 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/spf13/afero v1.14.0 // indirect go4.org v0.0.0-20230225012048-214862532bf5 // indirect golang.org/x/sys v0.33.0 // indirect golang.org/x/text v0.26.0 // indirect ) zfind-0.4.7/go.sum000066400000000000000000000706321502560436200140020ustar00rootroot00000000000000cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/kong v1.11.0 h1:y++1gI7jf8O7G7l4LZo5ASFhrhJvzc+WgF/arranEmM= github.com/alecthomas/kong v1.11.0/go.mod h1:p2vqieVMeTAnaC83txKtXe8FLke2X07aruPWXyMPQrU= github.com/alecthomas/participle/v2 v2.1.4 h1:W/H79S8Sat/krZ3el6sQMvMaahJ+XcM9WSI2naI7w2U= github.com/alecthomas/participle/v2 v2.1.4/go.mod h1:8tqVbpTX20Ru4NfYQgZf4mP18eXPTBViyMWiArNEgGI= github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= github.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU= github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs= github.com/bodgit/sevenzip v1.6.1 h1:kikg2pUMYC9ljU7W9SaqHXhym5HyKm8/M/jd31fYan4= github.com/bodgit/sevenzip v1.6.1/go.mod h1:GVoYQbEVbOGT8n2pfqCIMRUaRjQ8F9oSqoBEqZh5fQ8= github.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4= github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= 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/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc= github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= 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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go4.org v0.0.0-20230225012048-214862532bf5 h1:nifaUDeh+rPaBCMPMQHZmvJf+QdpLFnuQPwx+LxVmtc= go4.org v0.0.0-20230225012048-214862532bf5/go.mod h1:F57wTi5Lrj6WLyswp5EYV1ncrEbFGHD4hhz6S1ZYeaU= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= zfind-0.4.7/scripts/000077500000000000000000000000001502560436200143265ustar00rootroot00000000000000zfind-0.4.7/scripts/build000077500000000000000000000003171502560436200153540ustar00rootroot00000000000000#!/bin/bash set -eE -o pipefail script_dir=$(dirname "$(realpath "$0")") cd $script_dir/.. version=$(git describe --tags --always) CGO_ENABLED=0 go build -ldflags="-X main.appVersion=$version" ./cmd/zfind zfind-0.4.7/scripts/chkfmt000077500000000000000000000003071502560436200155300ustar00rootroot00000000000000#!/bin/bash set -eE -o pipefail script_dir=$(dirname "$(realpath "$0")") cd $script_dir/.. res="$(gofmt -l . 2>&1)" if [ -n "$res" ]; then echo "gofmt check failed:" echo "${res}" exit 1 fi zfind-0.4.7/scripts/lint000077500000000000000000000002151502560436200152200ustar00rootroot00000000000000#!/bin/bash set -eE -o pipefail script_dir=$(dirname "$(realpath "$0")") cd $script_dir/.. go vet -structtag=false -composites=false ./... zfind-0.4.7/scripts/run_test_prep000077500000000000000000000011551502560436200171470ustar00rootroot00000000000000#!/bin/bash export TZ='UTC' root="/tmp/zfind" go run scripts/run_test_prep.go cd $root/root/time zip -r ../day/time.zip * 7z a ../year/time.7z * rm -rf $root/root/time cd $root/root/thing tar -cvf ../way/thing.tar * tar -czvf ../year/thing.tar.gz * tar -czvf ../year/thing.tgz * tar --bzip2 -cvf ../people/thing.tar.bz2 * tar --bzip2 -cvf ../people/thing.tbz2 * tar --xz -cvf ../people/thing.tar.xz * tar --xz -cvf ../people/thing.txz * rm -rf $root/root/thing cd $root/root mv $root/root/people $root/people ln -s ../people people ln -s ../../people/face/office-door.pdf day/friend/party-result.png find -L | wc -l zfind-0.4.7/scripts/run_test_prep.go000066400000000000000000000051371502560436200175540ustar00rootroot00000000000000package main import ( "fmt" "io/ioutil" "os" "path/filepath" "time" ) var ( startList = []string{"time", "year", "people", "way", "day", "thing"} wordList = []string{"life", "world", "school", "state", "family", "student", "group", "country", "problem", "hand", "part", "place", "case", "week", "company", "system", "program", "work", "government", "number", "night", "point", "home", "water", "room", "mother", "area", "money", "story", "fact", "month", "lot", "right", "study", "book", "eye", "job", "word", "business", "issue", "side", "kind", "head", "house", "service", "friend", "father", "power", "hour", "game", "line", "end", "member", "law", "car", "city", "community", "name", "president", "team", "minute", "idea", "kid", "body", "information", "back", "face", "others", "level", "office", "door", "health", "person", "art", "war", "history", "party", "result", "change", "morning", "reason", "research", "moment", "air", "teacher", "force", "education"} extList = []string{"txt", "md", "pdf", "jpg", "jpeg", "png", "mp4", "mp3", "csv"} startDate = time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC) endDate = time.Date(2024, 12, 1, 0, 0, 0, 0, time.UTC) dateList = []time.Time{} wordIdx = 0 extIdx = 0 dateIdx = 0 ) func nextWord() string { word := wordList[wordIdx%len(wordList)] wordIdx++ return word } func nextExt() string { ext := extList[extIdx%len(extList)] extIdx++ return ext } func setDate(filename string, r int) { date := dateList[dateIdx%len(dateList)] m := 17 * dateIdx / len(dateList) date = date.Add(time.Duration(m) * time.Hour) dateIdx++ os.Chtimes(filename, date, date) } func genFile(dir string, a int) { os.MkdirAll(dir, 0755) for i := 1; i <= 5; i++ { size := a*i*wordIdx*100 + extIdx file := nextWord() + "-" + nextWord() if i%3 == 0 { file += "-" + nextWord() } file += "." + nextExt() path := filepath.Join(dir, file) ioutil.WriteFile(path, make([]byte, size), 0644) setDate(path, size*size) } } func genDir(root string) { for _, start := range startList { for i := 1; i <= 5; i++ { dir := filepath.Join(root, start, nextWord()) genFile(dir, 1) if wordIdx%3 == 0 { dir = filepath.Join(dir, nextWord()) genFile(dir, 1) } } } } func main() { root := "/tmp/zfind" var c int64 = 50 interval := (int64)(endDate.Sub(startDate).Seconds()) / c for i := range make([]int64, c) { dateList = append(dateList, startDate.Add(time.Duration(interval*(int64)(i))*time.Second)) } if err := os.RemoveAll(root); err == nil { genDir(filepath.Join(root, "root")) fmt.Println("Ready.") } else { fmt.Println("Failed to clean") } } zfind-0.4.7/scripts/run_tests000077500000000000000000000035471502560436200163130ustar00rootroot00000000000000#!/bin/bash set -e export TZ='UTC' script_dir=$(dirname "$(realpath "$0")") base_dir=$(dirname "$script_dir") dir=$(realpath "$script_dir/../testdata/run_test") root="/tmp/zfind/root" if [[ ! -d $root ]]; then echo "must run run_test_prep first" exit 1 fi # setup status1=$( cd $base_dir git status --porcelain ) $script_dir/build rm -rf $dir mkdir -p $dir function zft { local name=$1 shift local path=$1 shift echo "- $name" cd $root/$path "$base_dir/zfind" "$@" > "$dir/$name.txt" } # run actual tests zft plain01 day/car zft csv01 day/car 'type!="dir"' --csv zft csv02 way/job 'type="file"' --csv-no-head zft link01 / 'name like "party-%" and type="file"' zft link02 / 'name like "party-%" and type="file"' -L zft link03 / 'container like "%.tar.xz" and archive="tar" and name ilike "Art-%"' -L zft arc01 day --archive-separator=": " 'path like "life/%" and archive="zip"' zft name01 / 'name="service-friend.md"' -l zft name02 / 'name like "air%"' -l zft name03 / 'name ilike "%History%" and type="dir"' . zft ext01 / 'ext in ("jpg","jpeg") and size>100k' zft ext02 / 'ext in ("jpg","jpeg") and size>250k and (not container or container like "%.tar.gz")' -l zft date01 / 'date < "2002"' -l zft date02 / 'date between "2004" and "2005-12-31"' -l zft size01 / 'size < 1K and type="file"' -l zft reg01 / 'name rlike ".*\\.tar\\.gz"' zft reg02 way 'name rlike "(.+-){2}" and size>200k' zft reg03 / 'name rlike "^[abc].*-[a-d]"' # check result status2=$( cd $base_dir git status --porcelain ) if [ -n "$status2" ]; then if [ -n "$status1" ]; then echo "run_tests was started with a dirty git directory, please verify the results manually." exit 1 fi echo "run_tests detected changes in the test output" echo "$status2" cd $base_dir git diff exit 1 else echo "run_tests: OK" fi zfind-0.4.7/scripts/tests000077500000000000000000000001441502560436200154150ustar00rootroot00000000000000#!/bin/bash set -e script_dir=$(dirname "$(realpath "$0")") cd $script_dir/.. go test -v ./filter zfind-0.4.7/scripts/xbuild000077500000000000000000000017021502560436200155430ustar00rootroot00000000000000#!/bin/bash set -eE -o pipefail script_dir=$(dirname "$(realpath "$0")") cd $script_dir/.. if [ -z "$version" ]; then version=$(git rev-parse HEAD) fi echo "building version $version" mkdir -p dist rm -f dist/* build() { echo "- $1-$2" rm -f dist/zfind CGO_ENABLED=0 GOOS="$1" GOARCH="$2" go build -o dist -ldflags="-X main.appVersion=$version" ./cmd/zfind pushd dist case "$1" in windows) outfile="zfind-$1-$2.zip" zip "$outfile" zfind.exe --move ;; *) outfile="zfind-$1-$2.tar.gz" tar -czf "$outfile" zfind --remove-files ;; esac popd } build android arm64 build darwin amd64 build darwin arm64 build freebsd amd64 build freebsd arm64 build freebsd riscv64 build linux amd64 build linux arm64 build linux riscv64 build netbsd amd64 build netbsd arm64 build openbsd amd64 build openbsd arm64 build windows amd64 build windows arm64 zfind-0.4.7/testdata/000077500000000000000000000000001502560436200144505ustar00rootroot00000000000000zfind-0.4.7/testdata/run_test/000077500000000000000000000000001502560436200163135ustar00rootroot00000000000000zfind-0.4.7/testdata/run_test/arc01.txt000066400000000000000000000005751502560436200177710ustar00rootroot00000000000000time.zip: life/case time.zip: life/case/home-water.txt time.zip: life/case/night-point.csv time.zip: life/case/system-program.mp4 time.zip: life/case/week-company.png time.zip: life/case/work-government-number.mp3 time.zip: life/part-place.jpeg time.zip: life/problem-hand.jpg time.zip: life/state-family.md time.zip: life/student-group-country.pdf time.zip: life/world-school.txt zfind-0.4.7/testdata/run_test/csv01.txt000066400000000000000000000015001502560436200200040ustar00rootroot00000000000000name,path,container,size,date,time,ext,ext2,type,archive city-community.mp4,city-community.mp4,,57940,2019-12-11,04:12:00,mp4,,file, health-person-art.jpeg,face/health-person-art.jpeg,,178147,2023-06-07,09:33:36,jpeg,,file, office-door.jpg,face/office-door.jpg,,118446,2022-12-07,09:04:48,jpg,,file, others-level.pdf,face/others-level.pdf,,59145,2022-06-08,08:36:00,pdf,,file, party-result.mp4,face/party-result.mp4,,299249,2024-06-05,11:31:12,mp4,,file, war-history.png,face/war-history.png,,238648,2023-12-06,11:02:24,png,,file, information-back.md,information-back.md,,293244,2021-12-08,07:07:12,md,,file, kid-body.txt,kid-body.txt,,233843,2021-06-09,06:38:24,txt,,file, name-president.mp3,name-president.mp3,,116041,2020-06-10,04:40:48,mp3,,file, team-minute-idea.csv,team-minute-idea.csv,,174542,2020-12-09,06:09:36,csv,,file, zfind-0.4.7/testdata/run_test/csv02.txt000066400000000000000000000013651502560436200200160ustar00rootroot00000000000000father-power.pdf,father-power.pdf,,197164,2006-12-25,13:43:12,pdf,,file, community-name.mp4,hour/community-name.mp4,,161768,2008-12-22,17:38:24,mp4,,file, end-member.jpeg,hour/end-member.jpeg,,79966,2007-12-24,15:40:48,jpeg,,file, game-line.jpg,hour/game-line.jpg,,39865,2007-06-25,15:12:00,jpg,,file, law-car-city.png,hour/law-car-city.png,,120467,2008-06-23,16:09:36,png,,file, president-team.mp3,hour/president-team.mp3,,203169,2009-06-22,18:07:12,mp3,,file, issue-side.csv,issue-side.csv,,77561,2005-06-27,11:16:48,csv,,file, kind-head-house.txt,kind-head-house.txt,,116862,2005-12-26,12:45:36,txt,,file, service-friend.md,service-friend.md,,156963,2006-06-26,13:14:24,md,,file, word-business.mp3,word-business.mp3,,38660,2004-12-27,10:48:00,mp3,,file, zfind-0.4.7/testdata/run_test/date01.txt000066400000000000000000000046271502560436200201430ustar00rootroot000000000000002001-12-31 22:55:12 239.5K day/friend/city-community.mp4 2000-01-03 20:00:00 47.2K day/friend/father-power.pdf 2000-07-03 20:28:48 94.5K day/friend/hour-game.jpg 2001-07-02 22:26:24 190.8K day/friend/law-car.png 2001-01-01 20:57:36 142.3K day/friend/line-end-member.jpeg 2001-12-29 02:55:12 4.9K day/time.zip//life/part-place.jpeg 2001-06-30 02:26:24 3.1K day/time.zip//life/problem-hand.jpg 2000-07-01 00:28:48 601 day/time.zip//life/state-family.md 2000-12-30 00:57:36 1.5K day/time.zip//life/student-group-country.pdf 2000-01-01 00:00:00 100 day/time.zip//life/world-school.txt 2001-12-31 05:55:12 180.8K way/case/home-water.md 2001-07-02 05:26:24 143.9K way/case/night-point.txt 2000-07-03 03:28:48 71.0K way/case/system-program.mp3 2000-01-03 03:00:00 35.4K way/case/week-company.mp4 2001-01-01 03:57:36 107.1K way/case/work-government-number.csv 2001-01-02 13:57:36 177.5K way/thing.tar//change/air-teacher-force.txt 2001-07-03 15:26:24 237.7K way/thing.tar//change/education-life.md 2000-01-04 13:00:00 58.9K way/thing.tar//change/morning-reason.mp3 2000-07-04 13:28:48 118.0K way/thing.tar//change/research-moment.csv 2000-01-01 17:00:00 11.9K year/study/book-eye.png 2000-12-30 17:57:36 36.7K year/study/business-issue-side.mp3 2001-12-29 19:55:12 63.5K year/study/house-service.txt 2000-07-01 17:28:48 24.1K year/study/job-word.mp4 2001-06-30 19:26:24 50.1K year/study/kind-head.csv 2001-01-02 13:57:36 177.5K year/thing.tar.gz//change/air-teacher-force.txt 2001-07-03 15:26:24 237.7K year/thing.tar.gz//change/education-life.md 2000-01-04 13:00:00 58.9K year/thing.tar.gz//change/morning-reason.mp3 2000-07-04 13:28:48 118.0K year/thing.tar.gz//change/research-moment.csv 2001-01-02 13:57:36 177.5K year/thing.tgz//change/air-teacher-force.txt 2001-07-03 15:26:24 237.7K year/thing.tgz//change/education-life.md 2000-01-04 13:00:00 58.9K year/thing.tgz//change/morning-reason.mp3 2000-07-04 13:28:48 118.0K year/thing.tgz//change/research-moment.csv 2001-12-29 02:55:12 4.9K year/time.7z//life/part-place.jpeg 2001-06-30 02:26:24 3.1K year/time.7z//life/problem-hand.jpg 2000-07-01 00:28:48 601 year/time.7z//life/state-family.md 2000-12-30 00:57:36 1.5K year/time.7z//life/student-group-country.pdf 2000-01-01 00:00:00 100 year/time.7z//life/world-school.txt zfind-0.4.7/testdata/run_test/date02.txt000066400000000000000000000041651502560436200201410ustar00rootroot000000000000002004-06-29 03:19:12 245.3K day/friend/name/others-level.pdf 2004-12-28 03:48:00 49.5K day/office/door-health.jpg 2005-06-28 04:16:48 99.2K day/office/person-art.jpeg 2005-12-27 05:45:36 149.3K day/office/war-history-party.png 2004-06-26 07:19:12 10.8K day/time.zip//life/case/home-water.txt 2005-12-24 09:45:36 8.5K day/time.zip//room/fact-month-lot.jpg 2005-06-25 08:16:48 5.3K day/time.zip//room/money-story.pdf 2004-12-25 07:48:00 2.5K day/time.zip//room/mother-area.md 2004-06-28 10:19:12 186.7K way/case/room/book-eye.mp4 2005-06-27 11:16:48 75.7K way/job/issue-side.csv 2005-12-26 12:45:36 114.1K way/job/kind-head-house.txt 2004-12-27 10:48:00 37.8K way/job/word-business.mp3 2004-06-29 20:19:12 304.0K way/thing.tar//change/state/week-company.mp3 2005-06-28 21:16:48 122.7K way/thing.tar//system/government-number.txt 2005-12-27 22:45:36 184.5K way/thing.tar//system/night-point-home.md 2004-12-28 20:48:00 61.3K way/thing.tar//system/program-work.csv 2005-12-25 02:45:36 43.7K year/name/kid-body-information.csv 2005-06-26 01:16:48 28.8K year/name/minute-idea.mp3 2004-12-26 00:48:00 14.2K year/name/president-team.mp4 2004-06-27 00:19:12 69.4K year/study/friend/city-community.png 2004-06-29 20:19:12 304.0K year/thing.tar.gz//change/state/week-company.mp3 2005-06-28 21:16:48 122.7K year/thing.tar.gz//system/government-number.txt 2005-12-27 22:45:36 184.5K year/thing.tar.gz//system/night-point-home.md 2004-12-28 20:48:00 61.3K year/thing.tar.gz//system/program-work.csv 2004-06-29 20:19:12 304.0K year/thing.tgz//change/state/week-company.mp3 2005-06-28 21:16:48 122.7K year/thing.tgz//system/government-number.txt 2005-12-27 22:45:36 184.5K year/thing.tgz//system/night-point-home.md 2004-12-28 20:48:00 61.3K year/thing.tgz//system/program-work.csv 2004-06-26 07:19:12 10.8K year/time.7z//life/case/home-water.txt 2005-12-24 09:45:36 8.5K year/time.7z//room/fact-month-lot.jpg 2005-06-25 08:16:48 5.3K year/time.7z//room/money-story.pdf 2004-12-25 07:48:00 2.5K year/time.7z//room/mother-area.md zfind-0.4.7/testdata/run_test/ext01.txt000066400000000000000000000027161502560436200200230ustar00rootroot00000000000000day/car/face/health-person-art.jpeg day/car/face/office-door.jpg day/friend/line-end-member.jpeg day/group/government/area-money.jpg day/group/government/story-fact.jpeg day/month/head/line-end.jpeg day/month/head/power-hour-game.jpg day/office/research/family-student.jpg way/case/room/fact-month-lot.jpeg way/minute/door-health.jpg way/point/area-money-story.jpg way/point/fact-month.jpeg way/teacher/country-problem.jpeg way/teacher/student-group.jpg way/thing.tar//body/health-person.jpeg way/thing.tar//body/level-office-door.jpg way/thing.tar//change/state/group-country.jpeg way/thing.tar//issue/game-line.jpeg way/thing.tar//issue/power-hour.jpg way/thing.tar//life/state-family.jpg way/thing.tar//life/student-group-country.jpeg way/thing.tar//system/mother-area.jpg year/head/member-law.jpeg year/thing.tar.gz//body/health-person.jpeg year/thing.tar.gz//body/level-office-door.jpg year/thing.tar.gz//change/state/group-country.jpeg year/thing.tar.gz//issue/game-line.jpeg year/thing.tar.gz//issue/power-hour.jpg year/thing.tar.gz//life/state-family.jpg year/thing.tar.gz//life/student-group-country.jpeg year/thing.tar.gz//system/mother-area.jpg year/thing.tgz//body/health-person.jpeg year/thing.tgz//body/level-office-door.jpg year/thing.tgz//change/state/group-country.jpeg year/thing.tgz//issue/game-line.jpeg year/thing.tgz//issue/power-hour.jpg year/thing.tgz//life/state-family.jpg year/thing.tgz//life/student-group-country.jpeg year/thing.tgz//system/mother-area.jpg zfind-0.4.7/testdata/run_test/ext02.txt000066400000000000000000000006531502560436200200220ustar00rootroot000000000000002014-06-17 18:55:12 268.8K day/group/government/story-fact.jpeg 2009-06-23 11:07:12 257.0K day/office/research/family-student.jpg 2016-06-15 15:50:24 265.9K year/thing.tar.gz//body/health-person.jpeg 2011-12-21 08:31:12 321.6K year/thing.tar.gz//issue/game-line.jpeg 2011-06-22 07:02:24 256.5K year/thing.tar.gz//issue/power-hour.jpg 2006-12-26 23:43:12 309.8K year/thing.tar.gz//system/mother-area.jpg zfind-0.4.7/testdata/run_test/link01.txt000066400000000000000000000002521502560436200201510ustar00rootroot00000000000000day/car/face/party-result.mp4 way/thing.tar//body/history/party-result.mp4 year/thing.tar.gz//body/history/party-result.mp4 year/thing.tgz//body/history/party-result.mp4 zfind-0.4.7/testdata/run_test/link02.txt000066400000000000000000000007131502560436200201540ustar00rootroot00000000000000day/car/face/party-result.mp4 day/friend/party-result.png people/face/party-result.png people/history/party-result.png people/thing.tar.bz2//body/history/party-result.mp4 people/thing.tar.xz//body/history/party-result.mp4 people/thing.tbz2//body/history/party-result.mp4 people/thing.txz//body/history/party-result.mp4 way/thing.tar//body/history/party-result.mp4 year/thing.tar.gz//body/history/party-result.mp4 year/thing.tgz//body/history/party-result.mp4 zfind-0.4.7/testdata/run_test/link03.txt000066400000000000000000000000461502560436200201540ustar00rootroot00000000000000people/thing.tar.xz//body/art-war.png zfind-0.4.7/testdata/run_test/name01.txt000066400000000000000000000000711502560436200201330ustar00rootroot000000000000002006-06-26 13:14:24 153.3K way/job/service-friend.md zfind-0.4.7/testdata/run_test/name02.txt000066400000000000000000000007141502560436200201400ustar00rootroot000000000000002018-12-12 19:14:24 270.6K way/thing.tar//body/history/air-teacher.txt 2001-01-02 13:57:36 177.5K way/thing.tar//change/air-teacher-force.txt 2018-12-12 19:14:24 270.6K year/thing.tar.gz//body/history/air-teacher.txt 2001-01-02 13:57:36 177.5K year/thing.tar.gz//change/air-teacher-force.txt 2018-12-12 19:14:24 270.6K year/thing.tgz//body/history/air-teacher.txt 2001-01-02 13:57:36 177.5K year/thing.tgz//change/air-teacher-force.txt zfind-0.4.7/testdata/run_test/name03.txt000066400000000000000000000001341502560436200201350ustar00rootroot00000000000000way/thing.tar//body/history/ year/thing.tar.gz//body/history/ year/thing.tgz//body/history/ zfind-0.4.7/testdata/run_test/plain01.txt000066400000000000000000000003251502560436200203200ustar00rootroot00000000000000. city-community.mp4 face face/health-person-art.jpeg face/office-door.jpg face/others-level.pdf face/party-result.mp4 face/war-history.png information-back.md kid-body.txt name-president.mp3 team-minute-idea.csv zfind-0.4.7/testdata/run_test/reg01.txt000066400000000000000000000000221502560436200177640ustar00rootroot00000000000000year/thing.tar.gz zfind-0.4.7/testdata/run_test/reg02.txt000066400000000000000000000002161502560436200177720ustar00rootroot00000000000000thing.tar//body/history/reason-research-moment.csv thing.tar//life/case/work-government-number.txt thing.tar//life/student-group-country.jpeg zfind-0.4.7/testdata/run_test/reg03.txt000066400000000000000000000003661502560436200200010ustar00rootroot00000000000000day/car/city-community.mp4 day/friend/city-community.mp4 way/thing.tar//issue/end/car-city.mp4 year/head/car/city-community.png year/study/friend/city-community.png year/thing.tar.gz//issue/end/car-city.mp4 year/thing.tgz//issue/end/car-city.mp4 zfind-0.4.7/testdata/run_test/size01.txt000066400000000000000000000004121502560436200201640ustar00rootroot000000000000002000-07-01 00:28:48 601 day/time.zip//life/state-family.md 2000-01-01 00:00:00 100 day/time.zip//life/world-school.txt 2000-07-01 00:28:48 601 year/time.7z//life/state-family.md 2000-01-01 00:00:00 100 year/time.7z//life/world-school.txt