comma: upgrade template (#725)

- README.md: delete the content of template and replace it with a link
- comma_test: T/F execute a closure and return a true or false
- comma_tmpl: add example of building image

---------

Co-authored-by: nash <nash@iffy.me>
This commit is contained in:
fj0r 2024-01-05 20:05:07 +08:00 committed by GitHub
parent 0d55be71ea
commit 0632778754
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 205 additions and 127 deletions

View File

@ -1,93 +1,165 @@
# Comma, task and test runner of nu script
Working dir task runner, similar to `pwd-module`, but supports completion and description through custom data formats
- `,` or `*` need to be exported in order to use `,` directly
- Directly execute `,` to create a new template file or edit an existing file
- Custom tasks are written in `$env.comma` and can be nested
- no spaces allowed in name (except testing)
- Generate completions based on the structure of `$env.comma`
- You can use closure to customize completion
- In `$_.act` of default closure, you can receive parameters after the current position
- In `$_.cmp` , you can receive the parameter before the current position
- Supports `computed`, the definition method refers to `$env.comma_scope.computed`, accepts two parameters, runtime parameters and `$env.comma_scope`
- Supports `filter`, similar to `computed`, but only runs when declared, specified through `$_.flt`
- Supports `watch` (and polling), specified through `$_.wth`.
- `glob` defaults to `*`, `op` defaults to `['Write']`, `postpone` defaults to `false`
- In watch mode (not Polling) inject `$_.wth`(op, path, new_path) into parameter `$s`
- when the `interval` field is included, it is polling mode(`clear` defaults to 'false')
- Identity supports alias
- children sub s
- description desc dsc d
- action act a
- completion cmp c
- filter flt f
- computed cpu u
- watch wth w
- tag
- expect exp e x
- mock test_args m
- report rpt r
## Quick Start
`,` or `*` need to be exported in order to use `,` Directly
example:
```
$env.comma_scope = {|_|{
created: '2023-12-24{0}01:46:27'
computed: {$_.computed:{|a, s| $'($s.created)($a)' }}
say: {|s| print $'(ansi $_.settings.theme.info)($s)(ansi reset)' }
quick: {$_.filter:{|a, s| do $s.say 'run a `quick` filter' }}
slow: {$_.filter:{|a, s|
do $s.say 'run a `slow` filter'
sleep 1sec
do $s.say 'filter need to be declared'
sleep 1sec
$'($s.computed)<($a)>'
}}
}}
use comma.nu *
```
When you enter a directory, if a `,.nu` file exists, it will be loaded. (Currently you need to press the Enter key again to take effect)
Or `source` any file that defines `$env.comma_scope` and `$env.comma` variables
If there is no `,.nu` file in the current directory, executing `,` without arguments will create a new one from the template. If the file exists, edit it
### Task Definition
Tasks are written in `$env.comma` and can be nested, and no spaces allowed in name (except testing).
The nodes of the tree can be ordinary records, and the tasks are defined in the closure of the leaf nodes.
This tree will be traversed during completion. For tasks, you can customize the completion behavior.
Customize completion behavior, as well as descriptions, filters, watches, tests, etc. Need to add some special attributes to the record, such as `$_.children`, `$_.action`, `$_.completion` (so `$env.comma` and `$env.comma_scope` accepts a closure to avoid potential naming conflicts).
```
$env.comma = {|_|{
created: {|a, s| $s.computed }
inspect: {|a, s| {index: $_, scope: $s, args: $a} | table -e }
test: {
$_.sub: {
batch: { 'created; inspect' | do $_.batch }
watch: {
$_.action: {|a, s| $s | get $_.watch }
$_.completion: {ls *.json | get name}
$_.desc: 'inspect watch context'
$_.watch: {
glob: '*'
op: ['Write', 'Create']
postpone: true
}
}
open_file: {
$_.action: {|a, s| open $a.0 }
$_.completion: {ls | get name}
$_.desc: 'open a file'
$_.filter: ['slow']
}
ping: {
$_.action: {|a, s| ping -c 2 localhost }
$_.watch: {
interval: 2sec
clear: true
}
}
dev: {
run: {
$_.action: {|a,s| nu $a.0 }
$_.watch: { glob: '*.nu', clear: true }
$_.completion: { ls *.nu | get name }
$_.desc: "develop a nu script"
}
$_.desc: 'run test'
$_.filter: ['quick']
}
}}
```
### todo
These attributes support aliases like:
| attribute | alias |
|-------------|----------------|
| children | sub, s |
| description | desc, dsc, d |
| action | act, a |
| completion | cmp, c |
| filter | flt, f |
| computed | cpu, u |
| watch | wth, w |
| tag | |
| expect | exp, e, x |
| mock | test_args, m |
| report | rpt, r |
The closure of the task's `action`, `completion` accepts two parameters, the rest arguments after the breadcrumbs and `$env.comma_scope`.
`computed` and `filter` are defined in `$env.comma_scope` which is used to share data, alse accept these two parameters.
`computed` is calculated in the defined order and replaced with the result.
```
$env.comma_scope = {|_|{
hello: 'hello'
greet: {$_.computed:{|a, s| $'($s.hello): ($a)' }}
}}
```
`filter` is called when it is declared. If a record is returned, it will be merged back to the $env.comma_scope.
```
$env.comma_scope = {|_|{
log: {$_.filter:{|a, s| do $_.tips 'run filter' `foo` }}
}}
$env.comma = {|_|{
foo: {
$_.sub: {
bar: {
$_.action: { echo 'hello' }
$_.filter: ['log']
}
}
$_.filter: ['log']
}
}}
```
#### Dry run
If execute the command in `$_.action` with `pp`, and pass `--print` flag with `,`, only prints the arguments received by `pp` without actually executing it.
`pp` can be run alone with flag `--print`.
```
pp --print aaa bbbb ccccc dddddd eeeeee [
ffffff gggggggggg [
hhhhhhhhh iiiiiiiiii lllllllll
] mmmmmmmmmmmmm nnnnnnnnnnnn
aaaaaaaaaaaaaaa
xxxxxxxxxxxxxxxx
yyyyyyyyyyyyyyyy
zzzzzzzzzzzzzzz
jjjjjjjjjjjjj
] oooooooo ppppppppp [qqqqqq [rrrrrr ssssss tttttt] uuuuuu]
```
### Watch and polling
If `$_.watch` is defined and run with `--watch` flag, it will be run in watch mode.
```
$env.comma = {|_|{
foo: {
$_.watch: {
glob: '*'
op: ['Write', 'Create']
postpone: true
}
}
}}
```
- `glob` defaults to `*`, `op` defaults to `['Write']`, `postpone` defaults to `false`
- In watch mode (not Polling) inject `$_.watch`(op, path, new_path) into parameter `$s`
- when the `interval` field is included, it is polling mode(`clear` defaults to 'false')
### Test
If run with the `--test` flag, it will detect that all nodes with `$_.expect` under the current and run their actions.
If there is also the --watch flag, it will run in watch mode without defining `$_.watch`.
If `$_.mock` exists, it will be passed as arguments to the `$_.action` and `$_.expect`.
If `$_.expect` is closure, pass it the result of `$_.action`, rest arguments and `$_.comma_scope`, if return True and the test passes.
If `$_.expect` is list, will use the closures in it as a set of tests.
If `$_.expect` is a scalar, it is compared directly with the result of actions.
If `$_.report` exists and the test fails, execute `$_.report` (has a predefined report `$_.diff`)
### vscode-tasks
The default template contains `vscode-tasks` and outputs a `.vscode/tasks.json`.
```
$env.comma = {|_|{
vscode-tasks: {
$_.a: {
mkdir .vscode
', --vscode -j' | do $_.batch ',.nu' | save -f .vscode/tasks.json
}
$_.d: "generate .vscode/tasks.json"
$_.w: { glob: ',.nu' }
}
}}
```
> requires `augustocdias.tasks-shell-input` to run `$_.completion` closure.
## todo
- [x] run
- [ ] dry
- [ ] dry wrap lines
- [ ] accept list<string>
- [x] dry
- [x] dry wrap lines
- [x] accept list<string>
- [x] formatter: outdent
- [x] complete
- [x] with args
- [x] scoped test
- [x] pass scoped
- [x] tree map
- [x] test
- [ ] tag
@ -116,7 +188,6 @@ $env.comma = {|_|{
- [ ] pickString
- [x] augustocdias.tasks-shell-input
- [x] allow rest args as `promptString`
- https://code.visualstudio.com/docs/editor/variables-reference
- [x] clean filter output
- [x] add gen vscode-tasks to template
- [ ] test and watch

View File

@ -1,6 +1,12 @@
export def lg [tag?] {
let o = $in
print -e $'---($tag)---($o | describe)(char newline)($o | to yaml)'
let t = [
$'(ansi xterm_grey)--------(ansi xterm_olive)($tag)(ansi xterm_grey)--------'
$'(ansi xterm_grey39)($o | describe)'
$'(ansi xterm_grey66)($o | to yaml)'
(ansi reset)
]
print -e ($t | str join (char newline))
$o
}
@ -190,7 +196,9 @@ module resolve {
}
for i in ($flts | default []) {
if $i in $flt {
$vs = ($vs | merge {$i: (do ($flt | get $i) $args $vs)} )
let fr = do ($flt | get $i) $args $vs
let fr = if ($fr | describe -d).type == 'record' { $fr } else { {} }
$vs = ($vs | merge $fr)
} else {
error make -u {msg: $"filter `($i)` not found" }
}
@ -770,8 +778,8 @@ export-env {
print -e $"(ansi light_gray_italic)($m.0)(ansi reset) (ansi yellow_bold)($m.1?)(ansi reset)"
}
}
T: { true }
F: { false }
T: {|f| {|r,a,s| do $f $r $a $s; true } }
F: {|f| {|r,a,s| do $f $r $a $s; false } }
I: {|x| $x }
diff: {|x|
use test

View File

@ -65,8 +65,8 @@ $env.comma = {|_|{
'example a b c e': {
$_.act: {, -c example a b c e }
$_.x: [
{|r,a| $r | where value == 'f' | not ($in | is-empty) }
$_.T
{|r,a,s| $r | where value == 'f' | not ($in | is-empty) }
(do $_.T {|r,a,s| $s | lg 'expect'})
{|r,a| 'q1|q2|q3|q4| open a file' == ($r | get 1.description) }
]
}
@ -105,8 +105,8 @@ $env.comma = {|_|{
b: {
$_.sub: {
t1: {
$_.act: $_.T
$_.exp: $_.T
$_.act: { true }
$_.exp: { true }
}
open_file: {
$_.act: {|a, s| open $a.0 }
@ -119,7 +119,7 @@ $env.comma = {|_|{
e: {
$_.sub: {
f: {
$_.act: $_.T
$_.act: { true }
}
open_file: {
$_.act: {|a, s| open $a.0 }
@ -131,8 +131,8 @@ $env.comma = {|_|{
$_.report: $_.diff
}
t3: {
$_.act: $_.T
$_.exp: $_.T
$_.act: { true }
$_.exp: { true }
}
}
$_.dsc: 'ok'
@ -141,8 +141,8 @@ $env.comma = {|_|{
}
}
t2: {
$_.act: $_.T
$_.exp: $_.T
$_.act: { true }
$_.exp: { true }
}
}
$_.dsc: 'this way'
@ -198,15 +198,15 @@ $env.comma = {|_|{
args: [example a b c e]
}
do $_.test 'run test' {
expect: $_.T
expect: { true }
spec: {, -e test example }
}
do $_.test 'run leaf test' {
expect: $_.T
expect: { true }
spec: { , -t example a b t1 }
}
do $_.test 'suit' {
expect: $_.T
expect: { true }
spec: { , -t suit }
}
}
@ -244,7 +244,7 @@ $env.comma = {|_|{
$_.wth: { glob: '*.nu' }
}
complete: {
$_.act: $_.T
$_.act: { true }
$_.wth: { glob: '*.nu' }
}
}

View File

@ -1,14 +1,7 @@
$env.comma_scope = {|_|{
created: '{{time}}'
computed: {$_.computed:{|a, s| $'($s.created)($a)' }}
quick: {$_.filter:{|a, s| do $_.tips 'run filter' `quick` }}
slow: {$_.filter:{|a, s|
do $_.tips 'run filter' `slow`
sleep 1sec
do $_.tips 'filter need to be declared'
sleep 1sec
$'($s.computed)<($a)>'
}}
log_args: {$_.filter:{|a, s| do $_.tips 'received arguments' $a }}
}}
$env.comma = {|_|{
@ -29,36 +22,42 @@ $env.comma = {|_|{
$_.completion: { ls *.nu | get name }
$_.desc: "develop a nu script"
}
watch: {
$_.a: {|a,s| $', dev run ($a.0)' | do $_.batch ',.nu' }
$_.x: {|r,a| false }
$_.m: [,.nu]
$_.c: { ls *.nu | get name }
}
}
test: {
$_.sub: {
batch: { ', created; , inspect' | do $_.batch ',.nu' }
watch: {
$_.act: {|a, s| $s | get $_.watch }
$_.cmp: {ls *.json | get name}
$_.dsc: 'inspect watch context'
$_.wth: {
glob: '*'
op: ['Write', 'Create']
postpone: true
build: {
image: {
$_.a: {|a,s|
^$env.docker-cli pull $a.0
let tmp = mktemp
$"
FROM ($a.0)
RUN apt update \\
&& apt-get upgrade -y \\
&& DEBIAN_FRONTEND=noninteractive \\
apt-get install -y --no-install-recommends \\
curl ca-certificates \\
&& apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/* \\
&& curl -sSL ($a.2) | tar zxf - -C /opt/vendor \\
&& chown -R 33:33 /opt/vendor"
| do $_.outdent
| save -f $tmp
^$env.docker-cli build -f $tmp -t $a.1 .
rm -f $tmp
^$env.docker-cli push $a.1
}
}
ping: {
$_.action: {|a, s| ping -c 2 localhost }
$_.watch: {
interval: 2sec
clear: true
$_.c: {|a,s|
let l = $a | length
if $l < 1 {
['ubuntu', 'alpine', 'nginx']
} else if $l < 2 {
['target']
} else {
['vendor']
}
}
$_.filter: ['slow']
$_.d: 'build docker image'
$_.f: ['log_args']
}
}
$_.desc: 'run test'
$_.filter: ['quick']
}
}}