How-Tos

General

Modify the tutorial for documentation or runtime

Although antithetical to the core promise of this project, sometimes it is unavoidable to run commands differently from how they are rendered in documentation. Examples are commands that read passwords (and avoid reading data from stdin):

parts:
  - commands:
      - command: "{% if doc %}passwd{% else %}sudo sed 's/..../' /etc/shadow{% endif %}"

This will render as:

user@host:~$ passwd

… but in reality will run the sudo command to update the password file directly.

Running commands

Test for installed tools

You can specify a list of tools that is required for running the tutorial. structured-tutorials will then test if a certain tool is installed before starting the tutorial and present the user with a nice error message:

configuration:
  run:
    # Don't even start if git is not installed
    required_executables:
      - git

    # Require db clients only if alternative is selected
    alternatives:
      mariadb:
        required_executables:
          - mariadb
      postgres:
        required_executables:
          - psql
parts:
  - commands:
      - command: git checkout
  # ...

user@host:~$ git checkout

Cleanup after running a tutorial

To cleanup after after running a tutorial, specify a set of cleanup commands:

parts:
  - commands:
      - command: mkdir -p /tmp/new-directory
        run:
          cleanup:
            - command: rm -r /tmp/new-directory

Cleanup commands are not rendered in documentation, so this will simply render as:

user@host:~$ mkdir -p /tmp/new-directory

If multiple cleanup commands are specified, they will run in-order. In case of an error, only cleanup commands for commands that where actually run will be executed. Consider this example:

parts:
  - commands:
      - command: cmd1
        run:
          cleanup:
            - command: clean1
            - command: clean2
      - command: cmd2
        run:
          cleanup:
            - command: clean3

Assuming cmd1 and cmd2 run successfully (or cmd2 exits with a non-zero status code), this will run, in order, clean3, clean1 and clean2. Should cmd1 return a non-zero status code, only clean1 and clean2 will be run.

Skip a part at runtime

To skip an entire part at runtime, but still show it in documentation, simply set run: false:

parts:
  - commands:
      - command: ls /tmp
        doc:
          output: ...
    run: false
    # We could also skip part in documentation instead:
    #doc: false
  - commands:
      - command: ls /etc
        doc:
          output: ...
      # Or we could skip just a command, not the entire part, at runtime:
      - command: ls /tmp
        run: false
        doc:
          output: ...

When running the tutorial, only the first part will run:

user@host:~$ structured-tutorial docs/tutorials/skip-part-run/tutorial.yam
+ ls /etc
...

But when generating documentation, both parts will show, for example, this is part one:

user@host:~$ ls /tmp
...

… and this is part two:

user@host:~$ ls /etc
...
user@host:~$ ls /tmp
...

Documenting commands

Show output

To show an output when rendering commands, specify the output key:

parts:
  - commands:
      - command: echo "example output"
        doc:
          output: "example output"

This will render as:

user@host:~$ echo "example output"
example output

Template context

Both command and output are rendered as template with the current context. The initial context is specified in the global context, and each command can update the context before and after being shown:

configuration:
  doc:
    context:
      user_id: 1000
      path: test.txt
parts:
  - commands:
      # For some reason, compute twice your own user id
      - command: echo "{{ user_id }} * 2" | bc -l > test.txt
        doc:
          update_context:
            contents: 2000
      - command: cat {{ path }}
        doc:
          output: "{{ contents }}"

This will render as:

user@host:~$ echo "1000 * 2" | bc -l > test.txt
user@host:~$ cat test.txt
2000

Update the command prompt

To configure the initial command prompt, set below context variables in the initial context. You can update those variables at any time. The following variables influence the prompt:

prompt

Default: "{{ user }}@{{ host }}:{{ cwd }}{% if user == 'root' %}#{% else %}${% endif %} "

The template used to render the prompt, which includes the values below.

user

Default: "user"

The username rendered in the prompt.

host

Default: "host"

The hostname rendered in the prompt.

cwd

Default: "~"

The current working directory rendered in the prompt.

configuration:
  doc:
    context:
      user: example-user
      host: example-host
      cwd: /tmp
parts:
  - commands:
      - command: sudo su
        doc:
          update_context:
            user: root
      - command: cd /etc
        doc:
          update_context:
            cwd: /etc
      - command: pwd
        doc:
          output: /etc

This will render as:

example-user@example-host:/tmp$ sudo su
root@example-host:/tmp# cd /etc
root@example-host:/etc# pwd
/etc

Skip a part in documentation

To skip an entire part for documentation purposes, but still use it at runtime, you can use the skip configuration:

parts:
  - commands:
      - command: ls /tmp
        doc:
          output: ...
    # We could also skip part at runtime instead:
    #run: false
    doc: false
  - commands:
      - command: ls /etc
        doc:
          output: ...

When running the tutorial, only the first part will run:

user@host:~$ structured-tutorial docs/tutorials/skip-part-run/tutorial.yaml
+ ls /tmp
...
+ ls /etc
...

But when generating documentation, only the first part can be used. Calling structured-tutorial-part a second time will lead to an error (as there are no parts left).

user@host:~$ ls /etc
...