Change working directory
Sometimes you will want to change the working directory where commands are run from. At runtime, this will change the meaning of relatives paths in commands, when rendering documentation, the prompt will show a different working directory.
The working directory can changed using the chdir directive of commands. The value is a path, and is
rendered as a template.
Example
Consider the following tutorial file:
configuration:
run:
context:
WORKDIR: /tmp/run
doc:
context:
WORKDIR: /tmp/docs
parts:
- commands:
- command: cd /tmp/
chdir: /tmp/
- command: ls
doc:
output: "contents of /tmp/..."
- commands:
- command: mkdir {{ WORKDIR }}
run:
cleanup:
- command: rm -r {{ WORKDIR }}
- command: cd {{ WORKDIR }}
chdir: "{{ WORKDIR }}"
- command: ls
doc:
output: "contents of {{ WORKDIR }}..."
The first commands part shows the user how to switch the working directory and run a command there:
user@host:~$ cd /tmp/
user@host:/tmp$ ls
contents of /tmp/...
The second commands part shows the user how to create and switch to another directory, where the path is determined by a context variable:
user@host:/tmp$ mkdir /tmp/docs
user@host:/tmp$ cd /tmp/docs
user@host:/tmp/docs$ ls
contents of /tmp/docs...
… but will run in a random directory at runtime.
chdir and alternatives
Changing the working directory is a bit more tricky with alternatives. At runtime, it is easy to follow the selected alternative and do whatever that alternative specifies. But when rendering documentation, all alternatives are rendered as tabs. Different alternatives might switch to different directories, so which directory should subsequent parts use?
That’s why a chdir directive in an alternative part is discarded after the part when rendering
documentation. If all alternatives switch to the same directory, you can specify chdir also for the
alternative. The following contrived example kind of shows how not to use this feature, but this better
showcases how this works:
# Tutorial that has a foo and a bar alternative, but also uses chdir
parts:
- alternatives:
foo:
commands:
- command: cd /foo
chdir: /foo # discarded for the next part
- command: echo foo
bar:
commands:
- command: cd /bar
chdir: /bar # discarded for the next part
- command: echo bar
# Sets working directory for next part, regardless
# of mode or selected alternative
chdir: /alt
- commands:
- command: ls
The first part renders two alternatives, in this case they even switch to different directories:
user@host:~$ cd /foo
user@host:/foo$ echo foo
user@host:~$ cd /bar
user@host:/bar$ echo bar
But since the alternative specifies chdir: /alt, the next part will use that as working directory:
user@host:/alt$ ls
Switch back to the original working directory
You can also switch back to the original working directory that you started from by setting chdir: false:
parts:
- commands:
- command: cd /tmp
chdir: /tmp
- command: cd
chdir: false
- command: echo back to the start
As you can see, the third command is back in the home directory:
user@host:~$ cd /tmp
user@host:/tmp$ cd
user@host:~$ echo back to the start
Use a true temporary directory at runtime
Since chdir is a template value and update_context and/or output tests (that may update the context)
are run before applying it, the best way is simply use mkdir only at runtime:
configuration:
doc:
context:
WORKDIR: /tmp/docs # set only in docs
parts:
- commands:
- command: mktemp -d
doc: false # do not show mktemp in docs
run:
test:
- regex: "(?P<WORKDIR>.*)" # update context with output
cleanup: # make sure dir is removed in the end
- command: rm -r {{ WORKDIR }}
- command: cd {{ WORKDIR }}
chdir: "{{ WORKDIR }}"
- command: ls
doc:
output: "contents of {{ WORKDIR }}..."
This will show /tmp/docs in documentation:
user@host:~$ cd /tmp/docs
user@host:/tmp/docs$ ls
contents of /tmp/docs...
Switch to a different directory in documentation and at runtime
The best way to do this is to specify a different context for documentation and runtime. The above example already does this.
Why do I have to specify chdir at runtime, even though my command already actually changes it?
Because the command you specify is launched in a subprocess, and the caller (structured-tutorials) has no idea what that subprocess does. Your command is still useful (it shows that switching directory will work), but there is no way to pass this information to the next command.