aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-08-10 03:10:13 +0900
committerOphestra <cat@gensokyo.uk>2025-08-10 03:11:10 +0900
commit41ac2be9658b49c68cb793f3a6f0c5932d82e1c2 (patch)
treea079415bb5964f5962dfed7d2486e7977bdfe7ca
parent02271583fb791987a9406c9ba282c75ff7a0e395 (diff)
container/absolute: wrap safe stdlib functions
These functions do not change the absoluteness of a pathname. Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--container/absolute.go30
-rw-r--r--container/absolute_test.go40
-rw-r--r--ldd/exec.go2
-rw-r--r--system/dbus/proc.go4
4 files changed, 64 insertions, 12 deletions
diff --git a/container/absolute.go b/container/absolute.go
index cafb1804..8f1fa23b 100644
--- a/container/absolute.go
+++ b/container/absolute.go
@@ -5,10 +5,12 @@ import (
"errors"
"fmt"
"path"
+ "slices"
+ "strings"
"syscall"
)
-// AbsoluteError is returned by [NewAbsolute] and holds the invalid pathname.
+// AbsoluteError is returned by [NewAbs] and holds the invalid pathname.
type AbsoluteError struct {
Pathname string
}
@@ -37,23 +39,31 @@ func (a *Absolute) String() string {
return a.pathname
}
-// NewAbsolute checks pathname and returns a new [Absolute] if pathname is absolute.
-func NewAbsolute(pathname string) (*Absolute, error) {
+// NewAbs checks pathname and returns a new [Absolute] if pathname is absolute.
+func NewAbs(pathname string) (*Absolute, error) {
if !isAbs(pathname) {
return nil, &AbsoluteError{pathname}
}
return &Absolute{pathname}, nil
}
-// MustAbs calls [NewAbsolute] and panics on error.
+// MustAbs calls [NewAbs] and panics on error.
func MustAbs(pathname string) *Absolute {
- if a, err := NewAbsolute(pathname); err != nil {
+ if a, err := NewAbs(pathname); err != nil {
panic(err.Error())
} else {
return a
}
}
+// Append calls [path.Join] with [Absolute] as the first element.
+func (a *Absolute) Append(elem ...string) *Absolute {
+ return &Absolute{path.Join(append([]string{a.String()}, elem...)...)}
+}
+
+// Dir calls [path.Dir] with [Absolute] as its argument.
+func (a *Absolute) Dir() *Absolute { return &Absolute{path.Dir(a.String())} }
+
func (a *Absolute) GobEncode() ([]byte, error) { return []byte(a.String()), nil }
func (a *Absolute) GobDecode(data []byte) error {
pathname := string(data)
@@ -76,3 +86,13 @@ func (a *Absolute) UnmarshalJSON(data []byte) error {
a.pathname = pathname
return nil
}
+
+// SortAbs calls [slices.SortFunc] for a slice of [Absolute].
+func SortAbs(x []*Absolute) {
+ slices.SortFunc(x, func(a, b *Absolute) int { return strings.Compare(a.String(), b.String()) })
+}
+
+// CompactAbs calls [slices.CompactFunc] for a slice of [Absolute].
+func CompactAbs(s []*Absolute) []*Absolute {
+ return slices.CompactFunc(s, func(a *Absolute, b *Absolute) bool { return a.String() == b.String() })
+}
diff --git a/container/absolute_test.go b/container/absolute_test.go
index 2889d820..014ace81 100644
--- a/container/absolute_test.go
+++ b/container/absolute_test.go
@@ -39,7 +39,7 @@ func TestAbsoluteError(t *testing.T) {
})
}
-func TestNewAbsolute(t *testing.T) {
+func TestNewAbs(t *testing.T) {
testCases := []struct {
name string
@@ -54,12 +54,12 @@ func TestNewAbsolute(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
- got, err := NewAbsolute(tc.pathname)
+ got, err := NewAbs(tc.pathname)
if !reflect.DeepEqual(got, tc.want) {
- t.Errorf("NewAbsolute: %#v, want %#v", got, tc.want)
+ t.Errorf("NewAbs: %#v, want %#v", got, tc.want)
}
if !errors.Is(err, tc.wantErr) {
- t.Errorf("NewAbsolute: error = %v, want %v", err, tc.wantErr)
+ t.Errorf("NewAbs: error = %v, want %v", err, tc.wantErr)
}
})
}
@@ -282,3 +282,35 @@ func TestCodecAbsolute(t *testing.T) {
}
})
}
+
+func TestAbsoluteWrap(t *testing.T) {
+ t.Run("join", func(t *testing.T) {
+ want := "/etc/nix/nix.conf"
+ if got := MustAbs("/etc").Append("nix", "nix.conf"); got.String() != want {
+ t.Errorf("Append: %q, want %q", got, want)
+ }
+ })
+
+ t.Run("dir", func(t *testing.T) {
+ want := "/"
+ if got := MustAbs("/etc").Dir(); got.String() != want {
+ t.Errorf("Dir: %q, want %q", got, want)
+ }
+ })
+
+ t.Run("sort", func(t *testing.T) {
+ want := []*Absolute{MustAbs("/etc"), MustAbs("/proc"), MustAbs("/sys")}
+ got := []*Absolute{MustAbs("/proc"), MustAbs("/sys"), MustAbs("/etc")}
+ SortAbs(got)
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("SortAbs: %#v, want %#v", got, want)
+ }
+ })
+
+ t.Run("compact", func(t *testing.T) {
+ want := []*Absolute{MustAbs("/etc"), MustAbs("/proc"), MustAbs("/sys")}
+ if got := CompactAbs([]*Absolute{MustAbs("/etc"), MustAbs("/proc"), MustAbs("/proc"), MustAbs("/sys")}); !reflect.DeepEqual(got, want) {
+ t.Errorf("CompactAbs: %#v, want %#v", got, want)
+ }
+ })
+}
diff --git a/ldd/exec.go b/ldd/exec.go
index ac311fa2..cb0fec75 100644
--- a/ldd/exec.go
+++ b/ldd/exec.go
@@ -29,7 +29,7 @@ func Exec(ctx context.Context, p string) ([]*Entry, error) {
var toolPath *container.Absolute
if s, err := exec.LookPath(lddName); err != nil {
return nil, err
- } else if toolPath, err = container.NewAbsolute(s); err != nil {
+ } else if toolPath, err = container.NewAbs(s); err != nil {
return nil, err
}
diff --git a/system/dbus/proc.go b/system/dbus/proc.go
index ee298096..d6f98907 100644
--- a/system/dbus/proc.go
+++ b/system/dbus/proc.go
@@ -43,10 +43,10 @@ func (p *Proxy) Start() error {
}, nil)
} else {
var toolPath *container.Absolute
- if a, err := container.NewAbsolute(p.name); err != nil {
+ if a, err := container.NewAbs(p.name); err != nil {
if p.name, err = exec.LookPath(p.name); err != nil {
return err
- } else if toolPath, err = container.NewAbsolute(p.name); err != nil {
+ } else if toolPath, err = container.NewAbs(p.name); err != nil {
return err
}
} else {