diff options
| -rw-r--r-- | Magefile.go | 5 | ||||
| -rw-r--r-- | examples/examples.go | 37 | ||||
| -rw-r--r-- | internal/file/file.go | 41 | ||||
| -rw-r--r-- | internal/file/file_test.go | 54 |
4 files changed, 63 insertions, 74 deletions
diff --git a/Magefile.go b/Magefile.go index 44cfeee..0c3c59c 100644 --- a/Magefile.go +++ b/Magefile.go @@ -32,7 +32,6 @@ func Build() error { return run("go", "build", "-o", binName, "./cmd/gonf") } - // Run builds and runs the program. func Run() error { fmt.Println("running...") @@ -45,7 +44,7 @@ func Run() error { // Test runs all unit tests. func Test() error { fmt.Println("testing...") - return run("go", "test", "./...") + return run("go", "test", "-v", "./...") } // Lint runs go vet. @@ -77,4 +76,4 @@ func Uninstall() error { fmt.Println("removed " + binPath) } return nil -}
\ No newline at end of file +} diff --git a/examples/examples.go b/examples/examples.go index 180b446..8fe0f0d 100644 --- a/examples/examples.go +++ b/examples/examples.go @@ -1,31 +1,34 @@ package examples import ( - "fmt" - "codeberg.org/snonux/gonf/internal/file" ) func Run() error { - if err := file.Have("/tmp/gonf_example.conf", file.WithSource("source://assets/testfiles/test.tmpl")); err != nil { - return fmt.Errorf("failed to create example conf: %w", err) - } + // 1. Regular file with content + file.Have("/tmp/gonf_hello.txt", file.WithContent("Hello World!")) + + // 2. Regular file from a source template + file.Have("/tmp/gonf_example.conf", file.WithSource("assets/testfiles/test.tmpl")) + + // 3. Regular file with specific mode and owner + file.Have( + "/tmp/gonf_secret.txt", + file.WithContent("top secret"), + file.WithMode(0o600), + ) - if err := file.Have("/tmp/foo.txt", file.WithContent("hi")); err != nil { - return fmt.Errorf("failed to create foo.txt: %w", err) - } + // 4. A directory + file.Have("/tmp/gonf_dir", file.IsDirectory(), file.WithMode(0o755)) - if err := file.Have("/tmp/gonf_example_dir", file.IsDirectory(), file.WithMode(0o755)); err != nil { - return fmt.Errorf("failed to create example dir: %w", err) - } + // 5. A symlink + file.Have("/tmp/gonf_link", file.IsSymlink("/tmp/gonf_hello.txt")) - if err := file.Have("/tmp/gonf_example_link", file.IsSymlink("/tmp/foo.txt")); err != nil { - return fmt.Errorf("failed to create example symlink: %w", err) - } + // 6. A hardlink + file.Have("/tmp/gonf_hardlink", file.IsHardlink("/tmp/gonf_hello.txt")) - if err := file.Have("/tmp/gonf_example_hardlink", file.Hardlink("/tmp/foo.txt")); err != nil { - return fmt.Errorf("failed to create example hardlink: %w", err) - } + // 7. Ensuring something is absent + file.Have("/tmp/gonf_old.txt", file.IsAbsent()) return nil } diff --git a/internal/file/file.go b/internal/file/file.go index e6547c3..7f86d41 100644 --- a/internal/file/file.go +++ b/internal/file/file.go @@ -91,7 +91,7 @@ func IsSymlink(target string) Option { } } -func Hardlink(target string) Option { +func IsHardlink(target string) Option { return func(f *File) { f.hardlink = true f.hardlinkTarget = target @@ -104,10 +104,19 @@ func PruneDirectory() Option { } } -func Have(path string, opts ...Option) error { +func Have(path string, opts ...Option) resource.Resource { + res, err := have(path, opts...) + if err != nil { + log.Fatalf("failed to apply file resource %s: %v", path, err) + } + + return res +} + +func have(path string, opts ...Option) (resource.Resource, error) { curr, err := user.Current() if err != nil { - log.Fatalf("failed to get current user for default: %v", err) + return resource.Resource{}, fmt.Errorf("failed to get current user for default: %w", err) } f := &File{ @@ -127,34 +136,36 @@ func Have(path string, opts ...Option) error { // Apply dispatches to the concrete resource implementation based on the // options that were set. Each kind lives in its own file: // regular_file.go, directory.go and symlink.go. -func (f *File) Apply() error { +func (f *File) Apply() (resource.Resource, error) { + var res resource.Resource + switch { case f.absent: - _ = resource.Register(f.resourceType(), f.path) - return f.haveAbsent() + res = resource.Register(f.resourceType(), f.path) + return res, f.haveAbsent() case f.symlink: - _ = resource.Register("Symlink", f.path) - return f.haveSymlink() + res = resource.Register("Symlink", f.path) + return res, f.haveSymlink() case f.hardlink: - _ = resource.Register("Hardlink", f.path) - return f.haveHardlink() + res = resource.Register("Hardlink", f.path) + return res, f.haveHardlink() case f.directory: if !f.modeSet { f.mode = 0o750 } - _ = resource.Register("Directory", f.path) - return f.haveDirectory() + res = resource.Register("Directory", f.path) + return res, f.haveDirectory() default: - _ = resource.Register("File", f.path) + res = resource.Register("File", f.path) content, err := f.resolveContent() if err != nil { - return fmt.Errorf("failed to resolve content for %s: %w", f.path, err) + return res, fmt.Errorf("failed to resolve content for %s: %w", f.path, err) } - return f.haveRegularFile(content) + return res, f.haveRegularFile(content) } } diff --git a/internal/file/file_test.go b/internal/file/file_test.go index d9e09ac..a6488ce 100644 --- a/internal/file/file_test.go +++ b/internal/file/file_test.go @@ -101,9 +101,7 @@ func TestHaveStringCreateNewFile(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "new.txt") - if err := Have(path, WithContent("hello world")); err != nil { - t.Fatalf("unexpected error: %v", err) - } + Have(path, WithContent("hello world")) got, err := os.ReadFile(path) if err != nil { @@ -119,9 +117,7 @@ func TestHaveMode(t *testing.T) { path := filepath.Join(dir, "mode.txt") mode := os.FileMode(0o600) - if err := Have(path, WithContent("mode test"), WithMode(mode)); err != nil { - t.Fatalf("unexpected error: %v", err) - } + Have(path, WithContent("mode test"), WithMode(mode)) info, err := os.Stat(path) if err != nil { @@ -138,9 +134,7 @@ func TestHaveSourceFile(t *testing.T) { sourcePath := filepath.Join("..", "..", "assets", "testfiles", "test.txt") targetPath := filepath.Join(dir, "target.txt") - if err := Have(targetPath, WithSource(sourcePath)); err != nil { - t.Fatalf("unexpected error: %v", err) - } + Have(targetPath, WithSource(sourcePath)) got, err := os.ReadFile(targetPath) if err != nil { @@ -157,9 +151,7 @@ func TestHaveTemplateFile(t *testing.T) { sourcePath := filepath.Join("..", "..", "assets", "testfiles", "test.tmpl") targetPath := filepath.Join(dir, "target.conf") - if err := Have(targetPath, WithSource(sourcePath)); err != nil { - t.Fatalf("unexpected error: %v", err) - } + Have(targetPath, WithSource(sourcePath)) got, err := os.ReadFile(targetPath) if err != nil { @@ -176,9 +168,7 @@ func TestHaveDirectoryCreate(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "sub", "nested") - if err := Have(path, IsDirectory()); err != nil { - t.Fatalf("unexpected error: %v", err) - } + Have(path, IsDirectory()) info, err := os.Stat(path) if err != nil { @@ -223,7 +213,7 @@ func TestHaveDirectoryFailsWhenFileExists(t *testing.T) { t.Fatal(err) } - if err := Have(path, IsDirectory()); err == nil { + if _, err := have(path, IsDirectory()); err == nil { t.Error("expected error when a regular file is in the way of a directory") } } @@ -236,9 +226,7 @@ func TestHaveSymlinkCreateAndIdempotent(t *testing.T) { t.Fatal(err) } - if err := Have(link, IsSymlink(target)); err != nil { - t.Fatalf("create: %v", err) - } + Have(link, IsSymlink(target)) got, err := os.Readlink(link) if err != nil { t.Fatalf("readlink: %v", err) @@ -269,9 +257,7 @@ func TestHaveSymlinkRepoints(t *testing.T) { t.Fatal(err) } - if err := Have(link, IsSymlink(newT)); err != nil { - t.Fatalf("repoint: %v", err) - } + Have(link, IsSymlink(newT)) got, err := os.Readlink(link) if err != nil { t.Fatal(err) @@ -292,9 +278,7 @@ func TestHaveSymlinkMovesRealFileAside(t *testing.T) { t.Fatal(err) } - if err := Have(link, IsSymlink(target)); err != nil { - t.Fatalf("symlink over real file: %v", err) - } + Have(link, IsSymlink(target)) got, err := os.Readlink(link) if err != nil { @@ -315,9 +299,7 @@ func TestHaveAbsent(t *testing.T) { t.Fatal(err) } - if err := Have(path, IsAbsent()); err != nil { - t.Fatalf("absent: %v", err) - } + Have(path, IsAbsent()) if _, err := os.Stat(path); !os.IsNotExist(err) { t.Errorf("expected %s to be removed", path) } @@ -338,9 +320,7 @@ func TestHaveHardlinkCreateAndIdempotent(t *testing.T) { t.Fatal(err) } - if err := Have(link, Hardlink(target)); err != nil { - t.Fatalf("create: %v", err) - } + Have(link, IsHardlink(target)) ti, err := os.Stat(target) if err != nil { @@ -373,9 +353,7 @@ func TestHaveHardlinkMovesRealFileAside(t *testing.T) { t.Fatal(err) } - if err := Have(link, Hardlink(target)); err != nil { - t.Fatalf("hardlink over real file: %v", err) - } + Have(link, IsHardlink(target)) ti, err := os.Stat(target) if err != nil { @@ -396,7 +374,7 @@ func TestHaveHardlinkMovesRealFileAside(t *testing.T) { func TestHaveHardlinkMissingTarget(t *testing.T) { dir := t.TempDir() link := filepath.Join(dir, "link") - if err := Have(link, Hardlink(filepath.Join(dir, "nope"))); err == nil { + if _, err := have(link, IsHardlink(filepath.Join(dir, "nope"))); err == nil { t.Error("expected error when hardlink target does not exist") } } @@ -408,7 +386,7 @@ func TestHaveAbsentNonEmptyDirWithoutPruneFails(t *testing.T) { t.Fatal(err) } - if err := Have(target, IsAbsent()); err == nil { + if _, err := have(target, IsAbsent()); err == nil { t.Error("expected error removing a non-empty directory without PruneDirectory()") } if _, err := os.Stat(target); err != nil { @@ -426,9 +404,7 @@ func TestHaveAbsentPruneDirectoryRecursive(t *testing.T) { t.Fatal(err) } - if err := Have(target, IsAbsent(), PruneDirectory()); err != nil { - t.Fatalf("prune remove: %v", err) - } + Have(target, IsAbsent(), PruneDirectory()) if _, err := os.Stat(target); !os.IsNotExist(err) { t.Errorf("expected %s to be removed recursively", target) } |
