mirror of
https://github.com/kopia/kopia.git
synced 2026-01-25 23:08:01 -05:00
Both source and destination can be specified using user@host, @host or user@host:/path where destination values override the corresponding parts of the source, so both targeted and mass copying is supported. Supported combinations are: Source: Destination Behavior --------------------------------------------------- @host1 @host2 copy snapshots from all users of host1 user1@host1 @host2 copy all snapshots to user1@host2 user1@host1 user2@host2 copy all snapshots to user2@host2 user1@host1:/path1 @host2 copy to user1@host2:/path1 user1@host1:/path1 user2@host2 copy to user2@host2:/path1 user1@host1:/path1 user2@host2:/path2 copy snapshots from single path When --move is specified, the matching source snapshots are also deleted. * cli: upgraded kingpin to latest version (not tagged) This allows using `EnableFileExpansion` to disable treating arguments prefixed with "@" as file includes.
88 lines
2.2 KiB
Go
88 lines
2.2 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"strconv"
|
|
|
|
"github.com/alecthomas/kingpin"
|
|
|
|
"github.com/kopia/kopia/repo/blob"
|
|
"github.com/kopia/kopia/repo/blob/filesystem"
|
|
)
|
|
|
|
var options filesystem.Options
|
|
|
|
const (
|
|
defaultFileMode = 0o600
|
|
defaultDirMode = 0o700
|
|
)
|
|
|
|
var (
|
|
connectOwnerUID string
|
|
connectOwnerGID string
|
|
connectFileMode string
|
|
connectDirMode string
|
|
connectFlat bool
|
|
)
|
|
|
|
func connect(ctx context.Context, isNew bool) (blob.Storage, error) {
|
|
fso := options
|
|
if v := connectOwnerUID; v != "" {
|
|
fso.FileUID = getIntPtrValue(v, 10)
|
|
}
|
|
|
|
if v := connectOwnerGID; v != "" {
|
|
fso.FileGID = getIntPtrValue(v, 10)
|
|
}
|
|
|
|
fso.FileMode = getFileModeValue(connectFileMode, defaultFileMode)
|
|
fso.DirectoryMode = getFileModeValue(connectDirMode, defaultDirMode)
|
|
|
|
if connectFlat {
|
|
fso.DirectoryShards = []int{}
|
|
}
|
|
|
|
if isNew {
|
|
log(ctx).Debugf("creating directory for repository: %v dir mode: %v", fso.Path, fso.DirectoryMode)
|
|
|
|
if err := os.MkdirAll(fso.Path, fso.DirectoryMode); err != nil {
|
|
log(ctx).Warningf("unable to create directory: %v", fso.Path)
|
|
}
|
|
}
|
|
|
|
return filesystem.New(ctx, &fso)
|
|
}
|
|
|
|
func init() {
|
|
RegisterStorageConnectFlags(
|
|
"filesystem",
|
|
"a filesystem",
|
|
func(cmd *kingpin.CmdClause) {
|
|
cmd.Flag("path", "Path to the repository").Required().StringVar(&options.Path)
|
|
cmd.Flag("owner-uid", "User ID owning newly created files").PlaceHolder("USER").StringVar(&connectOwnerUID)
|
|
cmd.Flag("owner-gid", "Group ID owning newly created files").PlaceHolder("GROUP").StringVar(&connectOwnerGID)
|
|
cmd.Flag("file-mode", "File mode for newly created files (0600)").PlaceHolder("MODE").StringVar(&connectFileMode)
|
|
cmd.Flag("dir-mode", "Mode of newly directory files (0700)").PlaceHolder("MODE").StringVar(&connectDirMode)
|
|
cmd.Flag("flat", "Use flat directory structure").BoolVar(&connectFlat)
|
|
},
|
|
connect)
|
|
}
|
|
|
|
func getIntPtrValue(value string, base int) *int {
|
|
if int64Val, err := strconv.ParseInt(value, base, 32); err == nil {
|
|
intVal := int(int64Val)
|
|
return &intVal
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func getFileModeValue(value string, def os.FileMode) os.FileMode {
|
|
if uint32Val, err := strconv.ParseUint(value, 8, 32); err == nil {
|
|
return os.FileMode(uint32Val)
|
|
}
|
|
|
|
return def
|
|
}
|