Overview

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 package manager, only without the package manager part.

Main Features

pls can be used to:

Hello, World!

Here’s minimal but quite comprehensive example of how everything works with pls. Given the following pls.yml file (placed in $HOME or in %USERPROFILE% 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 command to build the pls program itself and copy it to the /home/h3rald/bin:

pls publish self

Key Concepts

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

Shell Command

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

Command

A command is an instruction given to pls to execute a shell command. The syntax of a command is always the following:

action-identifier thing-identifier-1 [… thing-identifier-n]

pls Commands vs. Shell Commands

The word command identifies a pls command, while a command executed by the underlying operating system shell is referred to as a shell command.

Action

An action identifies something that can be done with one or more things. Depending on the thing specified, the action can be configured to execute a different shell command.

Thing

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

Property

A property identifies a trait of a thing. It can be a simple flag or an attribute defining something about a thing that can be used as part of the identifier of an action definition or referenced via a placeholder in action definitions and other property values.

Action Definition

An action definition is defined by an identifier composed by plus-separated properties (e.g.: git+folder+value), and determines what shell command to execute when a command is run.

Dependency

A dependency identifies a command that must be executed before another command. If the shell command executed as a dependency fails, no more dependencies will be executed and neither will the command with the dependencies.

Placeholder

A placeholder is a reference to a property wrapped in double curly brackets that can be used in property values or shell commands.

Getting Started

Downloading Pre-built Binaries

The easiest way to get pls is by downloading one of the prebuilt binaries from the Github Releases Page:

Building from Source

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

To do so, after installing the Nim programming language, you can:

  1. Clone the pls repository.
  2. Navigate to the pls repository local folder.
  3. Run nimble build -d:release

Using pls

The first time you run pls, a pls.yml configuration file will be created in your $HOME (%USERPROFILE% on Windows) folder. This YAML configuration file will teach pls everything it needs to know to execute commands and it will be parsed and processed every time pls is executed.

Configuring pls

The pls.yml file contains three sections:

Consider the following sample pls.yml file:

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 pls to execute your own custom commands. In this case, it is possible to execute commands like:

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

Configuring things

Keep in mind that a thing is going to be used as the object or target of your action, so it typically should represent a file, a folder, a URL, a service name, and so on. Also, it makes sense to define new things if they are going to be used often in actions or referenced in other things. In relation to the configuration example, note how the home thing is re-used in dev and bin.

A thing is defined by one or more arbitrary properties. There are virtually no restrictions on what these properties can represent, but they must fit on one line and they will always be parsed as strings, no matter what the highlighting of your pls.yml says. Typically, it makes sense to define a value property for the property that most characterizes the thing, but this is merely a convention, nothing more.

Any property of any thing can be reused via a placeholder:

Configuring actions

While property identifiers are just straightforward names, actions are identified by a combination of plus-separated property identifiers. Each action can have one or more action definitions, each specifying a different set of property identifiers.

When an action is executed on one or more things, pls will try to match the appropriate action definition based on the properties specified in the action definition. Consider the build action in the configuration example; it is possible to run the following commands:

pls build self

which will result in cd /home/h3rald/dev/pls && nimble build -d:release being executed, and:

pls build h3

which will result in cd /home/h3rald/dev/h3 && npm run build.

Note how a different action definition is triggered depending on the properties of the specified thing. If however you try running the following command:

pls build home

nothing will happen, as there is no matching action definition for home, which only contains a value property.

Tip

If several action definitions match for the specified thing, the one with the most matching properties will be used.

Configuring dependencies

You can use the dependencies section to configure dependencies among commands. Essentially, for each command (comprised of an action followed by one or more thing), you can specify a list comprised of one or more commands that will be executed beforehand.

In the configuration example, executing:

pls publish self

will cause the build self command to be executed beforehand.

Command execution and dependencies

If dependencies are specified for a command:

  • all its dependencies are executed sequentially before the command is executed
  • if one dependent command fails, no more dependencies will be executed, and the command will not be executed

Executing commands

The previous sections already contain a few examples on how to run commands with pls. Essentially, the syntax is always the same:

pls action thing-1 […thing-n]

So, for example:

pls config self

will execute the config action on the self thing, and:

pls build self h3

will execute execute the build action on the self thing, and then on the h3 thing.

There are no built-in commands, so the first argument specified after pls is interpreted as an action, and the following ones as things. If no things are specified, an error will be printed.

Inspecting commands

If you want to see what shell commands a particular command will execute, or how certain thing properties will be matched or used, you can specify the -i (--inspect) option to print some diagnostic messages and the resulting shell commands, without executing them:

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

Displaying actions, things, and things

If you want to quickly display the actions, things or dependencies that are available without opening the pls.yml file, you can use the -a (--actions), -t (--things), and -d (--deps) respectively. Unless the -f (--full) option is specified as well, a simply list of actions, things, or dependencies will be displayed.

If you specify the -f (--full) option as well:

The pls Configuration YAML Schema

The following schema is based on the YAML Schema extension of JSON Schema Draft 4 and describes the configuration of pls.yml 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_-]+)+$