container/check: move absolute pathname
All checks were successful
Test / Create distribution (push) Successful in 34s
Test / Hpkg (push) Successful in 4m3s
Test / Sandbox (race detector) (push) Successful in 4m26s
Test / Hakurei (race detector) (push) Successful in 5m19s
Test / Sandbox (push) Successful in 1m28s
Test / Hakurei (push) Successful in 2m16s
Test / Flake checks (push) Successful in 1m37s
All checks were successful
Test / Create distribution (push) Successful in 34s
Test / Hpkg (push) Successful in 4m3s
Test / Sandbox (race detector) (push) Successful in 4m26s
Test / Hakurei (race detector) (push) Successful in 5m19s
Test / Sandbox (push) Successful in 1m28s
Test / Hakurei (push) Successful in 2m16s
Test / Flake checks (push) Successful in 1m37s
This allows use of absolute pathname values without importing container. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
104
container/check/absolute.go
Normal file
104
container/check/absolute.go
Normal file
@@ -0,0 +1,104 @@
|
||||
// Package check provides types yielding values checked to meet a condition.
|
||||
package check
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"slices"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// AbsoluteError is returned by [NewAbs] and holds the invalid pathname.
|
||||
type AbsoluteError struct{ Pathname string }
|
||||
|
||||
func (e *AbsoluteError) Error() string { return fmt.Sprintf("path %q is not absolute", e.Pathname) }
|
||||
func (e *AbsoluteError) Is(target error) bool {
|
||||
var ce *AbsoluteError
|
||||
if !errors.As(target, &ce) {
|
||||
return errors.Is(target, syscall.EINVAL)
|
||||
}
|
||||
return *e == *ce
|
||||
}
|
||||
|
||||
// Absolute holds a pathname checked to be absolute.
|
||||
type Absolute struct{ pathname string }
|
||||
|
||||
// unsafeAbs returns [check.Absolute] on any string value.
|
||||
func unsafeAbs(pathname string) *Absolute { return &Absolute{pathname} }
|
||||
|
||||
func (a *Absolute) String() string {
|
||||
if a.pathname == "" {
|
||||
panic("attempted use of zero Absolute")
|
||||
}
|
||||
return a.pathname
|
||||
}
|
||||
|
||||
func (a *Absolute) Is(v *Absolute) bool {
|
||||
if a == nil && v == nil {
|
||||
return true
|
||||
}
|
||||
return a != nil && v != nil &&
|
||||
a.pathname != "" && v.pathname != "" &&
|
||||
a.pathname == v.pathname
|
||||
}
|
||||
|
||||
// NewAbs checks pathname and returns a new [Absolute] if pathname is absolute.
|
||||
func NewAbs(pathname string) (*Absolute, error) {
|
||||
if !path.IsAbs(pathname) {
|
||||
return nil, &AbsoluteError{pathname}
|
||||
}
|
||||
return unsafeAbs(pathname), nil
|
||||
}
|
||||
|
||||
// MustAbs calls [NewAbs] and panics on error.
|
||||
func MustAbs(pathname string) *Absolute {
|
||||
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 unsafeAbs(path.Join(append([]string{a.String()}, elem...)...))
|
||||
}
|
||||
|
||||
// Dir calls [path.Dir] with [Absolute] as its argument.
|
||||
func (a *Absolute) Dir() *Absolute { return unsafeAbs(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)
|
||||
if !path.IsAbs(pathname) {
|
||||
return &AbsoluteError{pathname}
|
||||
}
|
||||
a.pathname = pathname
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Absolute) MarshalJSON() ([]byte, error) { return json.Marshal(a.String()) }
|
||||
func (a *Absolute) UnmarshalJSON(data []byte) error {
|
||||
var pathname string
|
||||
if err := json.Unmarshal(data, &pathname); err != nil {
|
||||
return err
|
||||
}
|
||||
if !path.IsAbs(pathname) {
|
||||
return &AbsoluteError{pathname}
|
||||
}
|
||||
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() })
|
||||
}
|
||||
Reference in New Issue
Block a user