mirror of
https://github.com/jkl1337/duplicacy.git
synced 2026-01-04 04:34:45 -06:00
Add an -enum-only option to the backup command to enumerate the repository only
This commit is contained in:
@@ -714,13 +714,14 @@ func backupRepository(context *cli.Context) {
|
|||||||
|
|
||||||
dryRun := context.Bool("dry-run")
|
dryRun := context.Bool("dry-run")
|
||||||
uploadRateLimit := context.Int("limit-rate")
|
uploadRateLimit := context.Int("limit-rate")
|
||||||
|
enumOnly := context.Bool("enum-only")
|
||||||
storage.SetRateLimits(0, uploadRateLimit)
|
storage.SetRateLimits(0, uploadRateLimit)
|
||||||
backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile)
|
backupManager := duplicacy.CreateBackupManager(preference.SnapshotID, storage, repository, password, preference.NobackupFile)
|
||||||
duplicacy.SavePassword(*preference, "password", password)
|
duplicacy.SavePassword(*preference, "password", password)
|
||||||
|
|
||||||
backupManager.SetupSnapshotCache(preference.Name)
|
backupManager.SetupSnapshotCache(preference.Name)
|
||||||
backupManager.SetDryRun(dryRun)
|
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")
|
runScript(context, preference.Name, "post")
|
||||||
}
|
}
|
||||||
@@ -1363,6 +1364,10 @@ func main() {
|
|||||||
Usage: "backup to the specified storage instead of the default one",
|
Usage: "backup to the specified storage instead of the default one",
|
||||||
Argument: "<storage name>",
|
Argument: "<storage name>",
|
||||||
},
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "enum-only",
|
||||||
|
Usage: "enumerate the repository recursively and then exit",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Usage: "Save a snapshot of the repository to the storage",
|
Usage: "Save a snapshot of the repository to the storage",
|
||||||
ArgsUsage: " ",
|
ArgsUsage: " ",
|
||||||
|
|||||||
@@ -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
|
// 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.
|
// 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,
|
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
|
var err error
|
||||||
top, err = filepath.Abs(top)
|
top, err = filepath.Abs(top)
|
||||||
@@ -194,6 +194,10 @@ func (manager *BackupManager) Backup(top string, quickMode bool, threads int, ta
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if enumOnly {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// This cache contains all chunks referenced by last snasphot. Any other chunks will lead to a call to
|
// This cache contains all chunks referenced by last snasphot. Any other chunks will lead to a call to
|
||||||
// UploadChunk.
|
// UploadChunk.
|
||||||
chunkCache := make(map[string]bool)
|
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 {
|
for _, file := range remoteSnapshot.Files {
|
||||||
|
|
||||||
if MatchPath(file.Path, patterns) {
|
if MatchPath(file.Path, patterns) {
|
||||||
LOG_TRACE("RESTORE_INCLUDE", "Include %s", file.Path)
|
|
||||||
includedFiles = append(includedFiles, file)
|
includedFiles = append(includedFiles, file)
|
||||||
} else {
|
|
||||||
LOG_TRACE("RESTORE_EXCLUDE", "Exclude %s", file.Path)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ func TestBackupManager(t *testing.T) {
|
|||||||
backupManager.SetupSnapshotCache("default")
|
backupManager.SetupSnapshotCache("default")
|
||||||
|
|
||||||
SetDuplicacyPreferencePath(testDir + "/repository1/.duplicacy")
|
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)
|
time.Sleep(time.Duration(delay) * time.Second)
|
||||||
SetDuplicacyPreferencePath(testDir + "/repository2/.duplicacy")
|
SetDuplicacyPreferencePath(testDir + "/repository2/.duplicacy")
|
||||||
backupManager.Restore(testDir+"/repository2", threads, /*inPlace=*/false, /*quickMode=*/false, threads, /*overwrite=*/true,
|
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)
|
modifyFile(testDir+"/repository1/dir1/file3", 0.3)
|
||||||
|
|
||||||
SetDuplicacyPreferencePath(testDir + "/repository1/.duplicacy")
|
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)
|
time.Sleep(time.Duration(delay) * time.Second)
|
||||||
SetDuplicacyPreferencePath(testDir + "/repository2/.duplicacy")
|
SetDuplicacyPreferencePath(testDir + "/repository2/.duplicacy")
|
||||||
backupManager.Restore(testDir+"/repository2", 2, /*inPlace=*/true, /*quickMode=*/true, threads, /*overwrite=*/true,
|
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/dir2/dir3", 0700)
|
||||||
os.Mkdir(testDir+"/repository1/dir4", 0700)
|
os.Mkdir(testDir+"/repository1/dir4", 0700)
|
||||||
SetDuplicacyPreferencePath(testDir + "/repository1/.duplicacy")
|
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)
|
time.Sleep(time.Duration(delay) * time.Second)
|
||||||
|
|
||||||
// Create some directories and files under repository2 that will be deleted during restore
|
// 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*/, "",
|
backupManager.SnapshotManager.CheckSnapshots( /*snapshotID*/ "host1" /*revisions*/, []int{2, 3} /*tag*/, "",
|
||||||
/*showStatistics*/ false /*showTabular*/, false /*checkFiles*/, false /*searchFossils*/, false /*resurrect*/, false)
|
/*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,
|
backupManager.SnapshotManager.PruneSnapshots("host1", "host1" /*revisions*/, nil /*tags*/, nil /*retentions*/, nil,
|
||||||
/*exhaustive*/ false /*exclusive=*/, true /*ignoredIDs*/, nil /*dryRun*/, false /*deleteOnly*/, false /*collectOnly*/, false)
|
/*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)
|
numberOfSnapshots = backupManager.SnapshotManager.ListSnapshots( /*snapshotID*/ "host1" /*revisionsToList*/, nil /*tag*/, "" /*showFiles*/, false /*showChunks*/, false)
|
||||||
|
|||||||
@@ -478,7 +478,6 @@ func ListEntries(top string, path string, fileList *[]*Entry, patterns []string,
|
|||||||
}
|
}
|
||||||
entry := CreateEntryFromFileInfo(f, normalizedPath)
|
entry := CreateEntryFromFileInfo(f, normalizedPath)
|
||||||
if len(patterns) > 0 && !MatchPath(entry.Path, patterns) {
|
if len(patterns) > 0 && !MatchPath(entry.Path, patterns) {
|
||||||
LOG_DEBUG("LIST_EXCLUDE", "%s is excluded", entry.Path)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if entry.IsLink() {
|
if entry.IsLink() {
|
||||||
|
|||||||
@@ -344,11 +344,13 @@ func MatchPath(filePath string, patterns []string) (included bool) {
|
|||||||
for _, pattern := range patterns {
|
for _, pattern := range patterns {
|
||||||
if pattern[0] == '+' {
|
if pattern[0] == '+' {
|
||||||
if matchPattern(filePath, pattern[1:]) {
|
if matchPattern(filePath, pattern[1:]) {
|
||||||
|
LOG_DEBUG("PATTERN_INCLUDE", "%s is included by pattern %s", filePath, pattern)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
} else if pattern[0] == '-' {
|
} else if pattern[0] == '-' {
|
||||||
allIncludes = false
|
allIncludes = false
|
||||||
if matchPattern(filePath, pattern[1:]) {
|
if matchPattern(filePath, pattern[1:]) {
|
||||||
|
LOG_DEBUG("PATTERN_EXCLUDE", "%s is excluded by pattern %s", filePath, pattern)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
} else if strings.HasPrefix(pattern, "i:") || strings.HasPrefix(pattern, "e:") {
|
} 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)
|
matched = re.MatchString(filePath)
|
||||||
}
|
}
|
||||||
if matched {
|
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 {
|
} else {
|
||||||
if strings.HasPrefix(pattern, "e:") {
|
if strings.HasPrefix(pattern, "e:") {
|
||||||
allIncludes = false
|
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 {
|
func joinPath(components ...string) string {
|
||||||
|
|||||||
Reference in New Issue
Block a user