From 5600bedb927e291e2e78e6140de256e1a1d4475c Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Mon, 6 Jul 2026 23:05:48 +0300 Subject: refactor --- api/api.go | 15 ++-- api/option/option.go | 140 ------------------------------------ api/options/option.go | 140 ++++++++++++++++++++++++++++++++++++ api/resource.go | 17 +++++ examples/examples.go | 5 +- internal/resource/dir/dir.go | 2 +- internal/resource/dir/dir_test.go | 2 +- internal/resource/dir/source.go | 2 +- internal/resource/file/file.go | 2 +- internal/resource/file/file_test.go | 2 +- internal/resource/link/link.go | 2 +- internal/resource/link/link_test.go | 2 +- 12 files changed, 173 insertions(+), 158 deletions(-) delete mode 100644 api/option/option.go create mode 100644 api/options/option.go create mode 100644 api/resource.go diff --git a/api/api.go b/api/api.go index f4ec70e..ea30363 100644 --- a/api/api.go +++ b/api/api.go @@ -1,39 +1,38 @@ package api import ( - "codeberg.org/snonux/gonf/api/option" - "codeberg.org/snonux/gonf/internal/resource" + "codeberg.org/snonux/gonf/api/options" "codeberg.org/snonux/gonf/internal/resource/dir" "codeberg.org/snonux/gonf/internal/resource/file" "codeberg.org/snonux/gonf/internal/resource/link" ) // File creates a file resource. -func File(path string, opts ...option.Option) resource.Resource { +func File(path string, opts ...options.Option) Resource { return file.Present(path, opts...) } // NoFile creates a file resource that is ensured to be absent. -func NoFile(path string, opts ...option.Option) resource.Resource { +func NoFile(path string, opts ...options.Option) Resource { return file.Absent(path, opts...) } // Dir creates a directory resource. -func Dir(path string, opts ...option.Option) resource.Resource { +func Dir(path string, opts ...options.Option) Resource { return dir.Present(path, opts...) } // NoDir creates a directory resource that is ensured to be absent. -func NoDir(path string, opts ...option.Option) resource.Resource { +func NoDir(path string, opts ...options.Option) Resource { return dir.Absent(path, opts...) } // Link creates a link resource (symbolic or hard). -func Link(path string, opts ...option.Option) resource.Resource { +func Link(path string, opts ...options.Option) Resource { return link.Present(path, opts...) } // NoLink creates a link resource that is ensured to be absent. -func NoLink(path string, opts ...option.Option) resource.Resource { +func NoLink(path string, opts ...options.Option) Resource { return link.Absent(path, opts...) } diff --git a/api/option/option.go b/api/option/option.go deleted file mode 100644 index b5d2531..0000000 --- a/api/option/option.go +++ /dev/null @@ -1,140 +0,0 @@ -// Package option provides interface-based, resource-agnostic configuration -// options shared by the file, dir, and link resource packages. -package option - -import ( - "log" - "os" -) - -// Option configures a resource. It is applied to the concrete resource value -// (e.g. *file.File) during construction. -type Option func(any) - -// Capability interfaces. A resource implements only the setters it supports. -type ( - Owner interface{ SetOwner(string) } - Grouped interface{ SetGroup(string) } - Moded interface{ SetMode(os.FileMode) } - Sourced interface{ SetSource(string) } - Contented interface{ SetContent(string) } - FileModed interface{ SetFileMode(os.FileMode) } - Prunable interface{ SetPrune() } - Absentable interface{ SetAbsent() } - Linkable interface { - SetSymlink(target string) - SetHardlink(target string) - } -) - -// WithOwner sets the owning user of the resource. -func WithOwner(owner string) Option { - return func(t any) { - r, ok := t.(Owner) - if !ok { - log.Fatalf("%T does not support WithOwner", t) - } - r.SetOwner(owner) - } -} - -// WithGroup sets the owning group of the resource. -func WithGroup(group string) Option { - return func(t any) { - r, ok := t.(Grouped) - if !ok { - log.Fatalf("%T does not support WithGroup", t) - } - r.SetGroup(group) - } -} - -// WithMode sets the resource's own file mode. -func WithMode(mode os.FileMode) Option { - return func(t any) { - r, ok := t.(Moded) - if !ok { - log.Fatalf("%T does not support WithMode", t) - } - r.SetMode(mode) - } -} - -// WithSource sets the source path the resource is populated from. -func WithSource(source string) Option { - return func(t any) { - r, ok := t.(Sourced) - if !ok { - log.Fatalf("%T does not support WithSource", t) - } - r.SetSource(source) - } -} - -// WithContent sets literal content for the resource. -func WithContent(content string) Option { - return func(t any) { - r, ok := t.(Contented) - if !ok { - log.Fatalf("%T does not support WithContent", t) - } - r.SetContent(content) - } -} - -// WithFileMode sets the mode applied to regular files copied from a source -// tree (distinct from the resource's own mode). -func WithFileMode(mode os.FileMode) Option { - return func(t any) { - r, ok := t.(FileModed) - if !ok { - log.Fatalf("%T does not support WithFileMode", t) - } - r.SetFileMode(mode) - } -} - -// WithPrune enables reconciliation of extra destination entries during a -// source copy, and recursive removal during IsAbsent(). -func WithPrune() Option { - return func(t any) { - r, ok := t.(Prunable) - if !ok { - log.Fatalf("%T does not support WithPrune", t) - } - r.SetPrune() - } -} - -// IsAbsent marks the resource for removal. -func IsAbsent() Option { - return func(t any) { - r, ok := t.(Absentable) - if !ok { - log.Fatalf("%T does not support IsAbsent", t) - } - r.SetAbsent() - } -} - -// WithSymlink makes the resource a symbolic link pointing at target. -func WithSymlink(target string) Option { - return func(t any) { - r, ok := t.(Linkable) - if !ok { - log.Fatalf("%T does not support WithSymlink", t) - } - r.SetSymlink(target) - } -} - -// WithHardlink makes the resource a hard link pointing at target. -func WithHardlink(target string) Option { - return func(t any) { - r, ok := t.(Linkable) - if !ok { - log.Fatalf("%T does not support WithHardlink", t) - } - r.SetHardlink(target) - } -} diff --git a/api/options/option.go b/api/options/option.go new file mode 100644 index 0000000..1c757c4 --- /dev/null +++ b/api/options/option.go @@ -0,0 +1,140 @@ +// Package option provides interface-based, resource-agnostic configuration +// options shared by the file, dir, and link resource packages. +package options + +import ( + "log" + "os" +) + +// Option configures a resource. It is applied to the concrete resource value +// (e.g. *file.File) during construction. +type Option func(any) + +// Capability interfaces. A resource implements only the setters it supports. +type ( + Owner interface{ SetOwner(string) } + Grouped interface{ SetGroup(string) } + Moded interface{ SetMode(os.FileMode) } + Sourced interface{ SetSource(string) } + Contented interface{ SetContent(string) } + FileModed interface{ SetFileMode(os.FileMode) } + Prunable interface{ SetPrune() } + Absentable interface{ SetAbsent() } + Linkable interface { + SetSymlink(target string) + SetHardlink(target string) + } +) + +// WithOwner sets the owning user of the resource. +func WithOwner(owner string) Option { + return func(t any) { + r, ok := t.(Owner) + if !ok { + log.Fatalf("%T does not support WithOwner", t) + } + r.SetOwner(owner) + } +} + +// WithGroup sets the owning group of the resource. +func WithGroup(group string) Option { + return func(t any) { + r, ok := t.(Grouped) + if !ok { + log.Fatalf("%T does not support WithGroup", t) + } + r.SetGroup(group) + } +} + +// WithMode sets the resource's own file mode. +func WithMode(mode os.FileMode) Option { + return func(t any) { + r, ok := t.(Moded) + if !ok { + log.Fatalf("%T does not support WithMode", t) + } + r.SetMode(mode) + } +} + +// WithSource sets the source path the resource is populated from. +func WithSource(source string) Option { + return func(t any) { + r, ok := t.(Sourced) + if !ok { + log.Fatalf("%T does not support WithSource", t) + } + r.SetSource(source) + } +} + +// WithContent sets literal content for the resource. +func WithContent(content string) Option { + return func(t any) { + r, ok := t.(Contented) + if !ok { + log.Fatalf("%T does not support WithContent", t) + } + r.SetContent(content) + } +} + +// WithFileMode sets the mode applied to regular files copied from a source +// tree (distinct from the resource's own mode). +func WithFileMode(mode os.FileMode) Option { + return func(t any) { + r, ok := t.(FileModed) + if !ok { + log.Fatalf("%T does not support WithFileMode", t) + } + r.SetFileMode(mode) + } +} + +// WithPrune enables reconciliation of extra destination entries during a +// source copy, and recursive removal during IsAbsent(). +func WithPrune() Option { + return func(t any) { + r, ok := t.(Prunable) + if !ok { + log.Fatalf("%T does not support WithPrune", t) + } + r.SetPrune() + } +} + +// IsAbsent marks the resource for removal. +func IsAbsent() Option { + return func(t any) { + r, ok := t.(Absentable) + if !ok { + log.Fatalf("%T does not support IsAbsent", t) + } + r.SetAbsent() + } +} + +// WithSymlink makes the resource a symbolic link pointing at target. +func WithSymlink(target string) Option { + return func(t any) { + r, ok := t.(Linkable) + if !ok { + log.Fatalf("%T does not support WithSymlink", t) + } + r.SetSymlink(target) + } +} + +// WithHardlink makes the resource a hard link pointing at target. +func WithHardlink(target string) Option { + return func(t any) { + r, ok := t.(Linkable) + if !ok { + log.Fatalf("%T does not support WithHardlink", t) + } + r.SetHardlink(target) + } +} diff --git a/api/resource.go b/api/resource.go new file mode 100644 index 0000000..e254e1b --- /dev/null +++ b/api/resource.go @@ -0,0 +1,17 @@ +package api + +import ( + internal "codeberg.org/snonux/gonf/internal/resource" +) + +// Resource represents a system resource managed by gonfs. +// It is an interface to hide the internal implementation details +// of the resource registry. +type Resource interface { + ID() string + String() string +} + +func Apply() error { + return internal.Apply() +} diff --git a/examples/examples.go b/examples/examples.go index 1a1df0b..2168a40 100644 --- a/examples/examples.go +++ b/examples/examples.go @@ -4,8 +4,7 @@ import ( "os" . "codeberg.org/snonux/gonf/api" - . "codeberg.org/snonux/gonf/api/option" - "codeberg.org/snonux/gonf/internal/resource" + . "codeberg.org/snonux/gonf/api/options" ) func Run() error { @@ -68,5 +67,5 @@ func Run() error { _ = os.Link("/tmp/gonf_hello.txt", "/tmp/gonf_stale_hardlink") Link("/tmp/gonf_stale_hardlink", IsAbsent()) - return resource.Apply() + return Apply() } diff --git a/internal/resource/dir/dir.go b/internal/resource/dir/dir.go index 283cea9..94220b7 100644 --- a/internal/resource/dir/dir.go +++ b/internal/resource/dir/dir.go @@ -7,7 +7,7 @@ import ( "os/user" "strconv" - opt "codeberg.org/snonux/gonf/api/option" + opt "codeberg.org/snonux/gonf/api/options" "codeberg.org/snonux/gonf/internal/resource" ) diff --git a/internal/resource/dir/dir_test.go b/internal/resource/dir/dir_test.go index eb22268..c7ec92e 100644 --- a/internal/resource/dir/dir_test.go +++ b/internal/resource/dir/dir_test.go @@ -6,7 +6,7 @@ import ( "testing" "codeberg.org/snonux/gonf/internal/resource" - . "codeberg.org/snonux/gonf/api/option" + . "codeberg.org/snonux/gonf/api/options" ) func TestPresentDirectoryCreate(t *testing.T) { diff --git a/internal/resource/dir/source.go b/internal/resource/dir/source.go index b94756d..1539590 100644 --- a/internal/resource/dir/source.go +++ b/internal/resource/dir/source.go @@ -9,7 +9,7 @@ import ( "codeberg.org/snonux/gonf/internal/resource/file" "codeberg.org/snonux/gonf/internal/resource/link" - opt "codeberg.org/snonux/gonf/api/option" + opt "codeberg.org/snonux/gonf/api/options" ) // copySourceTree mirrors d.source into d.path, dispatching each entry by diff --git a/internal/resource/file/file.go b/internal/resource/file/file.go index 9879e27..9d8a0d9 100644 --- a/internal/resource/file/file.go +++ b/internal/resource/file/file.go @@ -10,7 +10,7 @@ import ( "strings" "text/template" - opt "codeberg.org/snonux/gonf/api/option" + opt "codeberg.org/snonux/gonf/api/options" "codeberg.org/snonux/gonf/internal/resource" ) diff --git a/internal/resource/file/file_test.go b/internal/resource/file/file_test.go index 7f9fedd..b158657 100644 --- a/internal/resource/file/file_test.go +++ b/internal/resource/file/file_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - . "codeberg.org/snonux/gonf/api/option" + . "codeberg.org/snonux/gonf/api/options" "codeberg.org/snonux/gonf/internal/resource" ) diff --git a/internal/resource/link/link.go b/internal/resource/link/link.go index 2bd8c66..a5c5122 100644 --- a/internal/resource/link/link.go +++ b/internal/resource/link/link.go @@ -5,7 +5,7 @@ import ( "log" "os" - opt "codeberg.org/snonux/gonf/api/option" + opt "codeberg.org/snonux/gonf/api/options" "codeberg.org/snonux/gonf/internal/resource" ) diff --git a/internal/resource/link/link_test.go b/internal/resource/link/link_test.go index 3012435..862d5f7 100644 --- a/internal/resource/link/link_test.go +++ b/internal/resource/link/link_test.go @@ -6,7 +6,7 @@ import ( "testing" "codeberg.org/snonux/gonf/internal/resource" - . "codeberg.org/snonux/gonf/api/option" + . "codeberg.org/snonux/gonf/api/options" ) func TestPresentSymlinkCreateAndIdempotent(t *testing.T) { -- cgit v1.2.3