mirror of
https://github.com/kopia/kopia.git
synced 2026-05-19 04:04:56 -04:00
changed how paths are interpreted for 'kopia backups' and 'kopia expire'
This commit is contained in:
@@ -79,8 +79,8 @@ func runBackupCommand(c *kingpin.ParseContext) error {
|
||||
|
||||
sourceInfo := repofs.SnapshotSourceInfo{
|
||||
Path: filepath.Clean(dir),
|
||||
Host: getBackupHostName(),
|
||||
UserName: getBackupUser(),
|
||||
Host: getHostNameOrDefault(*backupHostName),
|
||||
UserName: getUserOrDefault(*backupUser),
|
||||
}
|
||||
|
||||
if len(*backupDescription) > backupMaxDescriptionLength {
|
||||
@@ -142,8 +142,8 @@ func runBackupCommand(c *kingpin.ParseContext) error {
|
||||
}
|
||||
|
||||
func getLocalBackupPaths(vlt *vault.Vault) ([]string, error) {
|
||||
u := getBackupUser()
|
||||
h := getBackupHostName()
|
||||
u := getHostNameOrDefault(*backupHostName)
|
||||
h := getUserOrDefault(*backupUser)
|
||||
log.Printf("Looking for previous backups of '%v@%v'...", u, h)
|
||||
backupItems, err := vlt.List("B")
|
||||
if err != nil {
|
||||
@@ -179,19 +179,15 @@ func hashObjectID(oid string) string {
|
||||
return hex.EncodeToString(sum[0:foldLen])
|
||||
}
|
||||
|
||||
func getBackupUser() string {
|
||||
return getUserOrDefault(*backupUser)
|
||||
}
|
||||
|
||||
func getBackupHostName() string {
|
||||
return getHostNameOrDefault(*backupHostName)
|
||||
}
|
||||
|
||||
func getUserOrDefault(userName string) string {
|
||||
if userName != "" {
|
||||
return userName
|
||||
}
|
||||
|
||||
return getUserName()
|
||||
}
|
||||
|
||||
func getUserName() string {
|
||||
currentUser, err := user.Current()
|
||||
if err != nil {
|
||||
log.Fatalf("Cannot determine current user: %s", err)
|
||||
@@ -213,6 +209,10 @@ func getHostNameOrDefault(hostName string) string {
|
||||
return hostName
|
||||
}
|
||||
|
||||
return getHostName()
|
||||
}
|
||||
|
||||
func getHostName() string {
|
||||
hostname, err := os.Hostname()
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to determine hostname: %s", err)
|
||||
@@ -223,6 +223,7 @@ func getHostNameOrDefault(hostName string) string {
|
||||
|
||||
return hostname
|
||||
}
|
||||
|
||||
func init() {
|
||||
backupCommand.Action(runBackupCommand)
|
||||
}
|
||||
|
||||
@@ -19,16 +19,10 @@
|
||||
maxResultsPerPath = backupsCommand.Flag("maxresults", "Maximum number of results.").Default("100").Int()
|
||||
)
|
||||
|
||||
func findBackups(vlt *vault.Vault, path string) ([]string, string, error) {
|
||||
func findBackups(vlt *vault.Vault, sourceInfo repofs.SnapshotSourceInfo) ([]string, string, error) {
|
||||
var relPath string
|
||||
|
||||
for len(path) > 0 {
|
||||
sourceInfo := repofs.SnapshotSourceInfo{
|
||||
Path: path,
|
||||
Host: getBackupHostName(),
|
||||
UserName: getBackupUser(),
|
||||
}
|
||||
|
||||
for len(sourceInfo.Path) > 0 {
|
||||
prefix := sourceInfo.HashString() + "."
|
||||
|
||||
list, err := vlt.List("B" + prefix)
|
||||
@@ -41,18 +35,18 @@ func findBackups(vlt *vault.Vault, path string) ([]string, string, error) {
|
||||
}
|
||||
|
||||
if len(relPath) > 0 {
|
||||
relPath = filepath.Base(path) + "/" + relPath
|
||||
relPath = filepath.Base(sourceInfo.Path) + "/" + relPath
|
||||
} else {
|
||||
relPath = filepath.Base(path)
|
||||
relPath = filepath.Base(sourceInfo.Path)
|
||||
}
|
||||
|
||||
log.Printf("No backups of %v@%v:%v", sourceInfo.UserName, sourceInfo.Host, sourceInfo.Path)
|
||||
|
||||
parent := filepath.Dir(path)
|
||||
if parent == path {
|
||||
parentPath := filepath.Dir(sourceInfo.Path)
|
||||
if parentPath == sourceInfo.Path {
|
||||
break
|
||||
}
|
||||
path = parent
|
||||
sourceInfo.Path = parentPath
|
||||
}
|
||||
|
||||
return nil, "", nil
|
||||
@@ -67,12 +61,15 @@ func runBackupsCommand(context *kingpin.ParseContext) error {
|
||||
var err error
|
||||
|
||||
if *backupsPath != "" {
|
||||
path, err := filepath.Abs(*backupsPath)
|
||||
si, err := repofs.ParseSourceSnashotInfo(
|
||||
*backupsPath,
|
||||
getHostName(),
|
||||
getUserName())
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid directory: '%s': %s", *backupsPath, err)
|
||||
}
|
||||
|
||||
previous, relPath, err = findBackups(conn.Vault, filepath.Clean(path))
|
||||
previous, relPath, err = findBackups(conn.Vault, si)
|
||||
if relPath != "" {
|
||||
relPath = "/" + relPath
|
||||
}
|
||||
@@ -165,6 +162,4 @@ func loadBackupManifests(vlt *vault.Vault, names []string) []*repofs.Snapshot {
|
||||
|
||||
func init() {
|
||||
backupsCommand.Action(runBackupsCommand)
|
||||
backupsCommand.Flag("host", "Override backup hostname.").StringVar(backupHostName)
|
||||
backupsCommand.Flag("user", "Override backup user.").StringVar(backupUser)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -18,9 +17,9 @@
|
||||
expireCommand = app.Command("expire", "Remove old backups.")
|
||||
|
||||
expirationPolicies = map[string]func(){
|
||||
"KEEP_ALL": expirationPolicyKeepAll,
|
||||
"MANUAL": expirationPolicyManual,
|
||||
"DEFAULT": expirationPolicyDefault,
|
||||
"keep-all": expirationPolicyKeepAll,
|
||||
"manual": expirationPolicyManual,
|
||||
"default": expirationPolicyDefault,
|
||||
}
|
||||
|
||||
expireKeepLatest = expireCommand.Flag("keep-latest", "Number of most recent backups to keep per source").Int()
|
||||
@@ -29,9 +28,10 @@
|
||||
expireKeepWeekly = expireCommand.Flag("keep-weekly", "Number of most-recent weekly backups to keep per source").Int()
|
||||
expireKeepMonthly = expireCommand.Flag("keep-monthly", "Number of most-recent monthly backups to keep per source").Int()
|
||||
expireKeepAnnual = expireCommand.Flag("keep-annual", "Number of most-recent annual backups to keep per source").Int()
|
||||
expirePolicy = expireCommand.Flag("policy", "Expiration policy to use: "+strings.Join(expirationPolicyNames(), ",")).Default("DEFAULT").Enum(expirationPolicyNames()...)
|
||||
expirePolicy = expireCommand.Flag("policy", "Expiration policy to use: "+strings.Join(expirationPolicyNames(), ",")).Required().Enum(expirationPolicyNames()...)
|
||||
expireHost = expireCommand.Flag("host", "Expire backups from a given host").Default("").String()
|
||||
expireUser = expireCommand.Flag("user", "Expire backups from a given user").Default("").String()
|
||||
expireAll = expireCommand.Flag("all", "Expire all backups").Bool()
|
||||
expirePaths = expireCommand.Arg("path", "Expire backups for a given paths only").Strings()
|
||||
|
||||
expireDelete = expireCommand.Flag("delete", "Whether to actually delete backups").Default("no").String()
|
||||
@@ -149,28 +149,23 @@ func expire(snapshots []*repofs.Snapshot, snapshotNames []string) []string {
|
||||
}
|
||||
|
||||
func getSnapshotNamesToExpire(v *vault.Vault) ([]string, error) {
|
||||
if len(*expirePaths) == 0 {
|
||||
if !*expireAll && len(*expirePaths) == 0 {
|
||||
return nil, fmt.Errorf("Must specify paths to expire or --all")
|
||||
}
|
||||
|
||||
if *expireAll {
|
||||
fmt.Fprintf(os.Stderr, "Scanning all active snapshots...\n")
|
||||
return v.List("B")
|
||||
}
|
||||
|
||||
var result []string
|
||||
|
||||
hostName := getHostNameOrDefault(*expireHost)
|
||||
user := getUserOrDefault(*expireUser)
|
||||
|
||||
for _, p := range *expirePaths {
|
||||
path, err := filepath.Abs(p)
|
||||
si, err := repofs.ParseSourceSnashotInfo(p, *expireHost, *expireUser)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid directory: '%s': %s", p, err)
|
||||
return nil, fmt.Errorf("unable to parse %v: %v", p, err)
|
||||
}
|
||||
|
||||
var si repofs.SnapshotSourceInfo
|
||||
|
||||
si.Host = hostName
|
||||
si.UserName = user
|
||||
si.Path = filepath.Clean(path)
|
||||
|
||||
log.Printf("Looking for backups of %v", si)
|
||||
|
||||
matches, err := v.List("B" + si.HashString())
|
||||
@@ -178,6 +173,8 @@ func getSnapshotNamesToExpire(v *vault.Vault) ([]string, error) {
|
||||
return nil, fmt.Errorf("error listing backups for %v: %v", si, err)
|
||||
}
|
||||
|
||||
log.Printf("Found %v backups of %v", len(matches), si)
|
||||
|
||||
result = append(result, matches...)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/kopia/kopia/repo"
|
||||
@@ -20,7 +22,34 @@ type SnapshotSourceInfo struct {
|
||||
}
|
||||
|
||||
func (ssi SnapshotSourceInfo) String() string {
|
||||
return fmt.Sprintf("%v@%v : %v", ssi.UserName, ssi.Host, ssi.Path)
|
||||
return fmt.Sprintf("%v@%v:%v", ssi.UserName, ssi.Host, ssi.Path)
|
||||
}
|
||||
|
||||
// ParseSourceSnashotInfo parses a given path in the context of given hostname and username and returns
|
||||
// SnapshotSourceInfo. The path may be bare (in which case it's interpreted as local path and canonicalized)
|
||||
// or may be 'username@host:path' where path, username and host are not processed.
|
||||
func ParseSourceSnashotInfo(path string, hostname string, username string) (SnapshotSourceInfo, error) {
|
||||
p1 := strings.Index(path, "@")
|
||||
p2 := strings.Index(path, ":")
|
||||
|
||||
if p1 > 0 && p2 > 0 && p1 < p2 && p2 < len(path) {
|
||||
return SnapshotSourceInfo{
|
||||
UserName: path[0:p1],
|
||||
Host: path[p1+1 : p2],
|
||||
Path: path[p2+1:],
|
||||
}, nil
|
||||
}
|
||||
|
||||
absPath, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
return SnapshotSourceInfo{}, fmt.Errorf("invalid directory: '%s': %s", path, err)
|
||||
}
|
||||
|
||||
return SnapshotSourceInfo{
|
||||
Host: hostname,
|
||||
UserName: username,
|
||||
Path: filepath.Clean(absPath),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// HashString generates hash of SnapshotSourceInfo.
|
||||
|
||||
Reference in New Issue
Block a user