mirror of
https://github.com/restic/restic.git
synced 2026-02-03 04:20:45 -05:00
cmd/restic/cmd_rewrite.go: introduction of include filters for this command: - add include filters, add error checking code - add new parameter 'keepEmptyDirectoryFunc' to 'walker.NewSnapshotSizeRewriter()', so empty directories have to be kept to keep the directory structure intact - add parameter 'keepEmptySnapshot' to 'filterAndReplaceSnapshot()' to keep snapshots intact when nothing is to be included - introduce helper function 'gatherIncludeFilters()' and 'gatherExcludeFilters()' to keep code flow clean cmd/restic/cmd_rewrite_integration_test.go: add several new tests around the 'include' functionality internal/filter/include.go: this is where is include filter is defined internal/walker/rewriter.go: - struct RewriteOpts gains field 'KeepEmtpyDirectory', which is a 'NodeKeepEmptyDirectoryFunc()' which defaults to nil, so that al subdirectories are kept - function 'NewSnapshotSizeRewriter()' gains the parameter 'keepEmptyDirecoryFilter' which controls the management of empty subdirectories in case of include filters active internal/data/tree.go: gains a function Count() for checking the number if node elements in a newly built tree internal/walker/rewriter_test.go: function 'NewSnapshotSizeRewriter()' gets an additional parameter nil to keeps things happy cmd/restic/cmd_repair_snapshots.go: function 'filterAndReplaceSnapshot()' gets an additional parameter 'keepEmptySnapshot=nil' doc/045_working_with_repos.rst: gets to mention include filters changelog/unreleased/issue-4278: the usual announcement file git rebase master -i produced this restic rewrite include - keep linter happy cmd/restic/cmd_rewrite_integration_test.go: linter likes strings.Contain() better than my strings.Index() >= 0
103 lines
3.5 KiB
Go
103 lines
3.5 KiB
Go
package filter
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/restic/restic/internal/errors"
|
|
"github.com/spf13/pflag"
|
|
)
|
|
|
|
// IncludeByNameFunc is a function that takes a filename that should be included
|
|
// in the restore process and returns whether it should be included.
|
|
type IncludeByNameFunc func(item string) (matched bool, childMayMatch bool)
|
|
|
|
type IncludePatternOptions struct {
|
|
Includes []string
|
|
InsensitiveIncludes []string
|
|
IncludeFiles []string
|
|
InsensitiveIncludeFiles []string
|
|
}
|
|
|
|
func (opts *IncludePatternOptions) Add(f *pflag.FlagSet) {
|
|
f.StringArrayVarP(&opts.Includes, "include", "i", nil, "include a `pattern` (can be specified multiple times)")
|
|
f.StringArrayVar(&opts.InsensitiveIncludes, "iinclude", nil, "same as --include `pattern` but ignores the casing of filenames")
|
|
f.StringArrayVar(&opts.IncludeFiles, "include-file", nil, "read include patterns from a `file` (can be specified multiple times)")
|
|
f.StringArrayVar(&opts.InsensitiveIncludeFiles, "iinclude-file", nil, "same as --include-file but ignores casing of `file`names in patterns")
|
|
}
|
|
|
|
func (opts *IncludePatternOptions) Empty() bool {
|
|
return len(opts.Includes) == 0 && len(opts.InsensitiveIncludes) == 0 && len(opts.IncludeFiles) == 0 && len(opts.InsensitiveIncludeFiles) == 0
|
|
}
|
|
|
|
func (opts IncludePatternOptions) CollectPatterns(warnf func(msg string, args ...interface{})) ([]IncludeByNameFunc, error) {
|
|
var fs []IncludeByNameFunc
|
|
if len(opts.IncludeFiles) > 0 {
|
|
includePatterns, err := readPatternsFromFiles(opts.IncludeFiles)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := ValidatePatterns(includePatterns); err != nil {
|
|
return nil, errors.Fatalf("--include-file: %s", err)
|
|
}
|
|
|
|
opts.Includes = append(opts.Includes, includePatterns...)
|
|
}
|
|
|
|
if len(opts.InsensitiveIncludeFiles) > 0 {
|
|
includePatterns, err := readPatternsFromFiles(opts.InsensitiveIncludeFiles)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := ValidatePatterns(includePatterns); err != nil {
|
|
return nil, errors.Fatalf("--iinclude-file: %s", err)
|
|
}
|
|
|
|
opts.InsensitiveIncludes = append(opts.InsensitiveIncludes, includePatterns...)
|
|
}
|
|
|
|
if len(opts.InsensitiveIncludes) > 0 {
|
|
if err := ValidatePatterns(opts.InsensitiveIncludes); err != nil {
|
|
return nil, errors.Fatalf("--iinclude: %s", err)
|
|
}
|
|
|
|
fs = append(fs, IncludeByInsensitivePattern(opts.InsensitiveIncludes, warnf))
|
|
}
|
|
|
|
if len(opts.Includes) > 0 {
|
|
if err := ValidatePatterns(opts.Includes); err != nil {
|
|
return nil, errors.Fatalf("--include: %s", err)
|
|
}
|
|
|
|
fs = append(fs, IncludeByPattern(opts.Includes, warnf))
|
|
}
|
|
return fs, nil
|
|
}
|
|
|
|
// IncludeByPattern returns a IncludeByNameFunc which includes files that match
|
|
// one of the patterns.
|
|
func IncludeByPattern(patterns []string, warnf func(msg string, args ...interface{})) IncludeByNameFunc {
|
|
parsedPatterns := ParsePatterns(patterns)
|
|
return func(item string) (matched bool, childMayMatch bool) {
|
|
matched, childMayMatch, err := ListWithChild(parsedPatterns, item)
|
|
if err != nil {
|
|
warnf("error for include pattern: %v", err)
|
|
}
|
|
|
|
return matched, childMayMatch
|
|
}
|
|
}
|
|
|
|
// IncludeByInsensitivePattern returns a IncludeByNameFunc which includes files that match
|
|
// one of the patterns, ignoring the casing of the filenames.
|
|
func IncludeByInsensitivePattern(patterns []string, warnf func(msg string, args ...interface{})) IncludeByNameFunc {
|
|
for index, path := range patterns {
|
|
patterns[index] = strings.ToLower(path)
|
|
}
|
|
|
|
includeFunc := IncludeByPattern(patterns, warnf)
|
|
return func(item string) (matched bool, childMayMatch bool) {
|
|
return includeFunc(strings.ToLower(item))
|
|
}
|
|
}
|