aboutsummaryrefslogtreecommitdiff
path: root/README.md
blob: 791f88ca5021d11f47b9b4b1d82c14f0777e0c1a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# cloyster: a shell wrapper for machine-oriented shell scripts

_cloyster_ helps you making small, as portable as possible, single-task focused shell scripts
that are primarily consumed by other scripts or machines.

_cloyster_ provides a portable utilitary functions library to help you be efficient transforming
and manipulating data.

_cloyster_ scripts are called "commands". A good command does a single thing/action
(list something, create an interface, bridge an interface, ...).

Being machine-oriented and automation-oriented, commands accepts arguments as JSON, and return
JSON: this also to easily combine and use commands in commands, filter outputs easily (using `jq`),
pipe them together...

**Base dependencies**: POSIX shell, jq, jo

## Scripting commands

A command is a POSIX shell script, using `/usr/local/libexec/cloyster` as shebang.

It will run in the _cloyster_ environment and has three outputs:

- the standards outputs, stdout and stderr, which acts as usual: unstructured, line based text, automatically
  handled by _cloyster_ and returned as `output`,
- the structured JSON result of your command, set by calling `return_result`, returned as `result`.
- a structured JSON fatal error, set by calling `return_error`, returned as `error`.

### API

* `return_result JSON|JO` exits successfully with a JSON result
* `return_error JSON|JO [exit_code=1]` exists with exit_code and a JSON error
* `args_get [JQ_QUERY=.]` query the arguments using jq

### Utilitary Functions

* `ensure_command_exists BINARY` ensures a binary exists, exits with error if not
* `os_get [KEY=.|jq] [JQ_QUERY]` operating system version (type, name, pretty_name, version, version_id, supported)
* `make_random_identifier [SIZE=32]`
* `date_now_iso_utc`
* `posix_time_microseconds`

### Arguments/Input

Arguments, or inputs to the command, are also passed in JSON. You have three ways of passing the arguments:

* human friendly: `COMMAND arg1=something ...` (uses `jo`),
* escaped json string: `COMMAND '{"something": true}'`
* json wrapped in base64: `COMMAND -b eyJiYW5uZXIiOiJiZWFzdGllIGZvciB0aGUgd2luIn0K`

### Output

```js
{
  "error": null /* Error */,
  "exit_status": 0,
  "command": "./commands/ifconfig-interfaces-list.sh",
  "arguments": {},
  "duration_microseconds": /* microseconds */,
  "started_at_utc": /* ISO8061Z */,
  "finished_at_utc": /* ISO8061Z */,
  "result": /* any */,
  "output": [
    // Output Line
  ]
}
```

Output Line:

```js
{"output": "stdout|stderr", "date":"ISO8061Z", line: "...."}
```

Error:

```js
{
  "type": "execution|command",
  "error": "error_name",
  // Error specific field
}
```

### Reading script from stdin

You can tell _cloyster_ to execute a script from stdin by setting the `-s` or `-` option to `cloyster`:

```sh
cat commands/ifconfig-interfaces-list | cloyster -s
cloyster - <<EOF
json=$(jls --libxo json | jq -r '.["jail-information"].jail | @json')
set_result "${json}"
EOF
```

### Examples

#### Example: `commands/ifconfig-interfaces-names.sh`

```sh
#!/usr/local/libexec/cloyster
echo "stdout something"
>&2 "stderr something"
set_result $(ifconfig | grep -E "^[a-z0-9_]+:" | cut -d ':' -f 1 | jq -nRr '[inputs | select(length>0)] | @json')
```

Run it (piped to `jq` so you beautify JSON output):

```sh
./commands/ifconfig-interfaces-names.sh | jq
```

Result:

```json
{
  "error": false,
  "exit_status": 0,
  "command": "./commands/ifconfig-interfaces-list.sh",
  "arguments": [],
  "duration_microseconds": 67,
  "started_at_utc": "2022-03-22T09:28:51Z",
  "finished_at_utc": "2022-03-22T09:28:51Z",
  "result": ["eth0", "eth1", "lo0"],
  "output": [
    {"output": "stdout", "date":"iso8601 utc", line: "stdout something"},
    {"output": "stderr", "date":"iso8601 utc", line: "stderr something"}
  ]
}
```

## Code guide

meh

* We write POSIX Shell compliant code.
* Use `shellcheck`.
* Variables:
  * are considered private/local if they begin by a `_`
  * are considered public if they are in lowercase
  * are exported/env if they are in uppercase
* Cloyster itself must be portable (POSIX Shell) and should be able to work on macOS, Linux, ...
*