summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Magefile.go5
-rw-r--r--examples/examples.go37
-rw-r--r--internal/file/file.go41
-rw-r--r--internal/file/file_test.go54
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)
}