<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/default.xsl"?>
<fr:tree xmlns:fr="http://www.forester-notes.org" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:xml="http://www.w3.org/XML/1998/namespace" root="false" base-url="/">
  <fr:frontmatter>
    <fr:authors />
    <fr:date>
      <fr:year>2025</fr:year>
      <fr:month>8</fr:month>
      <fr:day>15</fr:day>
    </fr:date>
    <fr:uri>https://shelter.sirref.org/basix-syntax/</fr:uri>
    <fr:display-uri>basix-syntax</fr:display-uri>
    <fr:route>/basix-syntax/</fr:route>
    <fr:title text="Shelterfile Syntax › Basic Syntax "><fr:link href="/shelterfile-syntax/" title="Shelterfile Syntax" uri="https://shelter.sirref.org/shelterfile-syntax/" display-uri="shelterfile-syntax" type="local">Shelterfile Syntax</fr:link> › Basic Syntax </fr:title>
  </fr:frontmatter>
  <fr:mainmatter>
    <html:p><![CDATA[A basic shelterfile will have a series of commands (some which might be]]> <fr:link href="/shelter-0002/" title="Shelter Meta-commands" uri="https://shelter.sirref.org/shelter-0002/" display-uri="shelter-0002" type="local">meta-commands</fr:link><![CDATA[).]]>  Take the following Dockerfile for example:</html:p>
    <html:pre><![CDATA[FROM alpine
COPY hello.txt hello.txt
RUN cat hello.txt > hello2.txt]]></html:pre>
    <html:p>In <fr:link href="https://shelter.sirref.org/shelter/" type="external">Shelter</fr:link>, this can be expressed very similarly.</html:p>
    <html:pre><![CDATA[@ session example1 --image=alpine
@ import file://./hello.txt hello.txt
cat hello.txt > hello2.txt]]></html:pre>
    <html:p>We have had to use two <fr:link href="/shelter-0002/" title="Shelter Meta-commands" uri="https://shelter.sirref.org/shelter-0002/" display-uri="shelter-0002" type="local">meta-commands</fr:link> to achieve the same functionality. The first line creates a fresh session using the <html:code>alpine</html:code> base image.</html:p>
    <html:p>We then <fr:link href="https://shelter.sirref.org/shelter-0006/" type="external">import</fr:link> a file from the local filesystem into our image.</html:p>
  </fr:mainmatter>
  <fr:backmatter>
    <fr:tree show-metadata="false" hidden-when-empty="true">
      <fr:frontmatter>
        <fr:authors />
        <fr:title text="References">References</fr:title>
      </fr:frontmatter>
      <fr:mainmatter />
    </fr:tree>
    <fr:tree show-metadata="false" hidden-when-empty="true">
      <fr:frontmatter>
        <fr:authors />
        <fr:title text="Context">Context</fr:title>
      </fr:frontmatter>
      <fr:mainmatter>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>8</fr:month>
              <fr:day>15</fr:day>
            </fr:date>
            <fr:uri>https://shelter.sirref.org/shelterfile-syntax/</fr:uri>
            <fr:display-uri>shelterfile-syntax</fr:display-uri>
            <fr:route>/shelterfile-syntax/</fr:route>
            <fr:title text="Shelterfile Syntax">Shelterfile Syntax</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Shelterfiles, files with a <html:code>.shl</html:code> extension, are a funny mix of syntax borrowing from Dockerfiles and shell scripts.</html:p>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>8</fr:month>
                  <fr:day>15</fr:day>
                </fr:date>
                <fr:uri>https://shelter.sirref.org/basix-syntax/</fr:uri>
                <fr:display-uri>basix-syntax</fr:display-uri>
                <fr:route>/basix-syntax/</fr:route>
                <fr:title text="Basic Syntax ">Basic Syntax </fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><![CDATA[A basic shelterfile will have a series of commands (some which might be]]> <fr:link href="/shelter-0002/" title="Shelter Meta-commands" uri="https://shelter.sirref.org/shelter-0002/" display-uri="shelter-0002" type="local">meta-commands</fr:link><![CDATA[).]]>  Take the following Dockerfile for example:</html:p>
                <html:pre><![CDATA[FROM alpine
COPY hello.txt hello.txt
RUN cat hello.txt > hello2.txt]]></html:pre>
                <html:p>In <fr:link href="https://shelter.sirref.org/shelter/" type="external">Shelter</fr:link>, this can be expressed very similarly.</html:p>
                <html:pre><![CDATA[@ session example1 --image=alpine
@ import file://./hello.txt hello.txt
cat hello.txt > hello2.txt]]></html:pre>
                <html:p>We have had to use two <fr:link href="/shelter-0002/" title="Shelter Meta-commands" uri="https://shelter.sirref.org/shelter-0002/" display-uri="shelter-0002" type="local">meta-commands</fr:link> to achieve the same functionality. The first line creates a fresh session using the <html:code>alpine</html:code> base image.</html:p>
                <html:p>We then <fr:link href="https://shelter.sirref.org/shelter-0006/" type="external">import</fr:link> a file from the local filesystem into our image.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>8</fr:month>
                  <fr:day>15</fr:day>
                </fr:date>
                <fr:uri>https://shelter.sirref.org/conditionals/</fr:uri>
                <fr:display-uri>conditionals</fr:display-uri>
                <fr:route>/conditionals/</fr:route>
                <fr:title text="Conditionals ">Conditionals </fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Unlike Dockerfiles, we have the possibility to introduce conditionals. Conditionals allow you to check a certain command exits with <html:code>0</html:code> and if so execute the first branch, otherwise execute the second branch.</html:p>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors />
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>8</fr:month>
                      <fr:day>15</fr:day>
                    </fr:date>
                    <fr:title text="Syntax">Syntax</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>The synax is similar to many programming languages' implementation of <html:code>if-then-else</html:code> constructs.</html:p>
                    <html:pre><![CDATA[@ session example2 --image=alpine
apk add node
if (printf "13.0.0\n%s" $(node --version) | sort --version-sort --check=quiet) {
  echo "Node version greater than 13!"
} else {
  echo "Node version less than 13!"
}]]></html:pre>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>8</fr:month>
                  <fr:day>15</fr:day>
                </fr:date>
                <fr:uri>https://shelter.sirref.org/parallel-for/</fr:uri>
                <fr:display-uri>parallel-for</fr:display-uri>
                <fr:route>/parallel-for/</fr:route>
                <fr:title text="Parallel Loops ">Parallel Loops </fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Given Shelter's underlying mergeable structure, it can offer a rather unique model for parallel computation. Tools exist within the shell scripting world for taking scripts and arguments and running them in parallel. For example, <fr:link href="https://www.gnu.org/software/parallel/" type="external">GNU parallel</fr:link> or <fr:link href="https://github.com/quantifyearth/littlejohn" type="external">littlejohn</fr:link>. These tools, like Shelter, use processes for parallelism. Shelter, however, runs the processes in isolation using namespaces which gives us two advantages:</html:p>
                <html:ol>
                  <html:li>
                    <html:p>It ensures that the parallel parts cannot interfere with one another. Each instantiation of the body of the loop starts from the same starting point <![CDATA[(whatever came just before).]]></html:p>
                  </html:li>
                  <html:li>
                    <html:p>Since each loop-body is independent, successful executions are recorded and do not need to be re-run in the event of a partial failure.</html:p>
                  </html:li>
                </html:ol>
                <html:p>After all parts of the loop have completed, the resulting data is <fr:link href="https://shelter.sirref.org/shelter-0009/" type="external">merged</fr:link> and execution continues from there. By providing this as an extra feature, if users do not like these semantics, they can always opt to use a more generic tool for their parallelism too!</html:p>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors />
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>8</fr:month>
                      <fr:day>15</fr:day>
                    </fr:date>
                    <fr:title text="Syntax">Syntax</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>For now, parallel for-loops are rather simplistic.</html:p>
                    <html:pre><![CDATA[for file in [ a.txt, b.txt, c.txt ] {
  echo #file > #file
}]]></html:pre>
                    <html:p>You may introduce a variable, here <html:code>file</html:code>, which will take on the value in your <![CDATA[list. In the commands of the loop-body (between the curly braces) variables are]]>  referenced using <html:code>#</html:code> and will be replaced accordingly.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
      </fr:mainmatter>
    </fr:tree>
    <fr:tree show-metadata="false" hidden-when-empty="true">
      <fr:frontmatter>
        <fr:authors />
        <fr:title text="Backlinks">Backlinks</fr:title>
      </fr:frontmatter>
      <fr:mainmatter />
    </fr:tree>
    <fr:tree show-metadata="false" hidden-when-empty="true">
      <fr:frontmatter>
        <fr:authors />
        <fr:title text="Related">Related</fr:title>
      </fr:frontmatter>
      <fr:mainmatter>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>7</fr:month>
              <fr:day>21</fr:day>
            </fr:date>
            <fr:uri>https://shelter.sirref.org/shelter-0002/</fr:uri>
            <fr:display-uri>shelter-0002</fr:display-uri>
            <fr:route>/shelter-0002/</fr:route>
            <fr:title text="Shelter Meta-commands">Shelter Meta-commands</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>When developing inside Shelter, most commands are sent straight to a shell <![CDATA[of your choice (see]]> <fr:link href="/shelter-0003/" title="Getting Started" uri="https://shelter.sirref.org/shelter-0003/" display-uri="shelter-0003" type="local">how to configure shelter</fr:link><![CDATA[).]]></html:p>
            <html:p>To interact with the meta aspects of Shelter you can prefix your command with <html:code>@</html:code>. If you type just <html:code>@</html:code> then you will get a list of possible commands.</html:p>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>21</fr:day>
                </fr:date>
                <fr:uri>https://shelter.sirref.org/at-session/</fr:uri>
                <fr:display-uri>at-session</fr:display-uri>
                <fr:route>/at-session/</fr:route>
                <fr:title text="@ session ">@ session </fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Sessions are your primary way of controlling different environments. You can think of them as git branches pointing at specific instances of data and code. By default, you will start shelter in the <html:code>main</html:code> session. Sessions <html:em>must</html:em> have <![CDATA[an associate "base image" (by default this is]]> <html:code>alpine</html:code><![CDATA[).]]></html:p>
                <html:pre><![CDATA[@ session experiment-1 --image=debian]]></html:pre>
                <html:p>This command will create a fresh session with no history called <html:code>experiment-1</html:code> using the Debian base image.</html:p>
                <html:pre><![CDATA[@ session --image=debian]]></html:pre>
                <html:p>This is a similar command, but the name will be randomly generated and is ensured to be unique. It is a bit like having a Dockerfile with a <html:code>FROM debian</html:code> at the top.</html:p>
                <html:pre><![CDATA[@ session]]></html:pre>
                <html:p>Will list all the currently available sessions.</html:p>
                <html:pre><![CDATA[@ session exp]]></html:pre>
                <html:p>When no <html:code>--image</html:code> is specified, this will try to switch you into an existing session if one exists, otherwise it will create a new session based on the current session.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>21</fr:day>
                </fr:date>
                <fr:uri>https://shelter.sirref.org/at-undo/</fr:uri>
                <fr:display-uri>at-undo</fr:display-uri>
                <fr:route>/at-undo/</fr:route>
                <fr:title text="@ undo ">@ undo </fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>The <html:code>@ undo</html:code> command will move your session back one commit into the past. You may specify a number of commits to move, for example <html:code>@ undo n</html:code> to move back <html:code>n</html:code> commits. If there are less than <html:code>n</html:code> commits, we will stop going backwards.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>21</fr:day>
                </fr:date>
                <fr:uri>https://shelter.sirref.org/at-how/</fr:uri>
                <fr:display-uri>at-how</fr:display-uri>
                <fr:route>/at-how/</fr:route>
                <fr:title text="@ how ">@ how </fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>The <html:code>@ how &lt;path&gt;</html:code> command allows you to ask <fr:link href="https://shelter.sirref.org/shelter/" type="external">Shelter</fr:link> to explain <html:em>how</html:em> a file came to be. Which executables wrote to the file, and what files did those executables read. This is an approximation to the provenance of a piece of data inside a <fr:link href="https://shelter.sirref.org/shelter/" type="external">Shelter</fr:link> session.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>21</fr:day>
                </fr:date>
                <fr:uri>https://shelter.sirref.org/at-import/</fr:uri>
                <fr:display-uri>at-import</fr:display-uri>
                <fr:route>/at-import/</fr:route>
                <fr:title text="@ import ">@ import </fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>An experimental command for importing arbitrary URIs into <fr:link href="/index/" title="Shelter" uri="https://shelter.sirref.org/index/" display-uri="index" type="local">Shelter</fr:link>.</html:p>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://shelter.sirref.org/Shelter Programmers/" type="external">Shelter Programmers</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>11</fr:month>
                      <fr:day>16</fr:day>
                    </fr:date>
                    <fr:uri>https://shelter.sirref.org/shelter-log-001/</fr:uri>
                    <fr:display-uri>shelter-log-001</fr:display-uri>
                    <fr:route>/shelter-log-001/</fr:route>
                    <fr:title text="Import statements">Import statements</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Welcome to the first <fr:link href="/index/" title="Shelter" uri="https://shelter.sirref.org/index/" display-uri="index" type="local">Shelter</fr:link> log! In this log I will explain the work I have been doing to add an <html:code>@ import</html:code> <fr:link href="/shelter-0002/" title="Shelter Meta-commands" uri="https://shelter.sirref.org/shelter-0002/" display-uri="shelter-0002" type="local">meta-command</fr:link>.</html:p>
                    <html:p>The syntax thus far is relatively straightforward.</html:p>
                    <html:pre><![CDATA[@ import --name=<optional-name> <URI> <DST>]]></html:pre>
                    <html:p>There are a few key principles underlying <html:code>@ import</html:code>.</html:p>
                    <html:ol>
                      <html:li>
                        <html:p>It should be at least as expressive as Docker's <html:code>COPY ...</html:code> command.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>It should deal with a wider variety of import sources. In addition to local <![CDATA[file paths this could be data over HTTP (]]> <html:code>https://</html:code><![CDATA[), git repositories, zip]]>  archives over ssh etc.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Imports, where possible, should be catalogued and shared across <fr:link href="/at-session/" title="Shelter Meta-commands › @ session " uri="https://shelter.sirref.org/at-session/" display-uri="at-session" type="local">sessions</fr:link>.</html:p>
                      </html:li>
                    </html:ol>
                    <fr:tree show-metadata="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://shelter.sirref.org/Shelter Programmers/" type="external">Shelter Programmers</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>11</fr:month>
                          <fr:day>16</fr:day>
                        </fr:date>
                        <fr:title text="URIs as Sources">URIs as Sources</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p><![CDATA[Point (1) can be dealt with by point (2). Indeed, that latest development]]>  branch already allows users to import local files and directories into their session. For example:</html:p>
                        <html:pre><![CDATA[@ import shelter.opam .
opam install . --deps-only --with-test]]></html:pre>
                        <html:p>By allowing arbitrary URIs in the import command, we hope to force users away from downloading data via <html:code>curl</html:code> or python scripts. Lifting these side-effectful imports into <fr:link href="https://shelter.sirref.org/shelter/" type="external">Shelter</fr:link> allows us to manage the data in a much cleaner fashion.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://shelter.sirref.org/Shelter Programmers/" type="external">Shelter Programmers</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>11</fr:month>
                          <fr:day>16</fr:day>
                        </fr:date>
                        <fr:title text="Scripts as Sources">Scripts as Sources</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>One idea I had was to allow users to invoke scripts as there "import source". Something like:</html:p>
                        <html:pre><![CDATA[@ import -- python download_gedi_data.py]]></html:pre>
                        <html:p>And using the same <fr:link href="https://shelter.sirref.org/shelter-tracing/" type="external">eBPF tracing</fr:link> we use during normal execution we can capture a fairly good idea of the tools and files needed to perform an import.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://shelter.sirref.org/Shelter Programmers/" type="external">Shelter Programmers</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>11</fr:month>
                          <fr:day>16</fr:day>
                        </fr:date>
                        <fr:title text="Sharing Imports">Sharing Imports</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>One example of better data management is that <fr:link href="https://shelter.sirref.org/shelter/" type="external">Shelter</fr:link> imports can be <![CDATA[explicitly shared across sessions via the naming mechanism (also by hash).]]></html:p>
                        <html:p>When a user imports some data, they can optionally name that piece of data. For example:</html:p>
                        <html:pre><![CDATA[@ import
  --name=belfast-trees \
  https://www.belfastcity.gov.uk/getmedia/262a1f01-f219-4780-835e-7a833bdd1e1c/odTrees.csv \
  /home]]></html:pre>
                        <html:p><fr:link href="https://shelter.sirref.org/shelter/" type="external">Shelter</fr:link> stores that away and makes a link between the name, the URI and the underlying data. A user may then import the same piece of data into a different session by simply writing:</html:p>
                        <html:pre><![CDATA[@ import --name=belfast-trees /var/lib]]></html:pre>
                        <html:p><![CDATA[The same data is shared (read-only) into this session. By asking for the user's]]>  intent via the naming scheme, it makes it possible to then <html:em>version</html:em> the data and have a means by which to update said data, one could imagine:</html:p>
                        <html:pre><![CDATA[@ update --name=belfast-trees]]></html:pre>
                        <html:p>Which will retry the original URI and see if the data has changed, or if it has not. There is an implicit versioning number that users can specify in the name should they choose to.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
      </fr:mainmatter>
    </fr:tree>
    <fr:tree show-metadata="false" hidden-when-empty="true">
      <fr:frontmatter>
        <fr:authors />
        <fr:title text="Contributions">Contributions</fr:title>
      </fr:frontmatter>
      <fr:mainmatter />
    </fr:tree>
  </fr:backmatter>
</fr:tree>
