summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulien Dessaux2024-03-12 23:23:10 +0100
committerJulien Dessaux2024-03-12 23:23:10 +0100
commit93b22a886a12cde2886616298446fcc3eee1bd4d (patch)
treee5147ae2968abb7922a4885332f9e8c9601271d5
parentchore(variables): support integer interpolation for all values (diff)
downloadgonf-93b22a886a12cde2886616298446fcc3eee1bd4d.tar.gz
gonf-93b22a886a12cde2886616298446fcc3eee1bd4d.tar.bz2
gonf-93b22a886a12cde2886616298446fcc3eee1bd4d.zip
feat(files): support creating intermediate directories
-rw-r--r--pkg/files.go37
-rw-r--r--pkg/utils.go26
-rw-r--r--stdlib/os/debian/apt.go13
3 files changed, 62 insertions, 14 deletions
diff --git a/pkg/files.go b/pkg/files.go
index 35420d4..379b437 100644
--- a/pkg/files.go
+++ b/pkg/files.go
@@ -8,6 +8,7 @@ import (
"io/fs"
"log/slog"
"os"
+ "path/filepath"
)
// ----- Globals ---------------------------------------------------------------
@@ -20,22 +21,24 @@ func init() {
// ----- Public ----------------------------------------------------------------
type FilePromise struct {
- chain []Promise
- contents Value
- err error
- filename Value
- permissions *Permissions
- status Status
+ chain []Promise
+ contents Value
+ dirPermissions *Permissions
+ err error
+ filename Value
+ permissions *Permissions
+ status Status
}
func File(filename any) *FilePromise {
return &FilePromise{
- chain: nil,
- contents: nil,
- err: nil,
- filename: interfaceToTemplateValue(filename),
- permissions: nil,
- status: PROMISED,
+ chain: nil,
+ contents: nil,
+ dirPermissions: nil,
+ err: nil,
+ filename: interfaceToTemplateValue(filename),
+ permissions: nil,
+ status: PROMISED,
}
}
@@ -44,6 +47,11 @@ func (f *FilePromise) Contents(contents any) *FilePromise {
return f
}
+func (f *FilePromise) DirectoriesPermissions(p *Permissions) *FilePromise {
+ f.dirPermissions = p
+ return f
+}
+
func (f *FilePromise) Permissions(p *Permissions) *FilePromise {
f.permissions = p
return f
@@ -67,6 +75,11 @@ func (f *FilePromise) Promise() Promise {
func (f *FilePromise) Resolve() {
filename := f.filename.String()
+ if f.dirPermissions != nil {
+ if f.status, f.err = makeDirectoriesHierarchy(filepath.Dir(filename), f.dirPermissions); f.err != nil {
+ return
+ }
+ }
if f.contents != nil {
var sumFile []byte
sumFile, f.err = sha256sumOfFile(filename)
diff --git a/pkg/utils.go b/pkg/utils.go
index f62d1c3..c3301f2 100644
--- a/pkg/utils.go
+++ b/pkg/utils.go
@@ -2,6 +2,10 @@ package gonf
import (
"crypto/sha256"
+ "errors"
+ "io/fs"
+ "os"
+ "path/filepath"
)
var builtinTemplateFunctions = map[string]any{
@@ -20,6 +24,28 @@ func FilterSlice[T any](slice *[]T, predicate func(T) bool) {
*slice = (*slice)[:i] // or truncated out of the slice
}
+// We cannot just use os.MakedirAll because we need to set the user:group on every intermediate directories created
+func makeDirectoriesHierarchy(dir string, perms *Permissions) (Status, error) {
+ if _, err := os.Lstat(dir); err != nil {
+ if errors.Is(err, fs.ErrNotExist) {
+ if status, err := makeDirectoriesHierarchy(filepath.Dir(dir), perms); err != nil {
+ return status, err
+ }
+ m, err := perms.mode.Int()
+ if err != nil {
+ return BROKEN, err
+ }
+ os.Mkdir(dir, fs.FileMode(m))
+ perms.resolve(dir)
+ return REPAIRED, nil
+ } else {
+ return BROKEN, err
+ }
+ } else {
+ return KEPT, nil
+ }
+}
+
func sha256sum(contents []byte) []byte {
h := sha256.New()
h.Write(contents)
diff --git a/stdlib/os/debian/apt.go b/stdlib/os/debian/apt.go
index 5ece696..aad8b65 100644
--- a/stdlib/os/debian/apt.go
+++ b/stdlib/os/debian/apt.go
@@ -26,12 +26,21 @@ var apt_norecommends []byte
var sources_list []byte
func Promise() {
+ rootDir := gonf.ModeUserGroup(0755, "root", "root")
rootRO := gonf.ModeUserGroup(0444, "root", "root")
gonf.Default("debian-release", "stable")
gonf.AppendVariable("debian-extra-sources", "# Extra sources")
apt_update := gonf.Command("apt-get", "update", "-qq")
- gonf.File("/etc/apt/sources.list").Permissions(rootRO).Template(sources_list).Promise().IfRepaired(apt_update)
- gonf.File("/etc/apt/apt.conf.d/99_norecommends").Permissions(rootRO).Template(apt_norecommends).Promise()
+ gonf.File("/etc/apt/sources.list").
+ Permissions(rootRO).
+ Template(sources_list).
+ Promise().
+ IfRepaired(apt_update)
+ gonf.File("/etc/apt/apt.conf.d/99_norecommends").
+ DirectoriesPermissions(rootDir).
+ Permissions(rootRO).
+ Template(apt_norecommends).
+ Promise()
gonf.SetPackagesConfiguration(packages_install, packages_list, apt_update)
gonf.Service("opensmtpd").State("enabled", "started").Promise()
systemd.Promise()