summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md45
-rw-r--r--cache/cache.go2
-rw-r--r--main.go25
-rw-r--r--menu/menu.go4
-rw-r--r--model/new.go11
-rw-r--r--runner/just/just.go7
6 files changed, 64 insertions, 30 deletions
diff --git a/README.md b/README.md
index c2fdb89..a03559b 100644
--- a/README.md
+++ b/README.md
@@ -4,25 +4,42 @@ pik
> file-based task runner
+## the goal
+
+are you ever uncertain what to do after cloning a repository? `pik` aims to fix this by making tasks findable,
+predictable and programmable.
+
+running `pik` in a supported repository will index its own file-based task system, as well as
+
+## getting started
+
+1. create a `.pik` folder in your project
+2. put a script in there, for example: `.pik/build.sh` containing `go build .`
+3. you can now access this script from almost anywhere by calling `pik build`. If you want to trigger a specific
+ projects build, specify `pik project build`, where `project` is the folder name.
+
## current features
-* run targets by their approximate name: `uwu build` will trigger `.uwu/build.sh`, or `.uwu/build.py`, or `make build` depending on what's possible.
- * including external targets from `just`
-* specify source names to search for the target in that source explicitly: `uwu myproject build` can run `../../myproject/.uwu/build.sh`
+* run targets by their approximate name: `uwu build` will trigger `.uwu/build.sh`, or `.uwu/build.py`, or `make build`
+ depending on what's possible.
+ * including external targets from `just`
+* specify source names to search for the target in that source explicitly: `uwu myproject build` can
+ run `../../myproject/.uwu/build.sh`
* unless overridden, targets will run in the directory where the `.uwu` folder resides.
* use `--all` flag to start out-of-tree targets without having to navigate to the directory.
* `--here` to run the target in the current working directory instead of the source directory.
- * `--at` to run the target in an arbitrary location
+ * `--at` to run the target in an arbitrary location
* target tags in filenames which trigger flag behaviours
* aliases to sources through the `.alias` file
* tui for viewing and running targets
* y/n confirmation with yes as default
- * will be used if we have an uncertain target guess
- * `--yes` to automatically confirm y/n prompts
+ * will be used if we have an uncertain target guess
+ * `--yes` to automatically confirm y/n prompts
* autoload .env files
- * both the project root and `.pik` folder will be searched
- * values specified with `--env` will be tried as pre- and suffixes: `--env asdf` will load `.env-asdf` and `asdf.env` if they exist.
- * env files are reread for every trigger, meaning you can have a pre-trigger fetch credentials and save it in .env
+ * both the project root and `.pik` folder will be searched
+ * values specified with `--env` will be tried as pre- and suffixes: `--env asdf` will load `.env-asdf`
+ and `asdf.env` if they exist.
+ * env files are reread for every trigger, meaning you can have a pre-trigger fetch credentials and save it in .env
* create any kind of target: high-level support for shell and python, and arbitrary shells with the shebang.
## planned features
@@ -32,12 +49,12 @@ time to catch up with all the features it used to have. This list is not exhaust
attach to these features.
* runner for executable files
- * this will also enable arbitrary shells like node by way of the shebang
+ * this will also enable arbitrary shells like node by way of the shebang
* indexers for other target types such as `make` and `npm`
* expand tui:
- * adding descriptions to targets based on the first comment in a target
- * support for categories and ordering of targets through the `.order` file
- * search
- * more hotkeys (filter jumping, toggle all, etc.)
+ * adding descriptions to targets based on the first comment in a target
+ * support for categories and ordering of targets through the `.order` file
+ * search
+ * more hotkeys (filter jumping, toggle all, etc.)
* git pre-commit and pre-push triggers
* linking sources together by `.include` and `.wants` files
diff --git a/cache/cache.go b/cache/cache.go
index b57d8b8..ae2d081 100644
--- a/cache/cache.go
+++ b/cache/cache.go
@@ -104,7 +104,7 @@ func Save(s *model.State) error {
return os.WriteFile(Path, []byte(c.String()), os.ModePerm)
}
-func LoadState(f fs.FS, cache Cache, indexers []model.Indexer, runners []model.Runner) (*model.State, error) {
+func LoadState(f fs.FS, cache Cache, indexers []model.Indexer, runners []model.Runner) (*model.State, []error) {
var locs []string
for _, e := range cache.Entries {
locs = append(locs, e.Path)
diff --git a/main.go b/main.go
index 4b0dcee..cc8275e 100644
--- a/main.go
+++ b/main.go
@@ -60,21 +60,22 @@ func main() {
panic(err)
}
var st *model.State
- var stateError error
+ var stateErrors []error
if !*flags.All {
- st, stateError = model.NewState(fs, locs, indexers, runners)
+ st, stateErrors = model.NewState(fs, locs, indexers, runners)
} else {
c, err := cache.Load()
if err != nil {
panic(err)
}
- st, stateError = cache.LoadState(fs, c, indexers, runners)
+ st, stateErrors = cache.LoadState(fs, c, indexers, runners)
}
- if stateError != nil {
- panic(stateError)
+ if stateErrors != nil {
+ spool.Warn("%v\n", stateErrors)
+ } else {
+ err = cache.Save(st)
}
- err = cache.Save(st)
if err != nil {
_, _ = spool.Warn("%v", err)
}
@@ -84,11 +85,13 @@ func main() {
if len(args) == 0 {
source, target, err := menu.Show(st, hydrators)
if err != nil {
- panic(err)
+ spool.Warn("%v\n", err)
+ os.Exit(1)
}
err = run.Run(source.Source, target, args...)
if err != nil {
- panic(err)
+ spool.Warn("%v\n", err)
+ os.Exit(1)
}
return
@@ -99,7 +102,8 @@ func main() {
err := pflag.Set("all", "true")
ForceConfirm = true
if err != nil {
- panic(err)
+ spool.Warn("%v\n", err)
+ os.Exit(1)
}
main()
return
@@ -119,6 +123,7 @@ func main() {
err = run.Run(src, target, args...)
if err != nil {
- panic(err)
+ spool.Warn("%v\n", err)
+ os.Exit(1)
}
}
diff --git a/menu/menu.go b/menu/menu.go
index 232a837..7f71e2d 100644
--- a/menu/menu.go
+++ b/menu/menu.go
@@ -8,8 +8,12 @@ import (
)
var WrongModelTypeError = errors.New("wrong model type")
+var NoSourcesIndexedError = errors.New("no sources indexed")
func Show(st *model.State, hydrators []model.Hydrator) (*model.HydratedSource, model.HydratedTarget, error) {
+ if len(st.Sources) == 0 {
+ return nil, nil, NoSourcesIndexedError
+ }
md := NewModel(st, hydrators)
program := tea.NewProgram(md)
resultModel, err := program.Run()
diff --git a/model/new.go b/model/new.go
index f26bc8f..41086c2 100644
--- a/model/new.go
+++ b/model/new.go
@@ -7,7 +7,8 @@ import (
"strings"
)
-func NewState(f fs.FS, locations []string, indexers []Indexer, runners []Runner) (*State, error) {
+func NewState(f fs.FS, locations []string, indexers []Indexer, runners []Runner) (*State, []error) {
+ var errs []error
st := &State{}
for _, loc := range locations {
_, dirName := filepath.Split(loc)
@@ -26,11 +27,13 @@ func NewState(f fs.FS, locations []string, indexers []Indexer, runners []Runner)
s, err := fs.Sub(f, loc)
if err != nil {
- return nil, err
+ errs = append(errs, err)
+ continue
}
targets, err := indexer.Index("/"+loc, s, runners)
if err != nil {
- return nil, err
+ errs = append(errs, err)
+ continue
}
src.Targets = append(src.Targets, targets...)
}
@@ -41,5 +44,5 @@ func NewState(f fs.FS, locations []string, indexers []Indexer, runners []Runner)
}
- return st, nil
+ return st, errs
}
diff --git a/runner/just/just.go b/runner/just/just.go
index e574536..a800212 100644
--- a/runner/just/just.go
+++ b/runner/just/just.go
@@ -1,6 +1,7 @@
package just
import (
+ "errors"
"io/fs"
"os/exec"
"pik/identity"
@@ -83,9 +84,13 @@ func ParseOutput(input string) []model.Target {
return result
}
+var NoJustError = errors.New("no just in $PATH but source contains justfile")
+
func (j *just) findJust() error {
loc, err := exec.LookPath("just")
- if err != nil {
+ if errors.Is(err, exec.ErrNotFound) {
+ return NoJustError
+ } else if err != nil {
return err
}
j.path = loc