summaryrefslogtreecommitdiff
path: root/internal/resource/opt/opt.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/resource/opt/opt.go')
-rw-r--r--internal/resource/opt/opt.go156
1 files changed, 156 insertions, 0 deletions
diff --git a/internal/resource/opt/opt.go b/internal/resource/opt/opt.go
new file mode 100644
index 0000000..23f076d
--- /dev/null
+++ b/internal/resource/opt/opt.go
@@ -0,0 +1,156 @@
+// Package opt provides interface-based, resource-agnostic configuration
+// options shared by the file, dir, and link resource packages.
+//
+// It is designed to be dot-imported at call sites so options read as bare
+// WithMode(...) / WithOwner(...) calls regardless of the resource type:
+//
+// import (
+// "codeberg.org/snonux/gonf/internal/resource/file"
+// . "codeberg.org/snonux/gonf/internal/resource/opt"
+// )
+//
+// file.Have("file.txt", WithOwner("paul"), WithMode(0o755))
+//
+// Each option targets a small capability interface (Owner, Moded, ...). A
+// resource implements only the setters it supports. Applying an option to a
+// resource that lacks the matching interface (e.g. WithPrune on a file) is a
+// programming error in the resource declaration and aborts the program via
+// log.Fatalf.
+package opt
+
+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)
+ }
+}