diff --git a/duplicacy/duplicacy_main.go b/duplicacy/duplicacy_main.go index f911726..c0f6897 100644 --- a/duplicacy/duplicacy_main.go +++ b/duplicacy/duplicacy_main.go @@ -714,13 +714,14 @@ func backupRepository(context *cli.Context) { dryRun := context.Bool("dry-run") uploadRateLimit := context.Int("limit-rate") + enumOnly := context.Bool("enum-only") storage.SetRateLimits(0, uploadRateLimit) backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile) duplicacy.SavePassword(*preference, "password", password) backupManager.SetupSnapshotCache(preference.Name) backupManager.SetDryRun(dryRun) - backupManager.Backup(repository, quickMode, threads, context.String("t"), showStatistics, enableVSS, vssTimeout) + backupManager.Backup(repository, quickMode, threads, context.String("t"), showStatistics, enableVSS, vssTimeout, enumOnly) runScript(context, preference.Name, "post") } @@ -1363,6 +1364,10 @@ func main() { Usage: "backup to the specified storage instead of the default one", Argument: "", }, + cli.BoolFlag{ + Name: "enum-only", + Usage: "enumerate the repository recursively and then exit", + }, }, Usage: "Save a snapshot of the repository to the storage", ArgsUsage: " ", diff --git a/src/duplicacy_backupmanager.go b/src/duplicacy_backupmanager.go index 2671c19..8ce96b9 100644 --- a/src/duplicacy_backupmanager.go +++ b/src/duplicacy_backupmanager.go @@ -163,7 +163,7 @@ func setEntryContent(entries []*Entry, chunkLengths []int, offset int) { // unmodified files with last backup). Otherwise (or if this is the first backup), the entire repository will // be scanned to create the snapshot. 'tag' is the tag assigned to the new snapshot. func (manager *BackupManager) Backup(top string, quickMode bool, threads int, tag string, - showStatistics bool, shadowCopy bool, shadowCopyTimeout int) bool { + showStatistics bool, shadowCopy bool, shadowCopyTimeout int, enumOnly bool) bool { var err error top, err = filepath.Abs(top) @@ -194,6 +194,10 @@ func (manager *BackupManager) Backup(top string, quickMode bool, threads int, ta return false } + if enumOnly { + return true + } + // This cache contains all chunks referenced by last snasphot. Any other chunks will lead to a call to // UploadChunk. chunkCache := make(map[string]bool) @@ -771,10 +775,7 @@ func (manager *BackupManager) Restore(top string, revision int, inPlace bool, qu for _, file := range remoteSnapshot.Files { if MatchPath(file.Path, patterns) { - LOG_TRACE("RESTORE_INCLUDE", "Include %s", file.Path) includedFiles = append(includedFiles, file) - } else { - LOG_TRACE("RESTORE_EXCLUDE", "Exclude %s", file.Path) } } diff --git a/src/duplicacy_backupmanager_test.go b/src/duplicacy_backupmanager_test.go index 80b6ecc..e960ceb 100644 --- a/src/duplicacy_backupmanager_test.go +++ b/src/duplicacy_backupmanager_test.go @@ -243,7 +243,7 @@ func TestBackupManager(t *testing.T) { backupManager.SetupSnapshotCache("default") SetDuplicacyPreferencePath(testDir + "/repository1/.duplicacy") - backupManager.Backup(testDir+"/repository1" /*quickMode=*/, true, threads, "first", false, false, 0) + backupManager.Backup(testDir+"/repository1" /*quickMode=*/, true, threads, "first", false, false, 0, false) time.Sleep(time.Duration(delay) * time.Second) SetDuplicacyPreferencePath(testDir + "/repository2/.duplicacy") backupManager.Restore(testDir+"/repository2", threads, /*inPlace=*/false, /*quickMode=*/false, threads, /*overwrite=*/true, @@ -267,7 +267,7 @@ func TestBackupManager(t *testing.T) { modifyFile(testDir+"/repository1/dir1/file3", 0.3) SetDuplicacyPreferencePath(testDir + "/repository1/.duplicacy") - backupManager.Backup(testDir+"/repository1" /*quickMode=*/, true, threads, "second", false, false, 0) + backupManager.Backup(testDir+"/repository1" /*quickMode=*/, true, threads, "second", false, false, 0, false) time.Sleep(time.Duration(delay) * time.Second) SetDuplicacyPreferencePath(testDir + "/repository2/.duplicacy") backupManager.Restore(testDir+"/repository2", 2, /*inPlace=*/true, /*quickMode=*/true, threads, /*overwrite=*/true, @@ -287,7 +287,7 @@ func TestBackupManager(t *testing.T) { os.Mkdir(testDir+"/repository1/dir2/dir3", 0700) os.Mkdir(testDir+"/repository1/dir4", 0700) SetDuplicacyPreferencePath(testDir + "/repository1/.duplicacy") - backupManager.Backup(testDir+"/repository1" /*quickMode=*/, false, threads, "third", false, false, 0) + backupManager.Backup(testDir+"/repository1" /*quickMode=*/, false, threads, "third", false, false, 0, false) time.Sleep(time.Duration(delay) * time.Second) // Create some directories and files under repository2 that will be deleted during restore @@ -350,7 +350,7 @@ func TestBackupManager(t *testing.T) { } backupManager.SnapshotManager.CheckSnapshots( /*snapshotID*/ "host1" /*revisions*/, []int{2, 3} /*tag*/, "", /*showStatistics*/ false /*showTabular*/, false /*checkFiles*/, false /*searchFossils*/, false /*resurrect*/, false) - backupManager.Backup(testDir+"/repository1" /*quickMode=*/, false, threads, "fourth", false, false, 0) + backupManager.Backup(testDir+"/repository1" /*quickMode=*/, false, threads, "fourth", false, false, 0, false) backupManager.SnapshotManager.PruneSnapshots("host1", "host1" /*revisions*/, nil /*tags*/, nil /*retentions*/, nil, /*exhaustive*/ false /*exclusive=*/, true /*ignoredIDs*/, nil /*dryRun*/, false /*deleteOnly*/, false /*collectOnly*/, false) numberOfSnapshots = backupManager.SnapshotManager.ListSnapshots( /*snapshotID*/ "host1" /*revisionsToList*/, nil /*tag*/, "" /*showFiles*/, false /*showChunks*/, false) diff --git a/src/duplicacy_entry.go b/src/duplicacy_entry.go index bc6ab47..12b2571 100644 --- a/src/duplicacy_entry.go +++ b/src/duplicacy_entry.go @@ -478,7 +478,6 @@ func ListEntries(top string, path string, fileList *[]*Entry, patterns []string, } entry := CreateEntryFromFileInfo(f, normalizedPath) if len(patterns) > 0 && !MatchPath(entry.Path, patterns) { - LOG_DEBUG("LIST_EXCLUDE", "%s is excluded", entry.Path) continue } if entry.IsLink() { diff --git a/src/duplicacy_utils.go b/src/duplicacy_utils.go index 6bde65b..1bfa728 100644 --- a/src/duplicacy_utils.go +++ b/src/duplicacy_utils.go @@ -344,11 +344,13 @@ func MatchPath(filePath string, patterns []string) (included bool) { for _, pattern := range patterns { if pattern[0] == '+' { if matchPattern(filePath, pattern[1:]) { + LOG_DEBUG("PATTERN_INCLUDE", "%s is included by pattern %s", filePath, pattern) return true } } else if pattern[0] == '-' { allIncludes = false if matchPattern(filePath, pattern[1:]) { + LOG_DEBUG("PATTERN_EXCLUDE", "%s is excluded by pattern %s", filePath, pattern) return false } } else if strings.HasPrefix(pattern, "i:") || strings.HasPrefix(pattern, "e:") { @@ -363,7 +365,14 @@ func MatchPath(filePath string, patterns []string) (included bool) { matched = re.MatchString(filePath) } if matched { - return strings.HasPrefix(pattern, "i:") + if strings.HasPrefix(pattern, "i:") { + LOG_DEBUG("PATTERN_INCLUDE", "%s is included by pattern %s", filePath, pattern) + return true + } else { + LOG_DEBUG("PATTERN_EXCLUDE", "%s is excluded by pattern %s", filePath, pattern) + return false + + } } else { if strings.HasPrefix(pattern, "e:") { allIncludes = false @@ -372,7 +381,13 @@ func MatchPath(filePath string, patterns []string) (included bool) { } } - return !allIncludes + if allIncludes { + LOG_DEBUG("PATTERN_EXCLUDE", "%s is excluded", filePath) + return false + } else { + LOG_DEBUG("PATTERN_INCLUDE", "%s is included", filePath) + return true + } } func joinPath(components ...string) string {