system: unexport Op implementations
All checks were successful
Test / Create distribution (push) Successful in 52s
Test / Sandbox (push) Successful in 3m30s
Test / Hakurei (push) Successful in 5m40s
Test / Sandbox (race detector) (push) Successful in 6m30s
Test / Hpkg (push) Successful in 7m21s
Test / Hakurei (race detector) (push) Successful in 3m22s
Test / Flake checks (push) Successful in 2m2s

None of these are valid with their zero value, and the implementations assume they are created by the builder methods. They are by all means an implementation detail and exporting them makes no sense.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
Ophestra 2025-09-06 16:16:03 +09:00
parent ac81cfbedc
commit e68db7fbfc
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
12 changed files with 157 additions and 157 deletions

View File

@ -9,33 +9,33 @@ import (
"hakurei.app/system/acl"
)
// UpdatePerm appends [ACLUpdateOp] to [I] with the [Process] criteria.
// UpdatePerm calls UpdatePermType with the [Process] criteria.
func (sys *I) UpdatePerm(path string, perms ...acl.Perm) *I {
sys.UpdatePermType(Process, path, perms...)
return sys
}
// UpdatePermType appends [ACLUpdateOp] to [I].
// UpdatePermType maintains [acl.Perms] on a file until its [Enablement] is no longer satisfied.
func (sys *I) UpdatePermType(et Enablement, path string, perms ...acl.Perm) *I {
sys.ops = append(sys.ops, &ACLUpdateOp{et, path, perms})
sys.ops = append(sys.ops, &aclUpdateOp{et, path, perms})
return sys
}
// ACLUpdateOp maintains [acl.Perms] on a file until its [Enablement] is no longer satisfied.
type ACLUpdateOp struct {
// aclUpdateOp implements [I.UpdatePermType].
type aclUpdateOp struct {
et Enablement
path string
perms acl.Perms
}
func (a *ACLUpdateOp) Type() Enablement { return a.et }
func (a *aclUpdateOp) Type() Enablement { return a.et }
func (a *ACLUpdateOp) apply(sys *I) error {
func (a *aclUpdateOp) apply(sys *I) error {
sys.verbose("applying ACL", a)
return newOpError("acl", sys.aclUpdate(a.path, sys.uid, a.perms...), false)
}
func (a *ACLUpdateOp) revert(sys *I, ec *Criteria) error {
func (a *aclUpdateOp) revert(sys *I, ec *Criteria) error {
if ec.hasType(a.Type()) {
sys.verbose("stripping ACL", a)
err := sys.aclUpdate(a.path, sys.uid)
@ -51,17 +51,17 @@ func (a *ACLUpdateOp) revert(sys *I, ec *Criteria) error {
}
}
func (a *ACLUpdateOp) Is(o Op) bool {
target, ok := o.(*ACLUpdateOp)
func (a *aclUpdateOp) Is(o Op) bool {
target, ok := o.(*aclUpdateOp)
return ok && a != nil && target != nil &&
a.et == target.et &&
a.path == target.path &&
slices.Equal(a.perms, target.perms)
}
func (a *ACLUpdateOp) Path() string { return a.path }
func (a *aclUpdateOp) Path() string { return a.path }
func (a *ACLUpdateOp) String() string {
func (a *aclUpdateOp) String() string {
return fmt.Sprintf("%s type: %s path: %q",
a.perms, TypeString(a.et), a.path)
}

View File

@ -12,44 +12,44 @@ import (
func TestACLUpdateOp(t *testing.T) {
checkOpBehaviour(t, []opBehaviourTestCase{
{"apply aclUpdate", 0xdeadbeef, 0xff,
&ACLUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}, []stub.Call{
call("verbose", stub.ExpectArgs{[]any{"applying ACL", &ACLUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil),
&aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}, []stub.Call{
call("verbose", stub.ExpectArgs{[]any{"applying ACL", &aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil),
call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xdeadbeef, []acl.Perm{acl.Read, acl.Write, acl.Execute}}, nil, stub.UniqueError(1)),
}, &OpError{Op: "acl", Err: stub.UniqueError(1)}, nil, nil},
{"revert aclUpdate", 0xdeadbeef, 0xff,
&ACLUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}, []stub.Call{
call("verbose", stub.ExpectArgs{[]any{"applying ACL", &ACLUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil),
&aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}, []stub.Call{
call("verbose", stub.ExpectArgs{[]any{"applying ACL", &aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil),
call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xdeadbeef, []acl.Perm{acl.Read, acl.Write, acl.Execute}}, nil, nil),
}, nil, []stub.Call{
call("verbose", stub.ExpectArgs{[]any{"stripping ACL", &ACLUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil),
call("verbose", stub.ExpectArgs{[]any{"stripping ACL", &aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil),
call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xdeadbeef, ([]acl.Perm)(nil)}, nil, stub.UniqueError(0)),
}, &OpError{Op: "acl", Err: stub.UniqueError(0), Revert: true}},
{"success revert skip", 0xdeadbeef, Process,
&ACLUpdateOp{User, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}, []stub.Call{
call("verbose", stub.ExpectArgs{[]any{"applying ACL", &ACLUpdateOp{User, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil),
&aclUpdateOp{User, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}, []stub.Call{
call("verbose", stub.ExpectArgs{[]any{"applying ACL", &aclUpdateOp{User, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil),
call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xdeadbeef, []acl.Perm{acl.Read, acl.Write, acl.Execute}}, nil, nil),
}, nil, []stub.Call{
call("verbose", stub.ExpectArgs{[]any{"skipping ACL", &ACLUpdateOp{User, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil),
call("verbose", stub.ExpectArgs{[]any{"skipping ACL", &aclUpdateOp{User, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil),
}, nil},
{"success revert aclUpdate ENOENT", 0xdeadbeef, 0xff,
&ACLUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}, []stub.Call{
call("verbose", stub.ExpectArgs{[]any{"applying ACL", &ACLUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil),
&aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}, []stub.Call{
call("verbose", stub.ExpectArgs{[]any{"applying ACL", &aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil),
call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xdeadbeef, []acl.Perm{acl.Read, acl.Write, acl.Execute}}, nil, nil),
}, nil, []stub.Call{
call("verbose", stub.ExpectArgs{[]any{"stripping ACL", &ACLUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil),
call("verbose", stub.ExpectArgs{[]any{"stripping ACL", &aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil),
call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xdeadbeef, ([]acl.Perm)(nil)}, nil, &os.PathError{Op: "acl_get_file", Path: "/proc/nonexistent", Err: syscall.ENOENT}),
call("verbosef", stub.ExpectArgs{"target of ACL %s no longer exists", []any{&ACLUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil),
call("verbosef", stub.ExpectArgs{"target of ACL %s no longer exists", []any{&aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil),
}, nil},
{"success", 0xdeadbeef, 0xff,
&ACLUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}, []stub.Call{
call("verbose", stub.ExpectArgs{[]any{"applying ACL", &ACLUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil),
&aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}, []stub.Call{
call("verbose", stub.ExpectArgs{[]any{"applying ACL", &aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil),
call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xdeadbeef, []acl.Perm{acl.Read, acl.Write, acl.Execute}}, nil, nil),
}, nil, []stub.Call{
call("verbose", stub.ExpectArgs{[]any{"stripping ACL", &ACLUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil),
call("verbose", stub.ExpectArgs{[]any{"stripping ACL", &aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil),
call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xdeadbeef, ([]acl.Perm)(nil)}, nil, nil),
}, nil},
})
@ -62,27 +62,27 @@ func TestACLUpdateOp(t *testing.T) {
UpdatePerm("/run/user/1971/hakurei", acl.Execute).
UpdatePerm("/tmp/hakurei.0/tmpdir/150", acl.Read, acl.Write, acl.Execute)
}, []Op{
&ACLUpdateOp{Process, "/run/user/1971/hakurei", []acl.Perm{acl.Execute}},
&ACLUpdateOp{Process, "/tmp/hakurei.0/tmpdir/150", []acl.Perm{acl.Read, acl.Write, acl.Execute}},
&aclUpdateOp{Process, "/run/user/1971/hakurei", []acl.Perm{acl.Execute}},
&aclUpdateOp{Process, "/tmp/hakurei.0/tmpdir/150", []acl.Perm{acl.Read, acl.Write, acl.Execute}},
}, stub.Expect{}},
})
checkOpsBuilder(t, "UpdatePermType", []opsBuilderTestCase{
{"tmpdirp", 0xdeadbeef, func(_ *testing.T, sys *I) {
sys.UpdatePermType(User, "/tmp/hakurei.0/tmpdir", acl.Execute)
}, []Op{
&ACLUpdateOp{User, "/tmp/hakurei.0/tmpdir", []acl.Perm{acl.Execute}},
&aclUpdateOp{User, "/tmp/hakurei.0/tmpdir", []acl.Perm{acl.Execute}},
}, stub.Expect{}},
{"tmpdir", 0xdeadbeef, func(_ *testing.T, sys *I) {
sys.UpdatePermType(User, "/tmp/hakurei.0/tmpdir/150", acl.Read, acl.Write, acl.Execute)
}, []Op{
&ACLUpdateOp{User, "/tmp/hakurei.0/tmpdir/150", []acl.Perm{acl.Read, acl.Write, acl.Execute}},
&aclUpdateOp{User, "/tmp/hakurei.0/tmpdir/150", []acl.Perm{acl.Read, acl.Write, acl.Execute}},
}, stub.Expect{}},
{"share", 0xdeadbeef, func(_ *testing.T, sys *I) {
sys.UpdatePermType(Process, "/run/user/1971/hakurei/fcb8a12f7c482d183ade8288c3de78b5", acl.Execute)
}, []Op{
&ACLUpdateOp{Process, "/run/user/1971/hakurei/fcb8a12f7c482d183ade8288c3de78b5", []acl.Perm{acl.Execute}},
&aclUpdateOp{Process, "/run/user/1971/hakurei/fcb8a12f7c482d183ade8288c3de78b5", []acl.Perm{acl.Execute}},
}, stub.Expect{}},
{"passwd", 0xdeadbeef, func(_ *testing.T, sys *I) {
@ -90,50 +90,50 @@ func TestACLUpdateOp(t *testing.T) {
UpdatePermType(Process, "/tmp/hakurei.0/fcb8a12f7c482d183ade8288c3de78b5/passwd", acl.Read).
UpdatePermType(Process, "/tmp/hakurei.0/fcb8a12f7c482d183ade8288c3de78b5/group", acl.Read)
}, []Op{
&ACLUpdateOp{Process, "/tmp/hakurei.0/fcb8a12f7c482d183ade8288c3de78b5/passwd", []acl.Perm{acl.Read}},
&ACLUpdateOp{Process, "/tmp/hakurei.0/fcb8a12f7c482d183ade8288c3de78b5/group", []acl.Perm{acl.Read}},
&aclUpdateOp{Process, "/tmp/hakurei.0/fcb8a12f7c482d183ade8288c3de78b5/passwd", []acl.Perm{acl.Read}},
&aclUpdateOp{Process, "/tmp/hakurei.0/fcb8a12f7c482d183ade8288c3de78b5/group", []acl.Perm{acl.Read}},
}, stub.Expect{}},
{"wayland", 0xdeadbeef, func(_ *testing.T, sys *I) {
sys.UpdatePermType(EWayland, "/run/user/1971/wayland-0", acl.Read, acl.Write, acl.Execute)
}, []Op{
&ACLUpdateOp{EWayland, "/run/user/1971/wayland-0", []acl.Perm{acl.Read, acl.Write, acl.Execute}},
&aclUpdateOp{EWayland, "/run/user/1971/wayland-0", []acl.Perm{acl.Read, acl.Write, acl.Execute}},
}, stub.Expect{}},
})
checkOpIs(t, []opIsTestCase{
{"nil", (*ACLUpdateOp)(nil), (*ACLUpdateOp)(nil), false},
{"zero", new(ACLUpdateOp), new(ACLUpdateOp), true},
{"nil", (*aclUpdateOp)(nil), (*aclUpdateOp)(nil), false},
{"zero", new(aclUpdateOp), new(aclUpdateOp), true},
{"et differs",
&ACLUpdateOp{
&aclUpdateOp{
EWayland, "/run/user/1971/wayland-0",
[]acl.Perm{acl.Read, acl.Write, acl.Execute},
}, &ACLUpdateOp{
}, &aclUpdateOp{
EX11, "/run/user/1971/wayland-0",
[]acl.Perm{acl.Read, acl.Write, acl.Execute},
}, false},
{"path differs", &ACLUpdateOp{
{"path differs", &aclUpdateOp{
EWayland, "/run/user/1971/wayland-0",
[]acl.Perm{acl.Read, acl.Write, acl.Execute},
}, &ACLUpdateOp{
}, &aclUpdateOp{
EWayland, "/run/user/1971/wayland-1",
[]acl.Perm{acl.Read, acl.Write, acl.Execute},
}, false},
{"perms differs", &ACLUpdateOp{
{"perms differs", &aclUpdateOp{
EWayland, "/run/user/1971/wayland-0",
[]acl.Perm{acl.Read, acl.Write, acl.Execute},
}, &ACLUpdateOp{
}, &aclUpdateOp{
EWayland, "/run/user/1971/wayland-0",
[]acl.Perm{acl.Read, acl.Write},
}, false},
{"equals", &ACLUpdateOp{
{"equals", &aclUpdateOp{
EWayland, "/run/user/1971/wayland-0",
[]acl.Perm{acl.Read, acl.Write, acl.Execute},
}, &ACLUpdateOp{
}, &aclUpdateOp{
EWayland, "/run/user/1971/wayland-0",
[]acl.Perm{acl.Read, acl.Write, acl.Execute},
}, true},
@ -141,42 +141,42 @@ func TestACLUpdateOp(t *testing.T) {
checkOpMeta(t, []opMetaTestCase{
{"clear",
&ACLUpdateOp{Process, "/proc/nonexistent", []acl.Perm{}},
&aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{}},
Process, "/proc/nonexistent",
`--- type: process path: "/proc/nonexistent"`},
{"read",
&ACLUpdateOp{User, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/0", []acl.Perm{acl.Read}},
&aclUpdateOp{User, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/0", []acl.Perm{acl.Read}},
User, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/0",
`r-- type: user path: "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/0"`},
{"write",
&ACLUpdateOp{User, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/1", []acl.Perm{acl.Write}},
&aclUpdateOp{User, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/1", []acl.Perm{acl.Write}},
User, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/1",
`-w- type: user path: "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/1"`},
{"execute",
&ACLUpdateOp{User, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/2", []acl.Perm{acl.Execute}},
&aclUpdateOp{User, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/2", []acl.Perm{acl.Execute}},
User, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/2",
`--x type: user path: "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/2"`},
{"wayland",
&ACLUpdateOp{EWayland, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/wayland", []acl.Perm{acl.Read, acl.Write}},
&aclUpdateOp{EWayland, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/wayland", []acl.Perm{acl.Read, acl.Write}},
EWayland, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/wayland",
`rw- type: wayland path: "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/wayland"`},
{"x11",
&ACLUpdateOp{EX11, "/tmp/.X11-unix/X0", []acl.Perm{acl.Read, acl.Execute}},
&aclUpdateOp{EX11, "/tmp/.X11-unix/X0", []acl.Perm{acl.Read, acl.Execute}},
EX11, "/tmp/.X11-unix/X0",
`r-x type: x11 path: "/tmp/.X11-unix/X0"`},
{"dbus",
&ACLUpdateOp{EDBus, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/bus", []acl.Perm{acl.Write, acl.Execute}},
&aclUpdateOp{EDBus, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/bus", []acl.Perm{acl.Write, acl.Execute}},
EDBus, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/bus",
`-wx type: dbus path: "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/bus"`},
{"pulseaudio",
&ACLUpdateOp{EPulse, "/run/user/1971/hakurei/27d81d567f8fae7f33278eec45da9446/pulse", []acl.Perm{acl.Read, acl.Write, acl.Execute}},
&aclUpdateOp{EPulse, "/run/user/1971/hakurei/27d81d567f8fae7f33278eec45da9446/pulse", []acl.Perm{acl.Read, acl.Write, acl.Execute}},
EPulse, "/run/user/1971/hakurei/27d81d567f8fae7f33278eec45da9446/pulse",
`rwx type: pulseaudio path: "/run/user/1971/hakurei/27d81d567f8fae7f33278eec45da9446/pulse"`},
})

View File

@ -28,9 +28,10 @@ func (sys *I) MustProxyDBus(sessionPath string, session *dbus.Config, systemPath
}
}
// ProxyDBus finalises configuration and appends [DBusProxyOp] to [I].
// ProxyDBus finalises configuration ahead of time and starts xdg-dbus-proxy via [dbus] and terminates it on revert.
// This [Op] is always [Process] scoped.
func (sys *I) ProxyDBus(session, system *dbus.Config, sessionPath, systemPath string) (func(), error) {
d := new(DBusProxyOp)
d := new(dbusProxyOp)
// session bus is required as otherwise this is effectively a very expensive noop
if session == nil {
@ -70,9 +71,8 @@ func (sys *I) ProxyDBus(session, system *dbus.Config, sessionPath, systemPath st
return d.out.Dump, nil
}
// DBusProxyOp starts xdg-dbus-proxy via [dbus] and terminates it on revert.
// This [Op] is always [Process] scoped.
type DBusProxyOp struct {
// dbusProxyOp implements [I.ProxyDBus].
type dbusProxyOp struct {
proxy *dbus.Proxy // populated during apply
final *dbus.Final
@ -81,9 +81,9 @@ type DBusProxyOp struct {
system bool
}
func (d *DBusProxyOp) Type() Enablement { return Process }
func (d *dbusProxyOp) Type() Enablement { return Process }
func (d *DBusProxyOp) apply(sys *I) error {
func (d *dbusProxyOp) apply(sys *I) error {
sys.verbosef("session bus proxy on %q for upstream %q", d.final.Session[1], d.final.Session[0])
if d.system {
sys.verbosef("system bus proxy on %q for upstream %q", d.final.System[1], d.final.System[0])
@ -99,7 +99,7 @@ func (d *DBusProxyOp) apply(sys *I) error {
return nil
}
func (d *DBusProxyOp) revert(sys *I, _ *Criteria) error {
func (d *dbusProxyOp) revert(sys *I, _ *Criteria) error {
// criteria ignored here since dbus is always process-scoped
sys.verbose("terminating message bus proxy")
sys.dbusProxyClose(d.proxy)
@ -116,8 +116,8 @@ func (d *DBusProxyOp) revert(sys *I, _ *Criteria) error {
fmt.Sprintf("message bus proxy error: %v", err), true)
}
func (d *DBusProxyOp) Is(o Op) bool {
target, ok := o.(*DBusProxyOp)
func (d *dbusProxyOp) Is(o Op) bool {
target, ok := o.(*dbusProxyOp)
return ok && d != nil && target != nil &&
d.system == target.system &&
d.final != nil && target.final != nil &&
@ -128,8 +128,8 @@ func (d *DBusProxyOp) Is(o Op) bool {
reflect.DeepEqual(d.final.WriterTo, target.final.WriterTo)
}
func (d *DBusProxyOp) Path() string { return container.Nonexistent }
func (d *DBusProxyOp) String() string { return d.proxy.String() }
func (d *dbusProxyOp) Path() string { return container.Nonexistent }
func (d *dbusProxyOp) String() string { return d.proxy.String() }
const (
// lpwSizeThreshold is the threshold of bytes written to linePrefixWriter which,

View File

@ -16,7 +16,7 @@ import (
func TestDBusProxyOp(t *testing.T) {
checkOpBehaviour(t, []opBehaviourTestCase{
{"dbusProxyStart", 0xdeadbeef, 0xff, &DBusProxyOp{
{"dbusProxyStart", 0xdeadbeef, 0xff, &dbusProxyOp{
final: dbusNewFinalSample(4),
out: new(linePrefixWriter), // panics on write
system: true,
@ -29,7 +29,7 @@ func TestDBusProxyOp(t *testing.T) {
Msg: "cannot start message bus proxy: unique error 2 injected by the test suite",
}, nil, nil},
{"dbusProxyWait", 0xdeadbeef, 0xff, &DBusProxyOp{
{"dbusProxyWait", 0xdeadbeef, 0xff, &dbusProxyOp{
final: dbusNewFinalSample(3),
}, []stub.Call{
call("verbosef", stub.ExpectArgs{"session bus proxy on %q for upstream %q", []any{"/tmp/hakurei.0/99dd71ee2146369514e0d10783368f8f/bus", "unix:path=/run/user/1000/bus"}}, nil, nil),
@ -45,7 +45,7 @@ func TestDBusProxyOp(t *testing.T) {
Msg: "message bus proxy error: unique error 1 injected by the test suite",
}},
{"success dbusProxyWait cancel", 0xdeadbeef, 0xff, &DBusProxyOp{
{"success dbusProxyWait cancel", 0xdeadbeef, 0xff, &dbusProxyOp{
final: dbusNewFinalSample(2),
system: true,
}, []stub.Call{
@ -60,7 +60,7 @@ func TestDBusProxyOp(t *testing.T) {
call("verbose", stub.ExpectArgs{[]any{"message bus proxy canceled upstream"}}, nil, nil),
}, nil},
{"success", 0xdeadbeef, 0xff, &DBusProxyOp{
{"success", 0xdeadbeef, 0xff, &dbusProxyOp{
final: dbusNewFinalSample(1),
system: true,
}, []stub.Call{
@ -154,7 +154,7 @@ func TestDBusProxyOp(t *testing.T) {
Talk: []string{"system\x00"}, Filter: true,
})
}, []Op{
&DBusProxyOp{
&dbusProxyOp{
final: dbusNewFinalSample(0),
system: true,
},
@ -174,10 +174,10 @@ func TestDBusProxyOp(t *testing.T) {
})
checkOpIs(t, []opIsTestCase{
{"nil", (*DBusProxyOp)(nil), (*DBusProxyOp)(nil), false},
{"zero", new(DBusProxyOp), new(DBusProxyOp), false},
{"nil", (*dbusProxyOp)(nil), (*dbusProxyOp)(nil), false},
{"zero", new(dbusProxyOp), new(dbusProxyOp), false},
{"system differs", &DBusProxyOp{final: &dbus.Final{
{"system differs", &dbusProxyOp{final: &dbus.Final{
Session: dbus.ProxyPair{"unix:path=/run/user/1000/bus", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/bus"},
System: dbus.ProxyPair{"unix:path=/run/dbus/system_bus_socket", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/system_bus_socket"},
@ -189,7 +189,7 @@ func TestDBusProxyOp(t *testing.T) {
"--filter", "unix:path=/run/dbus/system_bus_socket", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/system_bus_socket",
}),
}, system: false,
}, &DBusProxyOp{final: &dbus.Final{
}, &dbusProxyOp{final: &dbus.Final{
Session: dbus.ProxyPair{"unix:path=/run/user/1000/bus", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/bus"},
System: dbus.ProxyPair{"unix:path=/run/dbus/system_bus_socket", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/system_bus_socket"},
@ -203,7 +203,7 @@ func TestDBusProxyOp(t *testing.T) {
}, system: true,
}, false},
{"wt differs", &DBusProxyOp{final: &dbus.Final{
{"wt differs", &dbusProxyOp{final: &dbus.Final{
Session: dbus.ProxyPair{"unix:path=/run/user/1000/bus", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/bus"},
System: dbus.ProxyPair{"unix:path=/run/dbus/system_bus_socket", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/system_bus_socket"},
@ -215,7 +215,7 @@ func TestDBusProxyOp(t *testing.T) {
"--filter", "unix:path=/run/dbus/system_bus_socket", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/system_bus_socket",
}),
}, system: true,
}, &DBusProxyOp{final: &dbus.Final{
}, &dbusProxyOp{final: &dbus.Final{
Session: dbus.ProxyPair{"unix:path=/run/user/1000/bus", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/bus"},
System: dbus.ProxyPair{"unix:path=/run/dbus/system_bus_socket", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/system_bus_socket"},
@ -229,7 +229,7 @@ func TestDBusProxyOp(t *testing.T) {
}, system: true,
}, false},
{"final system upstream differs", &DBusProxyOp{final: &dbus.Final{
{"final system upstream differs", &dbusProxyOp{final: &dbus.Final{
Session: dbus.ProxyPair{"unix:path=/run/user/1000/bus", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/bus"},
System: dbus.ProxyPair{"unix:path=/run/dbus/system_bus_socket", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/system_bus_socket"},
@ -241,7 +241,7 @@ func TestDBusProxyOp(t *testing.T) {
"--filter", "unix:path=/run/dbus/system_bus_socket", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/system_bus_socket",
}),
}, system: true,
}, &DBusProxyOp{final: &dbus.Final{
}, &dbusProxyOp{final: &dbus.Final{
Session: dbus.ProxyPair{"unix:path=/run/user/1000/bus", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/bus"},
System: dbus.ProxyPair{"unix:path=/run/dbus/system_bus_socket", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/system_bus_socket"},
@ -255,7 +255,7 @@ func TestDBusProxyOp(t *testing.T) {
}, system: true,
}, false},
{"final session upstream differs", &DBusProxyOp{final: &dbus.Final{
{"final session upstream differs", &dbusProxyOp{final: &dbus.Final{
Session: dbus.ProxyPair{"unix:path=/run/user/1000/bus", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/bus"},
System: dbus.ProxyPair{"unix:path=/run/dbus/system_bus_socket", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/system_bus_socket"},
@ -267,7 +267,7 @@ func TestDBusProxyOp(t *testing.T) {
"--filter", "unix:path=/run/dbus/system_bus_socket", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/system_bus_socket",
}),
}, system: true,
}, &DBusProxyOp{final: &dbus.Final{
}, &dbusProxyOp{final: &dbus.Final{
Session: dbus.ProxyPair{"unix:path=/run/user/1000/bus", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/bus"},
System: dbus.ProxyPair{"unix:path=/run/dbus/system_bus_socket", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/system_bus_socket"},
@ -281,7 +281,7 @@ func TestDBusProxyOp(t *testing.T) {
}, system: true,
}, false},
{"final system differs", &DBusProxyOp{final: &dbus.Final{
{"final system differs", &dbusProxyOp{final: &dbus.Final{
Session: dbus.ProxyPair{"unix:path=/run/user/1000/bus", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/bus"},
System: dbus.ProxyPair{"unix:path=/run/dbus/system_bus_socket", "/tmp/hakurei.1/b186c281d9e83a39afdc66d964ef99c6/system_bus_socket"},
@ -293,7 +293,7 @@ func TestDBusProxyOp(t *testing.T) {
"--filter", "unix:path=/run/dbus/system_bus_socket", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/system_bus_socket",
}),
}, system: true,
}, &DBusProxyOp{final: &dbus.Final{
}, &dbusProxyOp{final: &dbus.Final{
Session: dbus.ProxyPair{"unix:path=/run/user/1000/bus", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/bus"},
System: dbus.ProxyPair{"unix:path=/run/dbus/system_bus_socket", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/system_bus_socket"},
@ -307,7 +307,7 @@ func TestDBusProxyOp(t *testing.T) {
}, system: true,
}, false},
{"final session differs", &DBusProxyOp{final: &dbus.Final{
{"final session differs", &dbusProxyOp{final: &dbus.Final{
Session: dbus.ProxyPair{"unix:path=/run/user/1001/bus", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/bus"},
System: dbus.ProxyPair{"unix:path=/run/dbus/system_bus_socket", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/system_bus_socket"},
@ -319,7 +319,7 @@ func TestDBusProxyOp(t *testing.T) {
"--filter", "unix:path=/run/dbus/system_bus_socket", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/system_bus_socket",
}),
}, system: true,
}, &DBusProxyOp{final: &dbus.Final{
}, &dbusProxyOp{final: &dbus.Final{
Session: dbus.ProxyPair{"unix:path=/run/user/1000/bus", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/bus"},
System: dbus.ProxyPair{"unix:path=/run/dbus/system_bus_socket", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/system_bus_socket"},
@ -333,7 +333,7 @@ func TestDBusProxyOp(t *testing.T) {
}, system: true,
}, false},
{"equals", &DBusProxyOp{final: &dbus.Final{
{"equals", &dbusProxyOp{final: &dbus.Final{
Session: dbus.ProxyPair{"unix:path=/run/user/1000/bus", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/bus"},
System: dbus.ProxyPair{"unix:path=/run/dbus/system_bus_socket", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/system_bus_socket"},
@ -345,7 +345,7 @@ func TestDBusProxyOp(t *testing.T) {
"--filter", "unix:path=/run/dbus/system_bus_socket", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/system_bus_socket",
}),
}, system: true,
}, &DBusProxyOp{final: &dbus.Final{
}, &dbusProxyOp{final: &dbus.Final{
Session: dbus.ProxyPair{"unix:path=/run/user/1000/bus", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/bus"},
System: dbus.ProxyPair{"unix:path=/run/dbus/system_bus_socket", "/tmp/hakurei.0/b186c281d9e83a39afdc66d964ef99c6/system_bus_socket"},
@ -361,7 +361,7 @@ func TestDBusProxyOp(t *testing.T) {
})
checkOpMeta(t, []opMetaTestCase{
{"dbus", new(DBusProxyOp),
{"dbus", new(dbusProxyOp),
Process, "/proc/nonexistent",
"(invalid dbus proxy)"},
})

View File

@ -5,29 +5,29 @@ import (
"os"
)
// Link appends [HardlinkOp] to [I] the [Process] criteria.
// Link calls LinkFileType with the [Process] criteria.
func (sys *I) Link(oldname, newname string) *I { return sys.LinkFileType(Process, oldname, newname) }
// LinkFileType appends [HardlinkOp] to [I].
// LinkFileType maintains a hardlink until its [Enablement] is no longer satisfied.
func (sys *I) LinkFileType(et Enablement, oldname, newname string) *I {
sys.ops = append(sys.ops, &HardlinkOp{et, newname, oldname})
sys.ops = append(sys.ops, &hardlinkOp{et, newname, oldname})
return sys
}
// HardlinkOp maintains a hardlink until its [Enablement] is no longer satisfied.
type HardlinkOp struct {
// hardlinkOp implements [I.LinkFileType].
type hardlinkOp struct {
et Enablement
dst, src string
}
func (l *HardlinkOp) Type() Enablement { return l.et }
func (l *hardlinkOp) Type() Enablement { return l.et }
func (l *HardlinkOp) apply(*I) error {
func (l *hardlinkOp) apply(*I) error {
msg.Verbose("linking", l)
return newOpError("hardlink", os.Link(l.src, l.dst), false)
}
func (l *HardlinkOp) revert(_ *I, ec *Criteria) error {
func (l *hardlinkOp) revert(_ *I, ec *Criteria) error {
if ec.hasType(l.Type()) {
msg.Verbosef("removing hard link %q", l.dst)
return newOpError("hardlink", os.Remove(l.dst), true)
@ -37,10 +37,10 @@ func (l *HardlinkOp) revert(_ *I, ec *Criteria) error {
}
}
func (l *HardlinkOp) Is(o Op) bool {
target, ok := o.(*HardlinkOp)
func (l *hardlinkOp) Is(o Op) bool {
target, ok := o.(*hardlinkOp)
return ok && l != nil && target != nil && *l == *target
}
func (l *HardlinkOp) Path() string { return l.src }
func (l *HardlinkOp) String() string { return fmt.Sprintf("%q from %q", l.dst, l.src) }
func (l *hardlinkOp) Path() string { return l.src }
func (l *hardlinkOp) String() string { return fmt.Sprintf("%q from %q", l.dst, l.src) }

View File

@ -6,30 +6,29 @@ import (
"os"
)
// Ensure appends [MkdirOp] to [I] with its [Enablement] ignored.
// Ensure ensures the existence of a directory.
func (sys *I) Ensure(name string, perm os.FileMode) *I {
sys.ops = append(sys.ops, &MkdirOp{User, name, perm, false})
sys.ops = append(sys.ops, &mkdirOp{User, name, perm, false})
return sys
}
// Ephemeral appends an ephemeral [MkdirOp] to [I].
// Ephemeral ensures the existence of a directory until its [Enablement] is no longer satisfied.
func (sys *I) Ephemeral(et Enablement, name string, perm os.FileMode) *I {
sys.ops = append(sys.ops, &MkdirOp{et, name, perm, true})
sys.ops = append(sys.ops, &mkdirOp{et, name, perm, true})
return sys
}
// MkdirOp ensures the existence of a directory.
// For ephemeral, the directory is destroyed once [Enablement] is no longer satisfied.
type MkdirOp struct {
// mkdirOp implements [I.Ensure] and [I.Ephemeral].
type mkdirOp struct {
et Enablement
path string
perm os.FileMode
ephemeral bool
}
func (m *MkdirOp) Type() Enablement { return m.et }
func (m *mkdirOp) Type() Enablement { return m.et }
func (m *MkdirOp) apply(*I) error {
func (m *mkdirOp) apply(*I) error {
msg.Verbose("ensuring directory", m)
// create directory
@ -44,7 +43,7 @@ func (m *MkdirOp) apply(*I) error {
}
}
func (m *MkdirOp) revert(_ *I, ec *Criteria) error {
func (m *mkdirOp) revert(_ *I, ec *Criteria) error {
if !m.ephemeral {
// skip non-ephemeral dir and do not log anything
return nil
@ -59,14 +58,14 @@ func (m *MkdirOp) revert(_ *I, ec *Criteria) error {
}
}
func (m *MkdirOp) Is(o Op) bool {
target, ok := o.(*MkdirOp)
func (m *mkdirOp) Is(o Op) bool {
target, ok := o.(*mkdirOp)
return ok && m != nil && target != nil && *m == *target
}
func (m *MkdirOp) Path() string { return m.path }
func (m *mkdirOp) Path() string { return m.path }
func (m *MkdirOp) String() string {
func (m *mkdirOp) String() string {
t := "ensure"
if m.ephemeral {
t = TypeString(m.Type())

View File

@ -21,7 +21,7 @@ func TestEnsure(t *testing.T) {
t.Run(tc.name+"_"+tc.perm.String(), func(t *testing.T) {
sys := New(t.Context(), 150)
sys.Ensure(tc.name, tc.perm)
(&tcOp{User, tc.name}).test(t, sys.ops, []Op{&MkdirOp{User, tc.name, tc.perm, false}}, "Ensure")
(&tcOp{User, tc.name}).test(t, sys.ops, []Op{&mkdirOp{User, tc.name, tc.perm, false}}, "Ensure")
})
}
}
@ -38,7 +38,7 @@ func TestEphemeral(t *testing.T) {
t.Run(tc.path+"_"+tc.perm.String()+"_"+TypeString(tc.et), func(t *testing.T) {
sys := New(t.Context(), 150)
sys.Ephemeral(tc.et, tc.path, tc.perm)
tc.test(t, sys.ops, []Op{&MkdirOp{tc.et, tc.path, tc.perm, true}}, "Ephemeral")
tc.test(t, sys.ops, []Op{&mkdirOp{tc.et, tc.path, tc.perm, true}}, "Ephemeral")
})
}
}
@ -60,7 +60,7 @@ func TestMkdirString(t *testing.T) {
}
for _, tc := range testCases {
t.Run(tc.want, func(t *testing.T) {
m := &MkdirOp{
m := &mkdirOp{
et: tc.et,
path: container.Nonexistent,
perm: 0701,

View File

@ -9,16 +9,16 @@ import (
"syscall"
)
// CopyFile appends [TmpfileOp] to [I].
func (sys *I) CopyFile(payload *[]byte, src string, cap int, n int64) *I {
// CopyFile reads up to n bytes from src and writes the resulting byte slice to payloadP.
func (sys *I) CopyFile(payloadP *[]byte, src string, cap int, n int64) *I {
buf := new(bytes.Buffer)
buf.Grow(cap)
sys.ops = append(sys.ops, &TmpfileOp{payload, src, n, buf})
sys.ops = append(sys.ops, &tmpfileOp{payloadP, src, n, buf})
return sys
}
// TmpfileOp reads up to n bytes from src and writes the resulting byte slice to payload.
type TmpfileOp struct {
// tmpfileOp implements [I.CopyFile].
type tmpfileOp struct {
payload *[]byte
src string
@ -26,8 +26,9 @@ type TmpfileOp struct {
buf *bytes.Buffer
}
func (t *TmpfileOp) Type() Enablement { return Process }
func (t *TmpfileOp) apply(*I) error {
func (t *tmpfileOp) Type() Enablement { return Process }
func (t *tmpfileOp) apply(*I) error {
msg.Verbose("copying", t)
if t.payload == nil {
@ -55,12 +56,12 @@ func (t *TmpfileOp) apply(*I) error {
*t.payload = t.buf.Bytes()
return nil
}
func (t *TmpfileOp) revert(*I, *Criteria) error { t.buf.Reset(); return nil }
func (t *tmpfileOp) revert(*I, *Criteria) error { t.buf.Reset(); return nil }
func (t *TmpfileOp) Is(o Op) bool {
target, ok := o.(*TmpfileOp)
func (t *tmpfileOp) Is(o Op) bool {
target, ok := o.(*tmpfileOp)
return ok && t != nil && target != nil &&
t.src == target.src && t.n == target.n
}
func (t *TmpfileOp) Path() string { return t.src }
func (t *TmpfileOp) String() string { return fmt.Sprintf("up to %d bytes from %q", t.n, t.src) }
func (t *tmpfileOp) Path() string { return t.src }
func (t *tmpfileOp) String() string { return fmt.Sprintf("up to %d bytes from %q", t.n, t.src) }

View File

@ -18,7 +18,7 @@ func TestCopyFile(t *testing.T) {
sys := New(t.Context(), 150)
sys.CopyFile(new([]byte), tc.path, tc.cap, tc.n)
tc.test(t, sys.ops, []Op{
&TmpfileOp{nil, tc.path, tc.n, nil},
&tmpfileOp{nil, tc.path, tc.n, nil},
}, "CopyFile")
})
}
@ -36,7 +36,7 @@ func TestLink(t *testing.T) {
sys := New(t.Context(), 150)
sys.Link(tc.src, tc.dst)
(&tcOp{Process, tc.src}).test(t, sys.ops, []Op{
&HardlinkOp{Process, tc.dst, tc.src},
&hardlinkOp{Process, tc.dst, tc.src},
}, "Link")
})
}
@ -55,7 +55,7 @@ func TestLinkFileType(t *testing.T) {
sys := New(t.Context(), 150)
sys.LinkFileType(tc.et, tc.path, tc.dst)
tc.test(t, sys.ops, []Op{
&HardlinkOp{tc.et, tc.dst, tc.path},
&hardlinkOp{tc.et, tc.dst, tc.path},
}, "LinkFileType")
})
}
@ -73,7 +73,7 @@ func TestTmpfile_String(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.want, func(t *testing.T) {
if got := (&TmpfileOp{src: tc.src, n: tc.n}).String(); got != tc.want {
if got := (&tmpfileOp{src: tc.src, n: tc.n}).String(); got != tc.want {
t.Errorf("String() = %v, want %v", got, tc.want)
}
})

View File

@ -9,16 +9,16 @@ import (
"hakurei.app/system/wayland"
)
// Wayland appends [WaylandOp] to [I].
// Wayland maintains a wayland socket with security-context-v1 attached via [wayland].
// The socket stops accepting connections once the pipe referred to by sync is closed.
// The socket is pathname only and is destroyed on revert.
func (sys *I) Wayland(syncFd **os.File, dst, src, appID, instanceID string) *I {
sys.ops = append(sys.ops, &WaylandOp{syncFd, dst, src, appID, instanceID, wayland.Conn{}})
sys.ops = append(sys.ops, &waylandOp{syncFd, dst, src, appID, instanceID, wayland.Conn{}})
return sys
}
// WaylandOp maintains a wayland socket with security-context-v1 attached via [wayland].
// The socket stops accepting connections once the pipe referred to by sync is closed.
// The socket is pathname only and is destroyed on revert.
type WaylandOp struct {
// waylandOp implements [I.Wayland].
type waylandOp struct {
sync **os.File
dst, src string
appID, instanceID string
@ -26,9 +26,9 @@ type WaylandOp struct {
conn wayland.Conn
}
func (w *WaylandOp) Type() Enablement { return Process }
func (w *waylandOp) Type() Enablement { return Process }
func (w *WaylandOp) apply(sys *I) error {
func (w *waylandOp) apply(sys *I) error {
if w.sync == nil {
// this is a misuse of the API; do not return a wrapped error
return errors.New("invalid sync")
@ -58,7 +58,7 @@ func (w *WaylandOp) apply(sys *I) error {
}
}
func (w *WaylandOp) revert(_ *I, ec *Criteria) error {
func (w *waylandOp) revert(_ *I, ec *Criteria) error {
if ec.hasType(w.Type()) {
msg.Verbosef("removing wayland socket on %q", w.dst)
if err := os.Remove(w.dst); err != nil && !errors.Is(err, os.ErrNotExist) {
@ -73,12 +73,12 @@ func (w *WaylandOp) revert(_ *I, ec *Criteria) error {
}
}
func (w *WaylandOp) Is(o Op) bool {
target, ok := o.(*WaylandOp)
func (w *waylandOp) Is(o Op) bool {
target, ok := o.(*waylandOp)
return ok && w != nil && target != nil &&
w.dst == target.dst && w.src == target.src &&
w.appID == target.appID && w.instanceID == target.instanceID
}
func (w *WaylandOp) Path() string { return w.dst }
func (w *WaylandOp) String() string { return fmt.Sprintf("wayland socket at %q", w.dst) }
func (w *waylandOp) Path() string { return w.dst }
func (w *waylandOp) String() string { return fmt.Sprintf("wayland socket at %q", w.dst) }

View File

@ -4,24 +4,24 @@ import (
"hakurei.app/system/internal/xcb"
)
// ChangeHosts appends [XHostOp] to [I].
// ChangeHosts inserts the target user into X11 hosts and deletes it once its [Enablement] is no longer satisfied.
func (sys *I) ChangeHosts(username string) *I {
sys.ops = append(sys.ops, XHostOp(username))
sys.ops = append(sys.ops, xhostOp(username))
return sys
}
// XHostOp inserts the target user into X11 hosts and deletes it once its [Enablement] is no longer satisfied.
type XHostOp string
// xhostOp implements [I.ChangeHosts].
type xhostOp string
func (x XHostOp) Type() Enablement { return EX11 }
func (x xhostOp) Type() Enablement { return EX11 }
func (x XHostOp) apply(*I) error {
func (x xhostOp) apply(*I) error {
msg.Verbosef("inserting entry %s to X11", x)
return newOpError("xhost",
xcb.ChangeHosts(xcb.HostModeInsert, xcb.FamilyServerInterpreted, "localuser\x00"+string(x)), false)
}
func (x XHostOp) revert(_ *I, ec *Criteria) error {
func (x xhostOp) revert(_ *I, ec *Criteria) error {
if ec.hasType(x.Type()) {
msg.Verbosef("deleting entry %s from X11", x)
return newOpError("xhost",
@ -32,6 +32,6 @@ func (x XHostOp) revert(_ *I, ec *Criteria) error {
}
}
func (x XHostOp) Is(o Op) bool { target, ok := o.(XHostOp); return ok && x == target }
func (x XHostOp) Path() string { return string(x) }
func (x XHostOp) String() string { return string("SI:localuser:" + x) }
func (x xhostOp) Is(o Op) bool { target, ok := o.(xhostOp); return ok && x == target }
func (x xhostOp) Path() string { return string(x) }
func (x xhostOp) String() string { return string("SI:localuser:" + x) }

View File

@ -11,7 +11,7 @@ func TestChangeHosts(t *testing.T) {
sys := New(t.Context(), 150)
sys.ChangeHosts(tc)
(&tcOp{EX11, tc}).test(t, sys.ops, []Op{
XHostOp(tc),
xhostOp(tc),
}, "ChangeHosts")
})
}
@ -26,7 +26,7 @@ func TestXHost_String(t *testing.T) {
}
for _, tc := range testCases {
t.Run(tc.want, func(t *testing.T) {
if got := XHostOp(tc.username).String(); got != tc.want {
if got := xhostOp(tc.username).String(); got != tc.want {
t.Errorf("String() = %v, want %v", got, tc.want)
}
})