all repos — pls @ 35a3fc34a89656c17c9378404d6fe4e8c09bdf4b

A polite but determined task runner.

Pls_UserGuide.md

 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
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
% pls User Guide
% Fabio Cevasco
% -

## Overview

{{p -> _pls_}} is a simple, general-purpose task runner that aims at making common tasks easier to manage and execute. It was inspired by some of the functionalities provided by the [nifty](https://h3rald.com/nifty) package manager, only without the package manager part.

### Main Features

{{p}} can be used to:

- Define a catalog of {{as -> _actions_}} to perform on {{ts -> _things_}}, which will result in {{cs -> _commands_}} to be executed, each with the same simple syntax.
- Define a catalog of {{ts}}, representing virtually anything that can be the object of a {{sc -> _shell command_}} or referred within other {{ts}}.
- Define a set of {{ds -> _dependencies_}} among {{cs}}, in the form of {{cs}}.
- Manage aliases to commonly-used strings ({{prs -> _properties_}}) to use within other sections of the configuration.

### Hello, World!

Here's minimal but quite comprehensive example of how everything works with {{p}}. Given the following {{cfg}} file (placed in <var>$HOME</var> or in <var>%USERPROFILE%</var> on Windows):

```
things:
  home:
    value: /home/h3rald
  bin:
    value: {{home.value}}/bin
  self:
    value: {{home.value}}/dev/pls
    exe: pls
    nimble: true
actions:
  build:
    nimble+value: cd {\{value}} && nimble build -d:release
  publish:
    exe+value: cd {\{value}} && $(cp "{\{exe}}" "{{bin.value}}") &
deps:
  publish self:
    - build self
```

It will be possible to run the following {{c}} to build the {{p}} program and copy it to the [/home/h3rald/bin](class:dir):

> %terminal%
>
> pls publish self

### Key Concepts

{{p}} is based on a few intuitive abstractions that are used for its configuration, as described in the following sections.

#### Shell Command

A {{sc}} is simply a string that can be passed to the underlying system shell to be executed.

#### Command

A {{c -> _command_}} is an instruction given to {{p}} to execute a {{sc}}. The syntax of a {{c}} is always the following:

_action-identifier_ _thing-identifier-1_ [... _thing-identifier-n_]

> %note%
> {{p}} Commands vs. Shell Commands
>
> The word {{c}} identifies a {{p}} command, while a command executed by the underlying operating system shell is referred to as a {{sc}}.

#### Action

An {{a -> _action_}} identifies something that can be done with one or more {{ts}}. Depending on the {{t}} specified, the {{a}} can be configured to execute a different {{sc}}.

#### Thing

A {{t -> _thing_}} identifies something that can be referenced by an {{a}}. There is virtually no restriction on what a {{t}} may represent: it can be a folder, a file, the name of a running process or service, and so on.

#### Property

A {{pr -> _property_}} identifies a trait of a {{t}}. It can be a simple flag or an attribute defining something about a {{t}} that can be used as part of the identifier of an {{ad}} or referenced via a {{pl}} in {{ads}} and other {{pr}} values.

#### Action Definition

An {{ad -> _action definition_}} is defined by an identifier composed by plus-separated _properties_ (e.g.: git+folder+value), and determines what {{sc}} to execute when a {{c}} is run.

#### Dependency

A {{d -> _dependency_}} identifies a {{c}} that must be executed before another {{c}}. If the {{sc}} executed as a dependency fails, no more {{ds}} will be executed and neither will the {{c}} with the {{ds}}.

#### Placeholder

A {{pl -> _placeholder_}} is a reference to a {{pr}} wrapped in double curly brackets that can be used in {{pr}} values or shell commands.

## Getting Started

### Downloading Pre-built Binaries

{# release -> [pls for $1]({{release}}/dowload/{{$version}}/pls_v{{$version}}_$2.zip)#}

The easiest way to get {{p}} is by downloading one of the prebuilt binaries from the [Github Releases Page]({{release -> https://github.com/h3rald/pls/releases}}):

- {#release||Mac OS X (x64)||macosx_x64#}
- {#release||Windows (x64)||windows_x64#}
- {#release||Linux (x64)||linux_x64#}

### Building from Source

You can also build {{p}} from source, if there is no pre-built binary for your platform.

To do so, after installing the {{nim -> [Nim](https://nim-lang.org)}} programming language, you can:

3. Clone the pls [repository](https://github.com/h3rald/pls).
4. Navigate to the [pls](class:dir) repository local folder.
5. Run **nimble build -d:release**

## Using {{p}}

The first time you run {{p}}, a {{cfg -> [pls.yml](class:file)}} configuration file will be created in your <var>$HOME</var> (<var>%USERPROFILE%</var> on Windows) folder. This YAML configuration file will teach {{p}} everything it needs to know to execute {{cs}} and it will be parsed and processed every time {{p}} is executed.

### Configuring {{p}}

The {{cfg}} file contains three sections:

- **actions**, where each {{a}} is defined.
- **things**, where each {{t}} is defined.
- **deps**, where each {{d}} is defined.

Consider the following sample {{cfg}} file:

<a id="cfg-example"></a>

```
things:
  home:
    value: /home/h3rald
  dev:
    value: {{home.value}}/dev
  bin:
    value: {{home.value}}/bin
  h3:
    value: {{home.dev}}/h3
    npm: true
  self:
    value: {{home.dev}}/{\{exe}}
    conf: {{home.value}}/{\{exe}}.yml
    exe: pls
    nimble: true
actions:
  config:
    conf: vim "{\{conf}}"
  edit:
    value: vim "{\{value}}"
  publish:
    exe+value: cd "{\{value}}" && $(cp "{\{exe}}" "{{bin.value}}") &
  build:
    npm+value: cd "{\{value}}" && npm run build
    nimble+value: cd "{\{value}}" && nimble build -d:release
deps:
  publish self:
    - build self
```

This configuration file should give you an idea of how to configure {{p}} to execute your own custom {{cs}}. In this case, it is possible to execute {{cs}} like:

- pls publish self
- pls config self
- pls edit h3
- pls build self h3

...and so on. Let's see how to configure each section more in detail.

#### Configuring {{ts}}

Keep in mind that a {{t}} is going to be used as the object or target of your {{a}}, so it typically should represent a file, a folder, a URL, a service name, and so on. Also, it makes sense to define new {{ts}} if they are going to be used often in actions or referenced in other {{ts}}. In relation to the [configuration example](#cfg-example), note how the [home](class:kwd) {{t}} is re-used in [dev](class:kwd) and [bin](class:kwd).

A {{t}} is defined by one or more arbitrary {{prs}}. There are virtually no restrictions on what these {{prs}} can represent, but they must fit on one line and they will always be parsed as strings, no matter what the highlighting of your {{cfg}} says. Typically, it makes sense to define a [value](class:kwd) {{pr}} for the {{pr}} that most characterizes the {{t}}, but this is merely a convention, nothing more.

Any {{pr}} of any {{t}} can be reused via a {{pl}}:

- in {{as}}
- in other {{ts}}

> %sidebar%
> Relative vs. Absolute Placeholders
>
> Properties of {{ts}} can be referenced using a relative {{pl}} specifying just the identified of the referenced {{pr}} (e.g. [{\{value}}](class:kwd)) when used within a {{pr}} of the same {{t}} or (within an {{a}}) when referring to the {{t}} matched by an {{a}}.
>
> Otherwise, you can use absolute {{pls -> _placeholders_}} by prepanding the name of the {{t}} followed by a dot, and then the {{pr}} identifier, e.g. [{\{home.value}}](class:kwd).

#### Configuring {{as}}

While {{pr}} identifiers are just straightforward names, {{as}} are identified by a combination of plus-separated {{pr}} identifiers. Each {{a}} can have one or more {{ads -> _action definitions_}}, each specifying a different set of {{pr}} identifiers.

When an action is executed on one or more {{ts}}, {{p}} will try to match the appropriate {{ad}} based on the {{prs}} specified in the {{ad}}. Consider the [build](class:kwd) {{a}} in the [configuration example](#cfg-example); it is possible to run the following {{cs}}:

> %terminal%
>
> pls build self

which will result in [cd /home/h3rald/dev/pls && nimble build -d:release](class:cmd) being executed, and:

> %terminal%
>
> pls build h3

which will result in [cd /home/h3rald/dev/h3 && npm run build](class:cmd).

Note how a different {{ad}} is triggered depending on the {{prs}} of the specified {{t}}. If however you try running the following {{c}}:

> %terminal%
>
> pls build home

nothing will happen, as there is no matching {{ad}} for [home](class:kwd), which only contains a [value](class:kwd) {{pr}}.

> %tip%
> Tip
>
> If several {{ads}} match for the specified {{t}}, the one with the most matching {{prs}} will be used.

#### Configuring {{ds}}

You can use the [dependencies](class:kwd) section to configure {{ds}} among commands. Essentially, for each {{c}} (comprised of an {{a}} followed by one or more {{t}}), you can specify a list comprised of one or more {{cs}} that will be executed beforehand.

In the [configuration example](#cfg-example), executing:

> %terminal%
>
> pls publish self

will cause the [build self](class:cmd) {{c}} to be executed beforehand.

> %note%
> Command execution and dependencies
>
> If {{ds}} are specified for a {{c}}:
>
> - all its {{ds}} are executed sequentially before the {{c}} is executed
> - if one dependent {{c}} fails, no more {{ds}} will be executed, and the {{c}} will not be executed

### Executing {{cs}}

The previous sections already contain a few examples on how to run {{cs}} with {{p}}. Essentially, the syntax is always the same:

[pls _action_ _thing-1_ [..._thing-n_]](class:cmd)

So, for example:

> %terminal%
>
> pls config self

will execute the [config](class:kwd) {{a}} on the [self](class:kwd) {{t}}, and:

> %terminal%
>
> pls build self h3

will execute execute the [build](class:kwd) {{a}} on the [self](class:kwd) {{t}}, and then on the [h3](class:kwd) {{t}}.

There are no built-in {{cs}}, so the first argument specified after {{p}} is interpreted as an {{a}}, and the following ones as things. If no things are specified, an error will be printed.

### Inspecting {{cs}}

If you want to see what {{scs -> _shell commands_}} a particular {{c}} will execute, or how certain {{t}} properties will be matched or used, you can specify the [-i](class:arg) ([\-\-inspect](class:arg)) option to print some diagnostic messages and the resulting shell {{cs}}, without executing them:

> %terminal%
>
> pls build self -i
> . Command: build self
> . Thing: self
> . -> Matching Definition: nimble+value
> . -> Command Definition: cd {\{value}} && nimble build
> . Resolving placeholder: {\{home.value}} -> /home/h3rald
> . Resolving placeholder: {\{dev.value}} -> /home/h3rald/dev
> . Resolving placeholder: {\{self.value}} -> /home/h3rald/dev/pls
> . -> Resolved Command: cd /home/h3rald/dev/pls && nimble build -d:release

> %sidebar%
> Using the [-f](class:arg) ([\-\-full](class:arg)) option
>
> If you specify the [-f](class:arg) together with the [-i](class:arg) option, additional messages will be printed related to the processing of the {{cfg}} file.
> If you specify only the [-f](class:arg) when executing a {{c}}, the resulting {{sc}} will be printed before being executed.

### Displaying {{as}}, {{ts}}, and {{ts}}

If you want to quickly display the {{as}}, {{ts}} or {{ds}} that are available without opening the {{cfg}} file, you can use the [-a](class:arg) ([\-\-actions](class:arg)), [-t](class:arg) ([\-\-things](class:arg)), and [-d](class:arg) ([\-\-deps](class:arg)) respectively. Unless the [-f](class:arg) ([\-\-full](class:arg)) option is specified as well, a simply list of {{as}}, {{ts}}, or {{ds}} will be displayed.

If you specify the [-f](class:arg) ([\-\-full](class:arg)) option as well:

- {{ads}} will be displayed for each {{a}}
- {{prs}} will be displayed for each {{t}}
- dependent {{cs}} will be displayed for each {{d}}

## The {{p}} Configuration YAML Schema

The following schema is based on the [YAML Schema](https://asdf-standard.readthedocs.io/en/latest/schemas/yaml_schema.html#yaml-schema-draft-01) extension of [JSON Schema Draft 4](http://json-schema.org/draft-04/json-schema-validation.html) and describes the configuration of {{cfg}} files.

```
%YAML 1.1
---
$schema: https://h3rald.com/pls/yaml-schema/v1.0.0
id: https://h3rald.com/schemas/pls/metadata-1.0.0
tag: tag:h3rald.com:pls/metadata-1.0.0
title: pls Configuration File
type: object
  properties:
    things:
      type: object
      patternProperties:
        ^[a-z0-9][a-zA-Z0-9_-]+$:
          $ref: #/$defs/thing
    actions:
      type: object
      patternProperties:
        ^[a-z0-9][a-zA-Z0-9_-]+$:
          $ref: #/$defs/action
    deps:
      type: object
      patternProperties:
        ^[a-z0-9][a-zA-Z0-9_-]+)( [a-z0-9][a-zA-Z0-9_-]+)+$:
          $ref: #/$defs/dependencies
required: [things, actions]
additionalProperties: false
$defs:
  thing:
    type: object
    patternProperties:
      ^[a-z0-9][a-zA-Z0-9_-]+$: string
  action:
    type: object
    patternProperties:
      ^[a-z0-9][a-zA-Z0-9_-]+(\+[a-z0-9][a-zA-Z0-9_-]+)*$: string
  dependencies:
    type: array
    items:
      type:
        $ref: #/$defs/command
  command:
    type: string
    pattern: |
      ^[a-z0-9][a-zA-Z0-9_-]+( [a-z0-9][a-zA-Z0-9_-]+)+$
```