mirror of
https://github.com/octoleo/restic.git
synced 2024-11-25 06:07:44 +00:00
Make snapshots dirs in mount command customizable
This commit is contained in:
parent
57f4003f2f
commit
1751afae26
7
changelog/unreleased/issue-2907
Normal file
7
changelog/unreleased/issue-2907
Normal 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
|
@ -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")
|
||||||
}
|
}
|
||||||
@ -154,7 +181,8 @@ func runMount(opts MountOptions, gopts GlobalOptions, args []string) error {
|
|||||||
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)
|
||||||
|
|
||||||
|
@ -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}))
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,8 @@ type Config struct {
|
|||||||
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
|
||||||
|
if len(cfg.PathTemplates) == 0 {
|
||||||
|
cfg.PathTemplates = []string{
|
||||||
"ids/%i",
|
"ids/%i",
|
||||||
"snapshots/%T",
|
"snapshots/%T",
|
||||||
"hosts/%h/%T",
|
"hosts/%h/%T",
|
||||||
"tags/%t/%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
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user