Use hidden directory based on mount path
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"bazil.org/fuse"
|
"bazil.org/fuse"
|
||||||
"bazil.org/fuse/fs"
|
"bazil.org/fuse/fs"
|
||||||
@@ -27,8 +28,8 @@ func main() {
|
|||||||
type Main struct {
|
type Main struct {
|
||||||
logger *log.Logger
|
logger *log.Logger
|
||||||
|
|
||||||
SourcePath string
|
TargetPath string
|
||||||
MountPath string
|
Path string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMain() *Main {
|
func NewMain() *Main {
|
||||||
@@ -39,19 +40,36 @@ func NewMain() *Main {
|
|||||||
|
|
||||||
func (m *Main) Run(args []string) (err error) {
|
func (m *Main) Run(args []string) (err error) {
|
||||||
flagSet := flag.NewFlagSet("litestream", flag.ContinueOnError)
|
flagSet := flag.NewFlagSet("litestream", flag.ContinueOnError)
|
||||||
|
flagSet.StringVar(&m.TargetPath, "target", "", "target directory")
|
||||||
verbose := flagSet.Bool("v", false, "verbose")
|
verbose := flagSet.Bool("v", false, "verbose")
|
||||||
flagSet.Usage = m.usage
|
flagSet.Usage = m.usage
|
||||||
if err := flagSet.Parse(args); err != nil {
|
if err := flagSet.Parse(args); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure src & mount paths are specified.
|
// Ensure mount path is specified.
|
||||||
if m.SourcePath = flagSet.Arg(0); m.SourcePath == "" {
|
if flagSet.NArg() > 1 {
|
||||||
return errors.New("source path required")
|
return errors.New("too many arguments, only specify mount path")
|
||||||
} else if m.MountPath = flagSet.Arg(1); m.MountPath == "" {
|
} else if m.Path = flagSet.Arg(0); m.Path == "" {
|
||||||
return errors.New("mount path required")
|
return errors.New("mount path required")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure mount path exists & is a directory.
|
||||||
|
if fi, err := os.Stat(m.Path); err != nil {
|
||||||
|
return err
|
||||||
|
} else if !fi.IsDir() {
|
||||||
|
return fmt.Errorf("mount path must be a directory")
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no target is specified, default to a hidden directory based on the mount path.
|
||||||
|
if m.TargetPath == "" {
|
||||||
|
m.TargetPath = filepath.Join(filepath.Dir(m.Path), "."+filepath.Base(m.Path))
|
||||||
|
|
||||||
|
if err := m.ensureTargetPath(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Setup logging, if verbose specified.
|
// Setup logging, if verbose specified.
|
||||||
var config fs.Config
|
var config fs.Config
|
||||||
if *verbose {
|
if *verbose {
|
||||||
@@ -60,29 +78,48 @@ func (m *Main) Run(args []string) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mount FUSE filesystem.
|
// Mount FUSE filesystem.
|
||||||
conn, err := fuse.Mount(m.MountPath, fuse.FSName("litestream"), fuse.Subtype("litestreamfs"))
|
conn, err := fuse.Mount(m.Path, fuse.FSName("litestream"), fuse.Subtype("litestreamfs"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer fuse.Unmount(m.MountPath)
|
defer fuse.Unmount(m.Path)
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
m.logger.Printf("mounted")
|
m.logger.Printf("mounted %s; target=%s", m.Path, m.TargetPath)
|
||||||
|
|
||||||
s := fs.New(conn, &config)
|
s := fs.New(conn, &config)
|
||||||
return s.Serve(&litestream.FileSystem{SourcePath: m.SourcePath})
|
return s.Serve(&litestream.FileSystem{TargetPath: m.TargetPath})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Main) ensureTargetPath() error {
|
||||||
|
// Check if target path exists, exit if it does.
|
||||||
|
if _, err := os.Stat(m.TargetPath); err == nil {
|
||||||
|
return nil
|
||||||
|
} else if err != nil && !os.IsNotExist(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create target path with the same permissions as the mount path.
|
||||||
|
fi, err := os.Stat(m.Path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return os.Mkdir(m.TargetPath, fi.Mode())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Main) usage() {
|
func (m *Main) usage() {
|
||||||
fmt.Println(`
|
fmt.Println(`
|
||||||
Litestream is a FUSE file system that automatically replicates SQLite databases.
|
Litestream is a FUSE file system that replicates SQLite databases.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
litestream [arguments] source_dir mount_dir
|
litestream [arguments] PATH
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
|
|
||||||
|
-target PATH
|
||||||
|
Specifies the directory to store data.
|
||||||
|
Defaults to a hidden directory next to PATH.
|
||||||
-v
|
-v
|
||||||
Enable verbose logging.
|
Enable verbose logging.
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ type FileSystem struct {
|
|||||||
config Config // configuration file
|
config Config // configuration file
|
||||||
|
|
||||||
// Filepath to the root of the source directory.
|
// Filepath to the root of the source directory.
|
||||||
SourcePath string
|
TargetPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFileSystem() *FileSystem {
|
func NewFileSystem() *FileSystem {
|
||||||
@@ -35,7 +35,7 @@ func NewFileSystem() *FileSystem {
|
|||||||
|
|
||||||
// ConfigPath returns the path to the file system config file.
|
// ConfigPath returns the path to the file system config file.
|
||||||
func (f *FileSystem) ConfigPath() string {
|
func (f *FileSystem) ConfigPath() string {
|
||||||
return filepath.Join(f.SourcePath, ConfigName)
|
return filepath.Join(f.TargetPath, ConfigName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open initializes the file system and finds all managed database files.
|
// Open initializes the file system and finds all managed database files.
|
||||||
|
|||||||
4
node.go
4
node.go
@@ -42,7 +42,7 @@ func NewNode(fs *FileSystem, path string) *Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) srcpath() string {
|
func (n *Node) srcpath() string {
|
||||||
return filepath.Join(n.fs.SourcePath, n.path)
|
return filepath.Join(n.fs.TargetPath, n.path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) Attr(ctx context.Context, a *fuse.Attr) (err error) {
|
func (n *Node) Attr(ctx context.Context, a *fuse.Attr) (err error) {
|
||||||
@@ -82,7 +82,7 @@ func (n *Node) Attr(ctx context.Context, a *fuse.Attr) (err error) {
|
|||||||
// Lookup need not to handle the names "." and "..".
|
// Lookup need not to handle the names "." and "..".
|
||||||
func (n *Node) Lookup(ctx context.Context, name string) (_ fs.Node, err error) {
|
func (n *Node) Lookup(ctx context.Context, name string) (_ fs.Node, err error) {
|
||||||
path := filepath.Join(n.path, name)
|
path := filepath.Join(n.path, name)
|
||||||
srcpath := filepath.Join(n.fs.SourcePath, path)
|
srcpath := filepath.Join(n.fs.TargetPath, path)
|
||||||
if _, err := os.Stat(srcpath); os.IsNotExist(err) {
|
if _, err := os.Stat(srcpath); os.IsNotExist(err) {
|
||||||
return nil, syscall.ENOENT
|
return nil, syscall.ENOENT
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user