2
2
mirror of https://github.com/octoleo/restic.git synced 2024-11-25 14:17:42 +00:00

Make snapshots dirs in mount command customizable

This commit is contained in:
Alexander Weiss 2020-09-03 20:31:57 +02:00 committed by Michael Eischer
parent 57f4003f2f
commit 1751afae26
4 changed files with 63 additions and 24 deletions

View File

@ -0,0 +1,7 @@
Enhancement: Make snapshot directory structure of mount command custimizable
We've added the possibility to customize the snapshot directory structure of the mount command.
This includes using subdirectories which is now also possible within time template and tags.
https://github.com/restic/restic/issues/2907
https://github.com/restic/restic/pull/2913

View File

@ -5,6 +5,7 @@ package main
import ( import (
"os" "os"
"strings"
"time" "time"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -30,10 +31,13 @@ read-only mount.
Snapshot Directories Snapshot Directories
==================== ====================
If you need a different template for all directories that contain snapshots, If you need a different template for directories that contain snapshots,
you can pass a template via --snapshot-template. Example without colons: you can pass a time template via --time-template and path templates via
--path-template.
--snapshot-template "2006-01-02_15-04-05" Example time template without colons:
--time-template "2006-01-02_15-04-05"
You need to specify a sample format for exactly the following timestamp: You need to specify a sample format for exactly the following timestamp:
@ -42,6 +46,20 @@ You need to specify a sample format for exactly the following timestamp:
For details please see the documentation for time.Format() at: For details please see the documentation for time.Format() at:
https://godoc.org/time#Time.Format https://godoc.org/time#Time.Format
For path templates, you can use the following patterns which will be replaced:
%i by short snapshot ID
%I by long snapshot ID
%u by username
%h by hostname
%t by tags
%T by timestamp as specified by --time-template
The default path templates are:
"ids/%i"
"snapshots/%T"
"hosts/%h/%T"
"tags/%t/%T"
EXIT STATUS EXIT STATUS
=========== ===========
@ -61,7 +79,8 @@ type MountOptions struct {
Hosts []string Hosts []string
Tags restic.TagLists Tags restic.TagLists
Paths []string Paths []string
SnapshotTemplate string TimeTemplate string
PathTemplates []string
} }
var mountOptions MountOptions var mountOptions MountOptions
@ -78,13 +97,21 @@ func init() {
mountFlags.Var(&mountOptions.Tags, "tag", "only consider snapshots which include this `taglist`") mountFlags.Var(&mountOptions.Tags, "tag", "only consider snapshots which include this `taglist`")
mountFlags.StringArrayVar(&mountOptions.Paths, "path", nil, "only consider snapshots which include this (absolute) `path`") mountFlags.StringArrayVar(&mountOptions.Paths, "path", nil, "only consider snapshots which include this (absolute) `path`")
mountFlags.StringVar(&mountOptions.SnapshotTemplate, "snapshot-template", time.RFC3339, "set `template` to use for snapshot dirs") mountFlags.StringArrayVar(&mountOptions.PathTemplates, "path-template", nil, "set `template` for path names (can be specified multiple times)")
mountFlags.StringVar(&mountOptions.TimeTemplate, "snapshot-template", time.RFC3339, "set `template` to use for snapshot dirs")
mountFlags.StringVar(&mountOptions.TimeTemplate, "time-template", time.RFC3339, "set `template` to use for times")
_ = mountFlags.MarkDeprecated("snapshot-template", "use --time-template")
} }
func runMount(opts MountOptions, gopts GlobalOptions, args []string) error { func runMount(opts MountOptions, gopts GlobalOptions, args []string) error {
if opts.SnapshotTemplate == "" { if opts.TimeTemplate == "" {
return errors.Fatal("snapshot template string cannot be empty") return errors.Fatal("time template string cannot be empty")
} }
if strings.HasPrefix(opts.TimeTemplate, "/") || strings.HasSuffix(opts.TimeTemplate, "/") {
return errors.Fatal("time template string cannot start or end with '/'")
}
if len(args) == 0 { if len(args) == 0 {
return errors.Fatal("wrong number of parameters") return errors.Fatal("wrong number of parameters")
} }
@ -150,11 +177,12 @@ func runMount(opts MountOptions, gopts GlobalOptions, args []string) error {
} }
cfg := fuse.Config{ cfg := fuse.Config{
OwnerIsRoot: opts.OwnerRoot, OwnerIsRoot: opts.OwnerRoot,
Hosts: opts.Hosts, Hosts: opts.Hosts,
Tags: opts.Tags, Tags: opts.Tags,
Paths: opts.Paths, Paths: opts.Paths,
SnapshotTemplate: opts.SnapshotTemplate, TimeTemplate: opts.TimeTemplate,
PathTemplates: opts.PathTemplates,
} }
root := fuse.NewRoot(repo, cfg) root := fuse.NewRoot(repo, cfg)

View File

@ -55,7 +55,7 @@ func waitForMount(t testing.TB, dir string) {
func testRunMount(t testing.TB, gopts GlobalOptions, dir string) { func testRunMount(t testing.TB, gopts GlobalOptions, dir string) {
opts := MountOptions{ opts := MountOptions{
SnapshotTemplate: time.RFC3339, TimeTemplate: time.RFC3339,
} }
rtest.OK(t, runMount(opts, gopts, []string{dir})) rtest.OK(t, runMount(opts, gopts, []string{dir}))
} }

View File

@ -15,11 +15,12 @@ import (
// Config holds settings for the fuse mount. // Config holds settings for the fuse mount.
type Config struct { type Config struct {
OwnerIsRoot bool OwnerIsRoot bool
Hosts []string Hosts []string
Tags []restic.TagList Tags []restic.TagList
Paths []string Paths []string
SnapshotTemplate string TimeTemplate string
PathTemplates []string
} }
// Root is the root node of the fuse mount of a repository. // Root is the root node of the fuse mount of a repository.
@ -59,14 +60,17 @@ func NewRoot(repo restic.Repository, cfg Config) *Root {
root.gid = uint32(os.Getgid()) root.gid = uint32(os.Getgid())
} }
paths := []string{ // set defaults, if PathTemplates is not set
"ids/%i", if len(cfg.PathTemplates) == 0 {
"snapshots/%T", cfg.PathTemplates = []string{
"hosts/%h/%T", "ids/%i",
"tags/%t/%T", "snapshots/%T",
"hosts/%h/%T",
"tags/%t/%T",
}
} }
root.SnapshotsDir = NewSnapshotsDir(root, rootInode, NewSnapshotsDirStructure(root, paths, cfg.SnapshotTemplate), "") root.SnapshotsDir = NewSnapshotsDir(root, rootInode, NewSnapshotsDirStructure(root, cfg.PathTemplates, cfg.TimeTemplate), "")
return root return root
} }