diff --git a/duplicacy/duplicacy_main.go b/duplicacy/duplicacy_main.go index 1878772..c4534f8 100644 --- a/duplicacy/duplicacy_main.go +++ b/duplicacy/duplicacy_main.go @@ -548,7 +548,13 @@ func setPreference(context *cli.Context) { newPreference.DoNotSavePassword = triBool.IsTrue() } - newPreference.NobackupFile = context.String("nobackup-file") + if context.String("nobackup-file") != "" { + newPreference.NobackupFile = context.String("nobackup-file") + } + + if context.String("filters") != "" { + newPreference.FiltersFile = context.String("filters") + } key := context.String("key") value := context.String("value") @@ -731,7 +737,7 @@ func backupRepository(context *cli.Context) { uploadRateLimit := context.Int("limit-rate") enumOnly := context.Bool("enum-only") storage.SetRateLimits(0, uploadRateLimit) - backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile) + backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile, preference.FiltersFile) duplicacy.SavePassword(*preference, "password", password) backupManager.SetupSnapshotCache(preference.Name) @@ -808,7 +814,7 @@ func restoreRepository(context *cli.Context) { duplicacy.LOG_INFO("SNAPSHOT_FILTER", "Loaded %d include/exclude pattern(s)", len(patterns)) storage.SetRateLimits(context.Int("limit-rate"), 0) - backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile) + backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile, preference.FiltersFile) duplicacy.SavePassword(*preference, "password", password) loadRSAPrivateKey(context.String("key"), preference, backupManager, false) @@ -850,7 +856,7 @@ func listSnapshots(context *cli.Context) { tag := context.String("t") revisions := getRevisions(context) - backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile) + backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, "", "") duplicacy.SavePassword(*preference, "password", password) id := preference.SnapshotID @@ -901,7 +907,7 @@ func checkSnapshots(context *cli.Context) { tag := context.String("t") revisions := getRevisions(context) - backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile) + backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, "", "") duplicacy.SavePassword(*preference, "password", password) loadRSAPrivateKey(context.String("key"), preference, backupManager, false) @@ -958,7 +964,7 @@ func printFile(context *cli.Context) { snapshotID = context.String("id") } - backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile) + backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, "", "") duplicacy.SavePassword(*preference, "password", password) loadRSAPrivateKey(context.String("key"), preference, backupManager, false) @@ -1016,13 +1022,13 @@ func diff(context *cli.Context) { } compareByHash := context.Bool("hash") - backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile) + backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, "", "") duplicacy.SavePassword(*preference, "password", password) loadRSAPrivateKey(context.String("key"), preference, backupManager, false) backupManager.SetupSnapshotCache(preference.Name) - backupManager.SnapshotManager.Diff(repository, snapshotID, revisions, path, compareByHash, preference.NobackupFile) + backupManager.SnapshotManager.Diff(repository, snapshotID, revisions, path, compareByHash, preference.NobackupFile, preference.FiltersFile) runScript(context, preference.Name, "post") } @@ -1061,7 +1067,7 @@ func showHistory(context *cli.Context) { revisions := getRevisions(context) showLocalHash := context.Bool("hash") - backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile) + backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, "", "") duplicacy.SavePassword(*preference, "password", password) backupManager.SetupSnapshotCache(preference.Name) @@ -1124,7 +1130,7 @@ func pruneSnapshots(context *cli.Context) { os.Exit(ArgumentExitCode) } - backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile) + backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, "", "") duplicacy.SavePassword(*preference, "password", password) backupManager.SetupSnapshotCache(preference.Name) @@ -1164,7 +1170,7 @@ func copySnapshots(context *cli.Context) { sourcePassword = duplicacy.GetPassword(*source, "password", "Enter source storage password:", false, false) } - sourceManager := duplicacy.CreateBackupManager(source.SnapshotID, sourceStorage, repository, sourcePassword, source.NobackupFile) + sourceManager := duplicacy.CreateBackupManager(source.SnapshotID, sourceStorage, repository, sourcePassword, "", "") sourceManager.SetupSnapshotCache(source.Name) duplicacy.SavePassword(*source, "password", sourcePassword) @@ -1199,7 +1205,7 @@ func copySnapshots(context *cli.Context) { destinationStorage.SetRateLimits(0, context.Int("upload-limit-rate")) destinationManager := duplicacy.CreateBackupManager(destination.SnapshotID, destinationStorage, repository, - destinationPassword, destination.NobackupFile) + destinationPassword, "", "") duplicacy.SavePassword(*destination, "password", destinationPassword) destinationManager.SetupSnapshotCache(destination.Name) @@ -1883,6 +1889,11 @@ func main() { Usage: "use the specified storage instead of the default one", Argument: "", }, + cli.StringFlag{ + Name: "filters", + Usage: "specify the path of the filters file containing include/exclude patterns", + Argument: "", + }, }, Usage: "Change the options for the default or specified storage", ArgsUsage: " ", diff --git a/src/duplicacy_backupmanager.go b/src/duplicacy_backupmanager.go index ff98339..2e0d71a 100644 --- a/src/duplicacy_backupmanager.go +++ b/src/duplicacy_backupmanager.go @@ -35,6 +35,7 @@ type BackupManager struct { config *Config // contains a number of options nobackupFile string // don't backup directory when this file name is found + filtersFile string // the path to the filters file } func (manager *BackupManager) SetDryRun(dryRun bool) { @@ -44,7 +45,7 @@ func (manager *BackupManager) SetDryRun(dryRun bool) { // CreateBackupManager creates a backup manager using the specified 'storage'. 'snapshotID' is a unique id to // identify snapshots created for this repository. 'top' is the top directory of the repository. 'password' is the // master key which can be nil if encryption is not enabled. -func CreateBackupManager(snapshotID string, storage Storage, top string, password string, nobackupFile string) *BackupManager { +func CreateBackupManager(snapshotID string, storage Storage, top string, password string, nobackupFile string, filtersFile string) *BackupManager { config, _, err := DownloadConfig(storage, password) if err != nil { @@ -67,6 +68,7 @@ func CreateBackupManager(snapshotID string, storage Storage, top string, passwor config: config, nobackupFile: nobackupFile, + filtersFile: filtersFile, } if IsDebugging() { @@ -198,7 +200,8 @@ func (manager *BackupManager) Backup(top string, quickMode bool, threads int, ta defer DeleteShadowCopy() LOG_INFO("BACKUP_INDEXING", "Indexing %s", top) - localSnapshot, skippedDirectories, skippedFiles, err := CreateSnapshotFromDirectory(manager.snapshotID, shadowTop, manager.nobackupFile) + localSnapshot, skippedDirectories, skippedFiles, err := CreateSnapshotFromDirectory(manager.snapshotID, shadowTop, + manager.nobackupFile, manager.filtersFile) if err != nil { LOG_ERROR("SNAPSHOT_LIST", "Failed to list the directory %s: %v", top, err) return false @@ -770,7 +773,8 @@ func (manager *BackupManager) Restore(top string, revision int, inPlace bool, qu remoteSnapshot := manager.SnapshotManager.DownloadSnapshot(manager.snapshotID, revision) manager.SnapshotManager.DownloadSnapshotContents(remoteSnapshot, patterns, true) - localSnapshot, _, _, err := CreateSnapshotFromDirectory(manager.snapshotID, top, manager.nobackupFile) + localSnapshot, _, _, err := CreateSnapshotFromDirectory(manager.snapshotID, top, manager.nobackupFile, + manager.filtersFile) if err != nil { LOG_ERROR("SNAPSHOT_LIST", "Failed to list the repository: %v", err) return false diff --git a/src/duplicacy_backupmanager_test.go b/src/duplicacy_backupmanager_test.go index cff0965..988f762 100644 --- a/src/duplicacy_backupmanager_test.go +++ b/src/duplicacy_backupmanager_test.go @@ -239,7 +239,7 @@ func TestBackupManager(t *testing.T) { time.Sleep(time.Duration(delay) * time.Second) SetDuplicacyPreferencePath(testDir + "/repository1/.duplicacy") - backupManager := CreateBackupManager("host1", storage, testDir, password, "") + backupManager := CreateBackupManager("host1", storage, testDir, password, "", "") backupManager.SetupSnapshotCache("default") SetDuplicacyPreferencePath(testDir + "/repository1/.duplicacy") diff --git a/src/duplicacy_preference.go b/src/duplicacy_preference.go index 3ae35e9..6ec3904 100644 --- a/src/duplicacy_preference.go +++ b/src/duplicacy_preference.go @@ -25,6 +25,7 @@ type Preference struct { DoNotSavePassword bool `json:"no_save_password"` NobackupFile string `json:"nobackup_file"` Keys map[string]string `json:"keys"` + FiltersFile string `json:"filters"` } var preferencePath string diff --git a/src/duplicacy_snapshot.go b/src/duplicacy_snapshot.go index 304496e..016c85f 100644 --- a/src/duplicacy_snapshot.go +++ b/src/duplicacy_snapshot.go @@ -58,7 +58,7 @@ func CreateEmptySnapshot(id string) (snapshto *Snapshot) { // CreateSnapshotFromDirectory creates a snapshot from the local directory 'top'. Only 'Files' // will be constructed, while 'ChunkHashes' and 'ChunkLengths' can only be populated after uploading. -func CreateSnapshotFromDirectory(id string, top string, nobackupFile string) (snapshot *Snapshot, skippedDirectories []string, +func CreateSnapshotFromDirectory(id string, top string, nobackupFile string, filtersFile string) (snapshot *Snapshot, skippedDirectories []string, skippedFiles []string, err error) { snapshot = &Snapshot{ @@ -69,7 +69,10 @@ func CreateSnapshotFromDirectory(id string, top string, nobackupFile string) (sn var patterns []string - patterns = ProcessFilters() + if filtersFile == "" { + filtersFile = joinPath(GetDuplicacyPreferencePath(), "filters") + } + patterns = ProcessFilters(filtersFile) directories := make([]*Entry, 0, 256) directories = append(directories, CreateEntry("", 0, 0, 0)) @@ -121,8 +124,8 @@ func AppendPattern(patterns []string, new_pattern string) (new_patterns []string new_patterns = append(patterns, new_pattern) return new_patterns } -func ProcessFilters() (patterns []string) { - patterns = ProcessFilterFile(joinPath(GetDuplicacyPreferencePath(), "filters"), make([]string, 0)) +func ProcessFilters(filtersFile string) (patterns []string) { + patterns = ProcessFilterFile(filtersFile, make([]string, 0)) LOG_DEBUG("REGEX_DEBUG", "There are %d compiled regular expressions stored", len(RegexMap)) diff --git a/src/duplicacy_snapshotmanager.go b/src/duplicacy_snapshotmanager.go index 39e8426..018f2ce 100644 --- a/src/duplicacy_snapshotmanager.go +++ b/src/duplicacy_snapshotmanager.go @@ -1299,7 +1299,7 @@ func (manager *SnapshotManager) PrintFile(snapshotID string, revision int, path // Diff compares two snapshots, or two revision of a file if the file argument is given. func (manager *SnapshotManager) Diff(top string, snapshotID string, revisions []int, - filePath string, compareByHash bool, nobackupFile string) bool { + filePath string, compareByHash bool, nobackupFile string, filtersFile string) bool { LOG_DEBUG("DIFF_PARAMETERS", "top: %s, id: %s, revision: %v, path: %s, compareByHash: %t", top, snapshotID, revisions, filePath, compareByHash) @@ -1312,7 +1312,7 @@ func (manager *SnapshotManager) Diff(top string, snapshotID string, revisions [] if len(revisions) <= 1 { // Only scan the repository if filePath is not provided if len(filePath) == 0 { - rightSnapshot, _, _, err = CreateSnapshotFromDirectory(snapshotID, top, nobackupFile) + rightSnapshot, _, _, err = CreateSnapshotFromDirectory(snapshotID, top, nobackupFile, filtersFile) if err != nil { LOG_ERROR("SNAPSHOT_LIST", "Failed to list the directory %s: %v", top, err) return false