The SALVE Language

What does a SALVE manifest actually look like? Here we describe the basic format of a manifest file.

Example Manifest

We begin with an example, which will be broken down and explained in the sections below.

file {
    source  "files/bash/bashrc"
    target  "$HOME/.bashrc"
    mode    600
}

directory "$HOME/dircolors" {
    source  "dirs/dircolors"
    action  copy
}

file {
    source  "/etc/passwd"
    target  "/opt/myprog/passwd-clone"
    mode    0440
    user    "admin"
    group   "root"
}

manifest "manifests/vim.manifest"

The Grammar

A manifest is a file containing expressions, e, in the following basic grammar. Some liberties have been taken with notation below.

e := Empty String
   | block_id optional_primary_attr { attrs } e

block_id := "file"
          | "directory"
          | "manifest"

optional_primary_attr := Empty String
                       | value

attrs := Empty String
       | name value attrs

name := namechar name
      | namechar

namechar := alpha
          | digit
          | "_"

value := valuechar value
       | valuechar
       | '"' quotedvalue '"'
       | "'" quotedvalue "'"

quotedvalue := quotedchar quotedvalue
             | quotedchar

quotedchar := valuechar | " "

valuechar := namechar
           | "_" | "-" | "+"
           | "=" | "^" | "&"
           | "@" | "`" | "/"
           | "|" | "~" | "$"
           | "(" | ")" | "["
           | "]" | "." | ","
           | "<" | ">" | "*"
           | "?" | "!" | "%"
           | "#"

Note that this only defines the grammar of acceptable SALVE expressions for the parser. There are further constraints upon what keywords are valid and carry meaning. Those are defined below.

Variables

SALVE supports the use of environment variables in templates. These values will be pulled out of the executing shell's environment, and used to expand the attribute values of blocks in manifests.

There are a small number of exceptions to this.

SUDO_USER is inspected, and if set, used in place of USER. At present, there is no way to specify the real value of USER, regardless of 'sudo' invocation.

SALVE_USER_PRIMARY_GROUP always refers to the primary group of USER, after SUDO_USER substitution.

HOME always refers to the home directory of USER after SUDO_USER substitution. This ensures that HOME always refers to the invoking user's homedir, even if sudo is set to reset the HOME environment variable.

Example

Given the block below

file {
    source  "files/bash/bashrc"
    target  "$HOME/.bashrc"
    mode    600
}

When SALVE is invoked by a user, "user1", with home directory "/home/user1", the value of "target" after expansion is "/home/user1/.bashrc" This holds even when "user1" invokes SALVE with sudo.

Relative Paths

Relative paths are also supported, so that it is not necessary to rely on values like $PWD. Relative paths are always interpreted relative to the root manifest's location. One item on the docket is to make an available override behavior to specify relative paths with respect to the dirname of the manifest containing the relative path.

Example

Given the block below

file {
    source  "files/bash/bashrc"
    target  "$HOME/.bashrc"
    mode    600
}

if SALVE is invoked as salve -m /tmp/myconf/root.manifest, then the value of "source" after expansion is "/tmp/myconf/files/bash/bashrc"

Primary Attributes

Primary Attributes are specified immediately after the block type, and are attribute values, as in manifest "manifests/vim.manifest". They have different semantics depending on the type of block being used. In the case of file and directory blocks, the primary attribute is the "target" or file or directory to create or copy over, while in the case of manifest blocks it is the "source" or manifest whose contents should be read.

Primary Attributes are assigned to the block being parsed as though they were specified explicitly with their matching attribute name. In other words,

manifest "manifests/vim.manifest"

is exactly the same as writing

manifest {
    source "manifests/vim.manifest"
}

Definitions

Each attribute of a block has a specific meaning, and many of the values themselves are keywords referring to specific actions. Knowing these meanings is key to reading and understanding a manifest. Below are the definitions of each manifest action, given in a subscript notation. For example, file[action] specifies the 'action' attribute of 'file' blocks.

file[action]

Specifies what the file block does.

  • file[action]=copy -- The copy action copies file[source] to file[target]
  • file[action]=create -- The create action touches file[target]

file[mode]

Is the umask (given in the typical octal notation) to be set on the file specified by file[target].

file[user], file[group]

These are set via chmod whenever SALVE is invoked as root. Otherwise, they do nothing.

  • file[user] -- The owner of file[target].
  • file[group] -- The owning group of file[target].

file[source], file[target]

The paths to files specified by the block. Typically the target is a location on the filesystem being configured, and the source is a file versioned in the SALVE repository being used to modify the target.

file[backup_dir], file[backup_log]

The backup_dir holds backups of any files that have destructive operations performed on them by the block. The backup_log records all backups that are performed.

  • file[backup_dir] -- The path to the directory in which file backups are stored
  • file[backup_log] -- The path to the file to which backup actions are logged (date, hash, full path to file)

manifest[source]

The path to the manifest that is expanded at this location.

directory[action]

  • directory[action]=create -- Create the directory at directory[target], and any required ancestors
  • directory[action]=copy -- Create the directory at directory[target], and then recursively copy contents from directory[source] to directory[target]

directory[mode]

Is the umask (given in the typical octal notation) to be set on the directory specified by directory[target].

directory[user], directory[group]

These are set via chmod whenever SALVE is invoked as root. Otherwise, they do nothing.

  • directory[user] -- The owner of directory[target].
  • file[group] -- The owning group of directory[target].

directory[source], directory[target]

The paths to directories specified by the block. Typically the target is a location on the filesystem being configured, and the source is a directory versioned in the SALVE repository being used to modify the target. When only one path exists, it is typically the target.

directory[backup_dir], directory[backup_log]

The backup_dir holds backups of any files that have destructive operations performed on them by the block. The backup_log records all backups that are performed.

  • file[backup_dir] -- The path to the directory in which file backups are stored
  • file[backup_log] -- The path to the file to which backup actions are logged (date, hash, full path to file)
Site tested on Firefox and Chrome.