diff --git a/changelog/unreleased/pull-2086 b/changelog/unreleased/pull-2086 new file mode 100644 index 000000000..5c033e750 --- /dev/null +++ b/changelog/unreleased/pull-2086 @@ -0,0 +1,7 @@ +Enhancement: Allow --files-from to be specified multiple times + +Before, restic took only the last file specified with `--files-from` into +account, this is now corrected. + +https://github.com/restic/restic/issues/2085 +https://github.com/restic/restic/pull/2086 diff --git a/cmd/restic/cmd_backup.go b/cmd/restic/cmd_backup.go index 1e47cd50c..fc24868a5 100644 --- a/cmd/restic/cmd_backup.go +++ b/cmd/restic/cmd_backup.go @@ -45,8 +45,12 @@ given as the arguments. }, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { - if backupOptions.Stdin && backupOptions.FilesFrom == "-" { - return errors.Fatal("cannot use both `--stdin` and `--files-from -`") + if backupOptions.Stdin { + for _, filename := range backupOptions.FilesFrom { + if filename == "-" { + return errors.Fatal("cannot use both `--stdin` and `--files-from -`") + } + } } var t tomb.Tomb @@ -75,7 +79,7 @@ type BackupOptions struct { StdinFilename string Tags []string Host string - FilesFrom string + FilesFrom []string TimeStamp string WithAtime bool } @@ -101,7 +105,7 @@ func init() { f.StringVar(&backupOptions.Host, "hostname", "", "set the `hostname` for the snapshot manually") f.MarkDeprecated("hostname", "use --host") - f.StringVar(&backupOptions.FilesFrom, "files-from", "", "read the files to backup from file (can be combined with file args)") + f.StringArrayVar(&backupOptions.FilesFrom, "files-from", nil, "read the files to backup from file (can be combined with file args/can be specified multiple times)") f.StringVar(&backupOptions.TimeStamp, "time", "", "time of the backup (ex. '2012-11-01 22:08:41') (default: now)") f.BoolVar(&backupOptions.WithAtime, "with-atime", false, "store the atime for all files and directories") } @@ -175,12 +179,16 @@ func readLinesFromFile(filename string) ([]string, error) { // Check returns an error when an invalid combination of options was set. func (opts BackupOptions) Check(gopts GlobalOptions, args []string) error { - if opts.FilesFrom == "-" && gopts.password == "" { - return errors.Fatal("unable to read password from stdin when data is to be read from stdin, use --password-file or $RESTIC_PASSWORD") + if gopts.password == "" { + for _, filename := range opts.FilesFrom { + if filename == "-" { + return errors.Fatal("unable to read password from stdin when data is to be read from stdin, use --password-file or $RESTIC_PASSWORD") + } + } } if opts.Stdin { - if opts.FilesFrom != "" { + if len(opts.FilesFrom) > 0 { return errors.Fatal("--stdin and --files-from cannot be used together") } @@ -302,23 +310,25 @@ func collectTargets(opts BackupOptions, args []string) (targets []string, err er return nil, nil } - fromfile, err := readLinesFromFile(opts.FilesFrom) - if err != nil { - return nil, err - } - - // expand wildcards var lines []string - for _, line := range fromfile { - var expanded []string - expanded, err := filepath.Glob(line) + for _, file := range opts.FilesFrom { + fromfile, err := readLinesFromFile(file) if err != nil { - return nil, errors.WithMessage(err, fmt.Sprintf("pattern: %s", line)) + return nil, err } - if len(expanded) == 0 { - Warnf("pattern %q does not match any files, skipping\n", line) + + // expand wildcards + for _, line := range fromfile { + var expanded []string + expanded, err := filepath.Glob(line) + if err != nil { + return nil, errors.WithMessage(err, fmt.Sprintf("pattern: %s", line)) + } + if len(expanded) == 0 { + Warnf("pattern %q does not match any files, skipping\n", line) + } + lines = append(lines, expanded...) } - lines = append(lines, expanded...) } // merge files from files-from into normal args so we can reuse the normal diff --git a/doc/040_backup.rst b/doc/040_backup.rst index 0ca976c5e..951f65a4c 100644 --- a/doc/040_backup.rst +++ b/doc/040_backup.rst @@ -205,8 +205,8 @@ backup ``/sys`` or ``/dev`` on a Linux system: $ restic -r /srv/restic-repo backup --one-file-system / By using the ``--files-from`` option you can read the files you want to -backup from a file. This is especially useful if a lot of files have to -be backed up that are not in the same folder or are maybe pre-filtered +backup from one or more files. This is especially useful if a lot of files have +to be backed up that are not in the same folder or are maybe pre-filtered by other software. For example maybe you want to backup files which have a name that matches a diff --git a/doc/manual_rest.rst b/doc/manual_rest.rst index e1f2ef8fd..bda66e9b7 100644 --- a/doc/manual_rest.rst +++ b/doc/manual_rest.rst @@ -80,7 +80,7 @@ command: --exclude-caches excludes cache directories that are marked with a CACHEDIR.TAG file --exclude-file file read exclude patterns from a file (can be specified multiple times) --exclude-if-present stringArray takes filename[:header], exclude contents of directories containing filename (except filename itself) if header of that file is as provided (can be specified multiple times) - --files-from string read the files to backup from file (can be combined with file args) + --files-from string read the files to backup from file (can be combined with file args/can be specified multiple times) -f, --force force re-reading the target files/directories (overrides the "parent" flag) -h, --help help for backup --hostname hostname set the hostname for the snapshot manually. To prevent an expensive rescan use the "parent" flag