Add a dry run flag
This commit is contained in:
180
filesystem.go
Normal file
180
filesystem.go
Normal file
@@ -0,0 +1,180 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var filesystem FileSystem = NewRealFileSystem()
|
||||
|
||||
// FileSystem abstracts filesystem operations so we can swap implementations
|
||||
type FileSystem interface {
|
||||
Remove(path string) error
|
||||
RemoveAll(path string) error
|
||||
MkdirAll(path string, perm os.FileMode) error
|
||||
Symlink(source, target string) error
|
||||
Link(source, target string) error
|
||||
SummaryLines() []string
|
||||
IsDryRun() bool
|
||||
}
|
||||
|
||||
const (
|
||||
opRemove = "remove"
|
||||
opRemoveAll = "remove_all"
|
||||
opMkdirAll = "mkdir_all"
|
||||
opSymlink = "symlink"
|
||||
opHardlink = "hardlink"
|
||||
)
|
||||
|
||||
type operationRecord struct {
|
||||
kind string
|
||||
source string
|
||||
target string
|
||||
err error
|
||||
dryRun bool
|
||||
}
|
||||
|
||||
func (r operationRecord) summaryLine() (string, bool) {
|
||||
if r.kind != opSymlink && r.kind != opHardlink {
|
||||
return "", false
|
||||
}
|
||||
|
||||
kindLabel := "Symlink"
|
||||
if r.kind == opHardlink {
|
||||
kindLabel = "Hardlink"
|
||||
}
|
||||
|
||||
status := "OK"
|
||||
if r.err != nil {
|
||||
status = fmt.Sprintf("FAIL: %v", r.err)
|
||||
} else if r.dryRun {
|
||||
status = "DRY-RUN"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s %s -> %s (%s)", kindLabel, r.source, r.target, status), true
|
||||
}
|
||||
|
||||
type baseFileSystem struct {
|
||||
mu sync.Mutex
|
||||
operations []operationRecord
|
||||
}
|
||||
|
||||
func (b *baseFileSystem) addOperation(kind, source, target string, err error, dryRun bool) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
b.operations = append(b.operations, operationRecord{
|
||||
kind: kind,
|
||||
source: source,
|
||||
target: target,
|
||||
err: err,
|
||||
dryRun: dryRun,
|
||||
})
|
||||
}
|
||||
|
||||
func (b *baseFileSystem) snapshot() []operationRecord {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
ops := make([]operationRecord, len(b.operations))
|
||||
copy(ops, b.operations)
|
||||
return ops
|
||||
}
|
||||
|
||||
func summarizeOperations(records []operationRecord) []string {
|
||||
var lines []string
|
||||
for _, record := range records {
|
||||
if line, ok := record.summaryLine(); ok {
|
||||
lines = append(lines, line)
|
||||
}
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
type realFileSystem struct {
|
||||
baseFileSystem
|
||||
}
|
||||
|
||||
// NewRealFileSystem returns a filesystem implementation that writes to disk
|
||||
func NewRealFileSystem() FileSystem {
|
||||
return &realFileSystem{}
|
||||
}
|
||||
|
||||
func (fs *realFileSystem) Remove(path string) error {
|
||||
err := os.Remove(path)
|
||||
fs.addOperation(opRemove, "", path, err, false)
|
||||
return err
|
||||
}
|
||||
|
||||
func (fs *realFileSystem) RemoveAll(path string) error {
|
||||
err := os.RemoveAll(path)
|
||||
fs.addOperation(opRemoveAll, "", path, err, false)
|
||||
return err
|
||||
}
|
||||
|
||||
func (fs *realFileSystem) MkdirAll(path string, perm os.FileMode) error {
|
||||
err := os.MkdirAll(path, perm)
|
||||
fs.addOperation(opMkdirAll, "", path, err, false)
|
||||
return err
|
||||
}
|
||||
|
||||
func (fs *realFileSystem) Symlink(source, target string) error {
|
||||
err := os.Symlink(source, target)
|
||||
fs.addOperation(opSymlink, source, target, err, false)
|
||||
return err
|
||||
}
|
||||
|
||||
func (fs *realFileSystem) Link(source, target string) error {
|
||||
err := os.Link(source, target)
|
||||
fs.addOperation(opHardlink, source, target, err, false)
|
||||
return err
|
||||
}
|
||||
|
||||
func (fs *realFileSystem) SummaryLines() []string {
|
||||
return summarizeOperations(fs.snapshot())
|
||||
}
|
||||
|
||||
func (fs *realFileSystem) IsDryRun() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type dryRunFileSystem struct {
|
||||
baseFileSystem
|
||||
}
|
||||
|
||||
// NewDryRunFileSystem returns a filesystem implementation that only records operations
|
||||
func NewDryRunFileSystem() FileSystem {
|
||||
return &dryRunFileSystem{}
|
||||
}
|
||||
|
||||
func (fs *dryRunFileSystem) Remove(path string) error {
|
||||
fs.addOperation(opRemove, "", path, nil, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fs *dryRunFileSystem) RemoveAll(path string) error {
|
||||
fs.addOperation(opRemoveAll, "", path, nil, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fs *dryRunFileSystem) MkdirAll(path string, perm os.FileMode) error {
|
||||
fs.addOperation(opMkdirAll, "", path, nil, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fs *dryRunFileSystem) Symlink(source, target string) error {
|
||||
fs.addOperation(opSymlink, source, target, nil, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fs *dryRunFileSystem) Link(source, target string) error {
|
||||
fs.addOperation(opHardlink, source, target, nil, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fs *dryRunFileSystem) SummaryLines() []string {
|
||||
return summarizeOperations(fs.snapshot())
|
||||
}
|
||||
|
||||
func (fs *dryRunFileSystem) IsDryRun() bool {
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user