2
2
mirror of https://github.com/octoleo/restic.git synced 2025-01-24 15:48:25 +00:00

restore: read includes, insensitive includes, excludes and insensitive excludes from a file

feature for gh-4781
This commit is contained in:
Srigovind Nayak 2024-05-19 23:30:14 +05:30
parent 78485160fc
commit b02117ef0b
No known key found for this signature in database
GPG Key ID: 3C4A72A34ABD4C43
2 changed files with 65 additions and 15 deletions

View File

@ -45,11 +45,15 @@ Exit status is 0 if the command was successful, and non-zero if there was any er
// RestoreOptions collects all options for the restore command. // RestoreOptions collects all options for the restore command.
type RestoreOptions struct { type RestoreOptions struct {
Exclude []string Exclude []string
InsensitiveExclude []string ExcludeFiles []string
Include []string InsensitiveExclude []string
InsensitiveInclude []string InsensitiveExcludeFiles []string
Target string Include []string
IncludeFiles []string
InsensitiveInclude []string
InsensitiveIncludeFiles []string
Target string
restic.SnapshotFilter restic.SnapshotFilter
Sparse bool Sparse bool
Verify bool Verify bool
@ -66,6 +70,10 @@ func init() {
flags.StringArrayVarP(&restoreOptions.Include, "include", "i", nil, "include a `pattern`, exclude everything else (can be specified multiple times)") flags.StringArrayVarP(&restoreOptions.Include, "include", "i", nil, "include a `pattern`, exclude everything else (can be specified multiple times)")
flags.StringArrayVar(&restoreOptions.InsensitiveInclude, "iinclude", nil, "same as --include but ignores the casing of `pattern`") flags.StringArrayVar(&restoreOptions.InsensitiveInclude, "iinclude", nil, "same as --include but ignores the casing of `pattern`")
flags.StringVarP(&restoreOptions.Target, "target", "t", "", "directory to extract data to") flags.StringVarP(&restoreOptions.Target, "target", "t", "", "directory to extract data to")
flags.StringArrayVar(&restoreOptions.ExcludeFiles, "exclude-file", nil, "read exclude patterns from a `file` (can be specified multiple times)")
flags.StringArrayVar(&restoreOptions.InsensitiveExcludeFiles, "iexclude-file", nil, "same as --exclude-file but ignores casing of `file`names in patterns")
flags.StringArrayVar(&restoreOptions.IncludeFiles, "include-file", nil, "read include patterns from a `file` (can be specified multiple times)")
flags.StringArrayVar(&restoreOptions.InsensitiveIncludeFiles, "iinclude-file", nil, "same as --include-file but ignores casing of `file`names in patterns")
initSingleSnapshotFilter(flags, &restoreOptions.SnapshotFilter) initSingleSnapshotFilter(flags, &restoreOptions.SnapshotFilter)
flags.BoolVar(&restoreOptions.Sparse, "sparse", false, "restore files as sparse") flags.BoolVar(&restoreOptions.Sparse, "sparse", false, "restore files as sparse")
@ -176,6 +184,27 @@ func runRestore(ctx context.Context, opts RestoreOptions, gopts GlobalOptions,
excludePatterns := filter.ParsePatterns(opts.Exclude) excludePatterns := filter.ParsePatterns(opts.Exclude)
insensitiveExcludePatterns := filter.ParsePatterns(opts.InsensitiveExclude) insensitiveExcludePatterns := filter.ParsePatterns(opts.InsensitiveExclude)
if len(opts.ExcludeFiles) > 0 {
patternsFromFile, err := readPatternsFromFiles(opts.ExcludeFiles)
if err != nil {
return err
}
excludePatternsFromFile := filter.ParsePatterns(patternsFromFile)
excludePatterns = append(excludePatterns, excludePatternsFromFile...)
}
if len(opts.InsensitiveExcludeFiles) > 0 {
patternsFromFile, err := readPatternsFromFiles(opts.ExcludeFiles)
if err != nil {
return err
}
iexcludePatternsFromFile := filter.ParsePatterns(patternsFromFile)
insensitiveExcludePatterns = append(insensitiveExcludePatterns, iexcludePatternsFromFile...)
}
selectExcludeFilter := func(item string, _ string, node *restic.Node) (selectedForRestore bool, childMayBeSelected bool) { selectExcludeFilter := func(item string, _ string, node *restic.Node) (selectedForRestore bool, childMayBeSelected bool) {
matched, err := filter.List(excludePatterns, item) matched, err := filter.List(excludePatterns, item)
if err != nil { if err != nil {
@ -199,6 +228,27 @@ func runRestore(ctx context.Context, opts RestoreOptions, gopts GlobalOptions,
includePatterns := filter.ParsePatterns(opts.Include) includePatterns := filter.ParsePatterns(opts.Include)
insensitiveIncludePatterns := filter.ParsePatterns(opts.InsensitiveInclude) insensitiveIncludePatterns := filter.ParsePatterns(opts.InsensitiveInclude)
if len(opts.IncludeFiles) > 0 {
patternsFromFile, err := readPatternsFromFiles(opts.IncludeFiles)
if err != nil {
return err
}
includePatternsFromFile := filter.ParsePatterns(patternsFromFile)
includePatterns = append(includePatterns, includePatternsFromFile...)
}
if len(opts.InsensitiveIncludeFiles) > 0 {
patternsFromFile, err := readPatternsFromFiles(opts.InsensitiveIncludeFiles)
if err != nil {
return err
}
iincludePatternsFromFile := filter.ParsePatterns(patternsFromFile)
insensitiveIncludePatterns = append(insensitiveIncludePatterns, iincludePatternsFromFile...)
}
selectIncludeFilter := func(item string, _ string, node *restic.Node) (selectedForRestore bool, childMayBeSelected bool) { selectIncludeFilter := func(item string, _ string, node *restic.Node) (selectedForRestore bool, childMayBeSelected bool) {
matched, childMayMatch, err := filter.ListWithChild(includePatterns, item) matched, childMayMatch, err := filter.ListWithChild(includePatterns, item)
if err != nil { if err != nil {

View File

@ -385,12 +385,12 @@ func rejectBySize(maxSizeStr string) (RejectFunc, error) {
}, nil }, nil
} }
// readExcludePatternsFromFiles reads all exclude files and returns the list of // readPatternsFromFiles reads all files and returns the list of
// exclude patterns. For each line, leading and trailing white space is removed // patterns. For each line, leading and trailing white space is removed
// and comment lines are ignored. For each remaining pattern, environment // and comment lines are ignored. For each remaining pattern, environment
// variables are resolved. For adding a literal dollar sign ($), write $$ to // variables are resolved. For adding a literal dollar sign ($), write $$ to
// the file. // the file.
func readExcludePatternsFromFiles(excludeFiles []string) ([]string, error) { func readPatternsFromFiles(files []string) ([]string, error) {
getenvOrDollar := func(s string) string { getenvOrDollar := func(s string) string {
if s == "$" { if s == "$" {
return "$" return "$"
@ -398,8 +398,8 @@ func readExcludePatternsFromFiles(excludeFiles []string) ([]string, error) {
return os.Getenv(s) return os.Getenv(s)
} }
var excludes []string var patterns []string
for _, filename := range excludeFiles { for _, filename := range files {
err := func() (err error) { err := func() (err error) {
data, err := textfile.Read(filename) data, err := textfile.Read(filename)
if err != nil { if err != nil {
@ -421,15 +421,15 @@ func readExcludePatternsFromFiles(excludeFiles []string) ([]string, error) {
} }
line = os.Expand(line, getenvOrDollar) line = os.Expand(line, getenvOrDollar)
excludes = append(excludes, line) patterns = append(patterns, line)
} }
return scanner.Err() return scanner.Err()
}() }()
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to read excludes from file %q: %w", filename, err) return nil, fmt.Errorf("failed to read patterns from file %q: %w", filename, err)
} }
} }
return excludes, nil return patterns, nil
} }
type excludePatternOptions struct { type excludePatternOptions struct {
@ -454,7 +454,7 @@ func (opts excludePatternOptions) CollectPatterns() ([]RejectByNameFunc, error)
var fs []RejectByNameFunc var fs []RejectByNameFunc
// add patterns from file // add patterns from file
if len(opts.ExcludeFiles) > 0 { if len(opts.ExcludeFiles) > 0 {
excludePatterns, err := readExcludePatternsFromFiles(opts.ExcludeFiles) excludePatterns, err := readPatternsFromFiles(opts.ExcludeFiles)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -467,7 +467,7 @@ func (opts excludePatternOptions) CollectPatterns() ([]RejectByNameFunc, error)
} }
if len(opts.InsensitiveExcludeFiles) > 0 { if len(opts.InsensitiveExcludeFiles) > 0 {
excludes, err := readExcludePatternsFromFiles(opts.InsensitiveExcludeFiles) excludes, err := readPatternsFromFiles(opts.InsensitiveExcludeFiles)
if err != nil { if err != nil {
return nil, err return nil, err
} }