summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorewy <ewy0@protonmail.com>2026-04-29 01:59:23 +0200
committerewy <ewy0@protonmail.com>2026-04-29 01:59:23 +0200
commit28e43c7356d796e18d2f818d100078c5aa31c14c (patch)
tree023c7f4a9d192bcf4f16755307f43a622beb671d
parent2b28ee919614d5ddaceda26ce488a0ca4c851cb3 (diff)
add executable runner
-rw-r--r--main.go2
-rw-r--r--motd/motd.go2
-rw-r--r--order/order.go13
-rw-r--r--runner/base.go28
-rw-r--r--runner/exc/exc.go6
-rw-r--r--runner/exc/runner.go42
-rw-r--r--runner/exc/target.go50
-rw-r--r--runner/shell/shell.go2
-rw-r--r--runner/shell/target.go2
9 files changed, 143 insertions, 4 deletions
diff --git a/main.go b/main.go
index 7909274..045e5e0 100644
--- a/main.go
+++ b/main.go
@@ -14,6 +14,7 @@ import (
"pik/model"
"pik/paths"
"pik/run"
+ "pik/runner/exc"
"pik/runner/gnumake"
"pik/runner/just"
"pik/runner/python"
@@ -49,6 +50,7 @@ var indexers = []model.Indexer{
var runners = []model.Runner{
shell.Runner,
python.Python,
+ exc.Exc,
}
// hydrators are ran when the menu is required
diff --git a/motd/motd.go b/motd/motd.go
index bb64606..10eacd2 100644
--- a/motd/motd.go
+++ b/motd/motd.go
@@ -21,6 +21,8 @@ var Messages = []string{
"create a target with the same base name but containing .override. to prefer it over the other during invocations",
"pik crawls both the regular and symlink evaluated locations, if they are different",
"unsure about what you're doing? use --dry to check what you're running",
+ "use --edit to open a target in your $EDITOR",
+ "pik indexes executable files too, if you want to run something arbitrary",
}
func One() string {
diff --git a/order/order.go b/order/order.go
index 40e6e73..83c7dcb 100644
--- a/order/order.go
+++ b/order/order.go
@@ -31,6 +31,7 @@ func FromFile(f fs.FS, path string) (Order, error) {
}
func FromReader(r io.Reader) (Order, error) {
+ o := &Order{}
scanner := bufio.NewScanner(r)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
@@ -45,6 +46,18 @@ func FromReader(r io.Reader) (Order, error) {
continue
}
}
+
+ spl := strings.SplitN(line, "#", 2)
+
+ e := &Element{
+ Identifier: identity.New(spl[0]),
+ }
+ if len(spl) > 1 {
+ e.Description = spl[1]
+ }
+
+ o.Elements = append(o.Elements, *e)
}
+ return *o, nil
}
diff --git a/runner/base.go b/runner/base.go
index c9825ae..e1fef66 100644
--- a/runner/base.go
+++ b/runner/base.go
@@ -1,15 +1,35 @@
package runner
import (
+ "path/filepath"
"pik/identity"
+ "pik/indexers/pikdex"
"pik/model"
+ "slices"
+ "strings"
)
// BaseTarget is an embeddable type which contains some of the information we need for (almost) every target.
type BaseTarget struct {
identity.Identity
MyTags model.Tags
- Sub []string
+ MySub []string
+}
+
+func SubFromFile(file string) []string {
+ _, filename := filepath.Split(file)
+ var sub []string
+ split := strings.Split(file, "/")
+ for _, p := range split {
+ if slices.Contains(pikdex.Roots, p) {
+ continue
+ }
+ if filename == p {
+ continue
+ }
+ sub = append(sub, p)
+ }
+ return sub
}
func (t *BaseTarget) Tags() model.Tags {
@@ -29,7 +49,7 @@ func (b *BaseTarget) Visible() bool {
}
func (b *BaseTarget) Invocation(src *model.Source) []string {
- return append([]string{src.Identity.Reduced}, append(b.Sub, b.Identity.Reduced)...)
+ return append([]string{src.Identity.Reduced}, append(b.MySub, b.Identity.Reduced)...)
}
func Hydrated[T model.Target](in T) BaseHydration[T] {
@@ -53,3 +73,7 @@ func (b *BaseHydration[T]) Description() string {
func (b *BaseHydration[T]) Target() model.Target {
return b.Self
}
+
+func (b *BaseTarget) Sub() []string {
+ return b.MySub
+}
diff --git a/runner/exc/exc.go b/runner/exc/exc.go
new file mode 100644
index 0000000..18d5214
--- /dev/null
+++ b/runner/exc/exc.go
@@ -0,0 +1,6 @@
+package exc
+
+type exc struct {
+}
+
+var Exc = &exc{}
diff --git a/runner/exc/runner.go b/runner/exc/runner.go
new file mode 100644
index 0000000..4b0c2e6
--- /dev/null
+++ b/runner/exc/runner.go
@@ -0,0 +1,42 @@
+package exc
+
+import (
+ "io/fs"
+ "path/filepath"
+ "pik/identity"
+ "pik/model"
+ "pik/runner"
+ "pik/spool"
+)
+
+func (e *exc) Hydrate(target model.Target) (model.HydratedTarget, error) {
+ return &Hydrated{
+ BaseHydration: &runner.BaseHydration[*Executable]{
+ Self: target.(*Executable),
+ },
+ }, nil
+}
+
+func (e *exc) Wants(fs fs.FS, file string, entry fs.DirEntry) (bool, error) {
+ if entry.IsDir() {
+ return false, nil
+ }
+ info, err := entry.Info()
+ if err != nil {
+ spool.Warn("%v\n", err)
+ }
+ return info.Mode()&0100 != 0, nil
+}
+
+func (e *exc) CreateTarget(fs fs.FS, source string, file string, entry fs.DirEntry) (model.Target, error) {
+ _, filename := filepath.Split(file)
+ return &Executable{
+
+ BaseTarget: runner.BaseTarget{
+ Identity: identity.New(entry.Name()),
+ MyTags: model.TagsFromFilename(filename),
+ MySub: runner.SubFromFile(file),
+ },
+ Path: filepath.Join(source, file),
+ }, nil
+}
diff --git a/runner/exc/target.go b/runner/exc/target.go
new file mode 100644
index 0000000..c9d20b8
--- /dev/null
+++ b/runner/exc/target.go
@@ -0,0 +1,50 @@
+package exc
+
+import (
+ "os/exec"
+ "pik/describe"
+ "pik/model"
+ "pik/runner"
+ "pik/spool"
+)
+
+type Executable struct {
+ runner.BaseTarget
+ Path string
+}
+
+type Hydrated struct {
+ *runner.BaseHydration[*Executable]
+}
+
+func (h *Hydrated) Icon() string {
+ return "\uEAE8"
+}
+
+func (h *Hydrated) Description(src *model.HydratedSource) string {
+ d, err := describe.Describe(h.Self, h.Self.Path)
+ if err != nil {
+ spool.Warn("%v\n", err)
+ }
+ return d
+}
+
+func (e *Executable) Create(s *model.Source) *exec.Cmd {
+ return exec.Command(e.Path)
+}
+
+func (e *Executable) Label() string {
+ return e.Identity.Full
+}
+
+func (e *Executable) Hydrate(src *model.Source) (model.HydratedTarget, error) {
+ return &Hydrated{
+ BaseHydration: &runner.BaseHydration[*Executable]{
+ Self: e,
+ },
+ }, nil
+}
+
+func (e *Executable) File(src *model.Source) string {
+ return e.Path
+}
diff --git a/runner/shell/shell.go b/runner/shell/shell.go
index f8e353c..c4513c9 100644
--- a/runner/shell/shell.go
+++ b/runner/shell/shell.go
@@ -99,7 +99,7 @@ func (s *shell) CreateTarget(fs fs.FS, src string, file string, _ fs.DirEntry) (
BaseTarget: runner.BaseTarget{
Identity: identity.New(filename),
MyTags: model.TagsFromFilename(filename),
- Sub: sub,
+ MySub: sub,
},
Shell: shell,
Script: filepath.Join(src, file),
diff --git a/runner/shell/target.go b/runner/shell/target.go
index 189bcb7..9c53617 100644
--- a/runner/shell/target.go
+++ b/runner/shell/target.go
@@ -25,7 +25,7 @@ func (s *Target) Hydrate(_ *model.Source) (model.HydratedTarget, error) {
}
func (s *Target) Sub() []string {
- return s.BaseTarget.Sub
+ return s.BaseTarget.MySub
}
func (s *Target) Label() string {