aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/system/mkdir.go
diff options
context:
space:
mode:
authorOphestra Umiker <cat@ophivana.moe>2024-10-16 01:31:23 +0900
committerOphestra Umiker <cat@ophivana.moe>2024-10-16 01:31:23 +0900
commit430f1a5b4e4e2b164297391390e3a0cbe2ad2eb2 (patch)
tree76aab87e648c6e8fd6c8afc3d314bc73563ee552 /internal/system/mkdir.go
parent0fd63e85e730d44abd488c892be377b332f5458e (diff)
system: isolate app/system into generic implementation
This improves maintainability and extensibility of system operations, makes writing tests for them possible, and operations now apply and revert in order, instead of being bunched up into their own categories. Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
Diffstat (limited to 'internal/system/mkdir.go')
-rw-r--r--internal/system/mkdir.go82
1 files changed, 82 insertions, 0 deletions
diff --git a/internal/system/mkdir.go b/internal/system/mkdir.go
new file mode 100644
index 00000000..2c303630
--- /dev/null
+++ b/internal/system/mkdir.go
@@ -0,0 +1,82 @@
+package system
+
+import (
+ "errors"
+ "fmt"
+ "os"
+
+ "git.ophivana.moe/cat/fortify/internal/fmsg"
+ "git.ophivana.moe/cat/fortify/internal/state"
+ "git.ophivana.moe/cat/fortify/internal/verbose"
+)
+
+// Ensure the existence and mode of a directory.
+func (sys *I) Ensure(name string, perm os.FileMode) {
+ sys.lock.Lock()
+ defer sys.lock.Unlock()
+
+ sys.ops = append(sys.ops, &Mkdir{User, name, perm, false})
+}
+
+// Ephemeral ensures the temporary existence and mode of a directory through the life of et.
+func (sys *I) Ephemeral(et state.Enablement, name string, perm os.FileMode) {
+ sys.lock.Lock()
+ defer sys.lock.Unlock()
+
+ sys.ops = append(sys.ops, &Mkdir{et, name, perm, true})
+}
+
+type Mkdir struct {
+ et state.Enablement
+ path string
+ perm os.FileMode
+ ephemeral bool
+}
+
+func (m *Mkdir) Type() state.Enablement {
+ return m.et
+}
+
+func (m *Mkdir) apply(_ *I) error {
+ verbose.Println("ensuring directory", m)
+
+ // create directory
+ err := os.Mkdir(m.path, m.perm)
+ if !errors.Is(err, os.ErrExist) {
+ return fmsg.WrapErrorSuffix(err,
+ fmt.Sprintf("cannot create directory %q:", m.path))
+ }
+
+ // directory exists, ensure mode
+ return fmsg.WrapErrorSuffix(os.Chmod(m.path, m.perm),
+ fmt.Sprintf("cannot change mode of %q to %s:", m.path, m.perm))
+}
+
+func (m *Mkdir) revert(_ *I, ec *Criteria) error {
+ if !m.ephemeral {
+ // skip non-ephemeral dir and do not log anything
+ return nil
+ }
+
+ if ec.hasType(m) {
+ verbose.Println("destroying ephemeral directory", m)
+ return fmsg.WrapErrorSuffix(os.Remove(m.path),
+ fmt.Sprintf("cannot remove ephemeral directory %q:", m.path))
+ } else {
+ verbose.Println("skipping ephemeral directory", m)
+ return nil
+ }
+}
+
+func (m *Mkdir) Is(o Op) bool {
+ m0, ok := o.(*Mkdir)
+ return ok && m0 != nil && *m == *m0
+}
+
+func (m *Mkdir) Path() string {
+ return m.path
+}
+
+func (m *Mkdir) String() string {
+ return fmt.Sprintf("mode: %s path: %q", m.perm.String(), m.path)
+}