mirror of
https://github.com/kopia/kopia.git
synced 2026-05-19 04:04:56 -04:00
added ability to mount special object 'all' that exposes the whole set of snapshots grouped by user@host, path and time
This commit is contained in:
@@ -43,12 +43,22 @@ func runMountCommand(context *kingpin.ParseContext) error {
|
||||
fuse.VolumeName("Kopia"),
|
||||
)
|
||||
|
||||
oid, err := parseObjectID(*mountObjectID, rep)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
entry := repofs.Directory(rep, oid)
|
||||
var entry fs.Directory
|
||||
|
||||
if *mountObjectID == "all" {
|
||||
entry = repofs.AllSources(rep)
|
||||
} else {
|
||||
oid, err := parseObjectID(*mountObjectID, rep)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
entry = repofs.Directory(rep, oid)
|
||||
}
|
||||
|
||||
if *mountTraceFS {
|
||||
entry = loggingfs.Wrap(entry).(fs.Directory)
|
||||
}
|
||||
|
||||
59
fs/repofs/all_sources.go
Normal file
59
fs/repofs/all_sources.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package repofs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/kopia/kopia/fs"
|
||||
"github.com/kopia/kopia/repo"
|
||||
"github.com/kopia/kopia/snapshot"
|
||||
)
|
||||
|
||||
type repositoryAllSources struct {
|
||||
repo *repo.Repository
|
||||
snapshotManager *snapshot.Manager
|
||||
}
|
||||
|
||||
func (s *repositoryAllSources) Parent() fs.Directory {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *repositoryAllSources) Metadata() *fs.EntryMetadata {
|
||||
return &fs.EntryMetadata{
|
||||
Name: "/",
|
||||
Permissions: 0555,
|
||||
Type: fs.EntryTypeDirectory,
|
||||
ModTime: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *repositoryAllSources) Readdir() (fs.Entries, error) {
|
||||
srcs, err := s.snapshotManager.ListSources()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
users := map[string]bool{}
|
||||
for _, src := range srcs {
|
||||
users[fmt.Sprintf("%v@%v", src.UserName, src.Host)] = true
|
||||
}
|
||||
|
||||
var result fs.Entries
|
||||
for u := range users {
|
||||
result = append(result, &sourceDirectories{
|
||||
parent: s,
|
||||
repo: s.repo,
|
||||
snapshotManager: s.snapshotManager,
|
||||
userHost: u,
|
||||
})
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// AllSources returns fs.Directory that contains the list of all snapshot sources found in the repository.
|
||||
func AllSources(r *repo.Repository) fs.Directory {
|
||||
sm := snapshot.NewManager(r)
|
||||
|
||||
return &repositoryAllSources{repo: r, snapshotManager: sm}
|
||||
}
|
||||
48
fs/repofs/source_directories.go
Normal file
48
fs/repofs/source_directories.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package repofs
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/kopia/kopia/fs"
|
||||
"github.com/kopia/kopia/repo"
|
||||
"github.com/kopia/kopia/snapshot"
|
||||
)
|
||||
|
||||
type sourceDirectories struct {
|
||||
parent fs.Directory
|
||||
repo *repo.Repository
|
||||
snapshotManager *snapshot.Manager
|
||||
userHost string
|
||||
}
|
||||
|
||||
func (s *sourceDirectories) Parent() fs.Directory {
|
||||
return s.parent
|
||||
}
|
||||
|
||||
func (s *sourceDirectories) Metadata() *fs.EntryMetadata {
|
||||
return &fs.EntryMetadata{
|
||||
Name: s.userHost,
|
||||
Permissions: 0555,
|
||||
Type: fs.EntryTypeDirectory,
|
||||
ModTime: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *sourceDirectories) Readdir() (fs.Entries, error) {
|
||||
sources, err := s.snapshotManager.ListSources()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result fs.Entries
|
||||
|
||||
for _, src := range sources {
|
||||
if src.UserName+"@"+src.Host != s.userHost {
|
||||
continue
|
||||
}
|
||||
|
||||
result = append(result, &sourceSnapshots{s, s.repo, s.snapshotManager, src})
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
64
fs/repofs/source_snapshots.go
Normal file
64
fs/repofs/source_snapshots.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package repofs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/kopia/kopia/fs"
|
||||
"github.com/kopia/kopia/internal/dir"
|
||||
"github.com/kopia/kopia/repo"
|
||||
"github.com/kopia/kopia/snapshot"
|
||||
)
|
||||
|
||||
type sourceSnapshots struct {
|
||||
parent fs.Directory
|
||||
repo *repo.Repository
|
||||
snapshotManager *snapshot.Manager
|
||||
src *snapshot.SourceInfo
|
||||
}
|
||||
|
||||
func (s *sourceSnapshots) Parent() fs.Directory {
|
||||
return s.parent
|
||||
}
|
||||
|
||||
func (s *sourceSnapshots) Metadata() *fs.EntryMetadata {
|
||||
return &fs.EntryMetadata{
|
||||
Name: fmt.Sprintf("%v", safeName(s.src.Path)),
|
||||
Permissions: 0555,
|
||||
Type: fs.EntryTypeDirectory,
|
||||
}
|
||||
}
|
||||
|
||||
func safeName(path string) string {
|
||||
path = strings.TrimLeft(path, "/")
|
||||
return strings.Replace(path, "/", "_", -1)
|
||||
}
|
||||
|
||||
func (s *sourceSnapshots) Readdir() (fs.Entries, error) {
|
||||
manifests, err := s.snapshotManager.ListSnapshots(s.src, -1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result fs.Entries
|
||||
|
||||
for _, m := range manifests {
|
||||
name := m.StartTime.Format("20060102-150405")
|
||||
if m.IncompleteReason != "" {
|
||||
name += fmt.Sprintf(" (%v)", m.IncompleteReason)
|
||||
}
|
||||
e := newRepoEntry(s.repo, &dir.Entry{
|
||||
EntryMetadata: fs.EntryMetadata{
|
||||
Name: name,
|
||||
Permissions: 0555,
|
||||
Type: fs.EntryTypeDirectory,
|
||||
ModTime: m.StartTime,
|
||||
},
|
||||
ObjectID: m.RootObjectID,
|
||||
}, s)
|
||||
|
||||
result = append(result, e)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"github.com/kopia/kopia/fs"
|
||||
|
||||
@@ -72,11 +73,21 @@ func (dir *fuseDirectoryNode) Lookup(ctx context.Context, fileName string) (fuse
|
||||
}
|
||||
|
||||
return newFuseNode(e, dir.cache)
|
||||
|
||||
}
|
||||
|
||||
func (dir *fuseDirectoryNode) readPossiblyCachedReaddir() (fs.Entries, error) {
|
||||
return dir.cache.getEntries(dir.cacheID, func() (fs.Entries, error) { return dir.directory().Readdir() })
|
||||
return dir.cache.getEntries(dir.cacheID, func() (fs.Entries, error) {
|
||||
entries, err := dir.directory().Readdir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sort.Slice(entries, func(i, j int) bool {
|
||||
return entries[i].Metadata().Name < entries[j].Metadata().Name
|
||||
})
|
||||
|
||||
return entries, nil
|
||||
})
|
||||
}
|
||||
|
||||
func (dir *fuseDirectoryNode) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
|
||||
|
||||
Reference in New Issue
Block a user