Complete Guide to Calculate Templates

Updated 5 November 2026

Introduction

Traditionally, in Linux distributions application settings are stored in text files, as a rule in the /etc directory, less often in /var. The formats of such configuration files vary: from simple variable=value to more complex C-like constructs, or ones written in XML.

A seemingly simple approach provides exceptional stability in application operation, since only the filesystem is responsible for keeping the settings safe.

Different Linux distributions, as a rule, offer their own programs for configuring applications. Unfortunately, this approach has an undeniable advantage in convenience but also a number of drawbacks:

  • the user is tied to a specific configuration program (the distribution);

  • the number of settings is, as a rule, limited by the program interface;

  • direct editing of settings becomes difficult, because the program rewrites the file when changes are made.

Specifics of working with templates

In the Calculate utilities 2 and 3, the approach to templates has been substantially reworked and differs from the first version in several ways:

  • The main method of transferring templates is appending them to the system configuration files. At the same time, all popular file formats are supported.

  • A template is merged with a configuration file through conversion to the XML format. The template file format may differ from that of the configuration file.

  • A template file may contain a header describing the merge methods.

  • The names of built-in variables have been renamed according to type.

Installation templates

The Calculate program replaces direct editing of configuration files with template creation.

File formats

Depending on the data storage method, template files can have one of the listed formats:

  • apache, kde, bind, postfix, proftpd, samba, procmail, ldap, dovecot, xml_xfce, xml_xfcepanel, xml_gconf, xml_gconf_tree, compiz, plasma, squid, dhcp, openrc, kernel, json, world - configuration file formats of common applications

  • bin - binary file format

  • raw - raw text

  • patch - a template for applying regular expressions (uses the special patch merge method).

  • diff - a template for applying patches obtained with the diff command

  • dconf - a file for modifying settings in the user's dconf service

  • ldif - a text format for representing directory service records or their changes

  • contents - a specialized format for changing which package a file belongs to

  • backgrounds - a specialized format for creating background images

  • sqlite - a format for modifying the contents of SQLite databases; the engine accepts this format: the template body is run as an SQL script, so an invalid query returns a warning from the SQLite interpreter (for example, near "BODY": syntax error on a body of SELECT 1;). Like the other executable formats, it requires the patch merge method: # Calculate format=sqlite append=join … is rejected.

For the kde format, the '-', '+' parameters for elements inside a section are not processed.

Parameter names in the openrc format are case-insensitive.

The ldif format is available only if the Calculate utilities' ldap module is present. Without env=, the header does not pass with this module: Wrong header parameter 'format=ldif' in template; with env=ldap on a system without the module, the template is omitted without an error message.

The dconf format is available in user profile configuration templates, if the gnome-base/dconf package is present. The package alone is not enough: dbus-run-session and su are also needed, otherwise the template ends with the message The 'dconf' format is unavailable.

Control elements

Besides the service settings written in the program's original format, template files contain control records, which can be roughly divided into several types.

Variable

A variable is a named text element in a template that is replaced by a value in the corresponding configuration file.

A variable has a name, a value and a scope.

  • name - Latin letters and digits

  • value - the replacement text (created in the program)

  • scope - applies globally to all templates or locally to one

Variables are divided into template variables and function variables.

Template variables have a global scope, that is, any template variable available to the program can be used in any template. The value of a variable cannot be changed in a template.

Function variables can be created in a template; the value of a variable can also be changed in a template. The scope of a function variable is the current template.

To pass function variable values from the current template to another template, the template function variable stack (LIFO) is used: the push() template function writes a value from the current template into it, and the pop() template function retrieves the value in another template. Note: only the value goes to the other template. The name created by pop() belongs to the receiving template and is already unavailable in a third template, so you need to read the stack in the same file where you are going to use the variable.

Template function variable stack

A stack (LIFO - "last in, first out") for storing function variable values. Available globally to all templates; the template functions push() - write and pop() - read are used. Writing and reading are possible both in the same template and in different ones.

A header is a template control record which defines how the template will be merged into the system. The template header is written as the first line of the file and has the following form:

# Calculate parameter1=value1 parameter2 [parameter3=value3 ...]

The header content can be split into lines. In this case, each header line except the last must end with the "\" character (backslash).

If the header is absent, the template file settings are determined from the default values.

Allowed parameters:
Format

  • format=[...] - the format of the template file (see file formats). By default, the template file format is determined as raw, or bin for files containing binary data.

  • comment=[.] - the line comment start marker (example: #).

Merging

  • append=[join|before|after|replace|remove|skip|patch|clear] - the merge method. By default, the merge method is set according to the file format. If append=skip, the template is omitted. If append=clear, in the case of a file template the configuration file is cleared - file length 0, and in the case of a directory template all files and directories inside the configuration directory are deleted.

  • force - delete existing files before writing the configuration file. The rule applies by default if the symbolic parameter is specified.

  • link=path - the file from which the template text is taken instead of the template file itself: the engine reads the specified file as a template and writes the result to the target set by path and name. Therefore, the template file's own lines are not used when link= is specified. By default, the content is taken from the template itself. Support for the parameter for a directory template: all files, symlinks and directories from the directory specified by link are copied into the created directory. link for a directory supports only two append types: join and replace. When using replace, files from the target directory are deleted before copying. Example: link=/etc/conf.d/net.example

  • path=path - the path to the directory that will contain the configuration file

  • name=name - the name of the configuration file

  • mirror - perform the merge only if the configuration file exists. If the configuration file is set by the link parameter and it does not exist, the target file is deleted.

  • protected - protect the file when the package it belongs to is removed.

  • symbolic - create a symlink to the file specified by the link parameter.

  • autoupdate - when any package is installed, a special cl-update-config script is launched, which applies the templates for the package being installed. The configuration files of the package being installed are protected. In other words, when a package is installed, if such a file already exists in the system and has been modified, it will not be replaced. The configuration files of installed packages are replaced with the dispatch-conf command. If the template header contains the autoupdate parameter, then after the template is applied the configuration file will be copied into the system. If the parameter is missing, you must use dispatch-conf to transfer the modified configuration file.

  • run - the shell for running the configuration file obtained from the template. The script runs immediately after this template is processed. Example: run=/bin/bash

  • exec - the shell for running the configuration file obtained from the template. The script is added to a queue that runs after all non-executable templates have been processed. Example: exec=/bin/bash. The queue is processed on the engine's second pass, so in a single pass the exec= script is not run; neither run= nor exec= leaves the configuration file on disk.

  • env - use the variables of the specified module in the template. If the module is absent from the system, the template will be omitted. Example: env=install. The template is omitted without an error message. Not all allowed header parameters are listed: module= is also accepted.

  • subvolume - apply to directory templates: if the configuration directory is missing and is being created, create it as a btrfs subvolume. The parameter is specified without a value. Parent directories are created as regular directories (recursively); the subvolume is created only for the template directory itself; nested template directories with subvolume form nested subvolumes. Example: "# Calculate subvolume"

Actions

  • merge - configure the listed packages at the end. Example: merge=openrc,grub (packages must be specified together with the category merge=sys-apps/openrc,sys-boot/grub)

  • postmerge - configure the listed packages at the end. Unlike merge, the packages will be configured after pkg_postinst() during the package build. Example: "postmerge=sys-apps/openrc,sys-boot/grub"

  • stop, start, restart - stop/start/restart the services specified, separated by commas. For a file template, the service action will run immediately after the template is merged; for a directory template, the service action will run immediately after all nested templates are processed. Example: restart=consolefont,keymap

  • rebuild - lower the package version for its subsequent rebuild during the system update. Specifying slots and package versions is supported.

Access rights

  • chmod=XXX - the rights of access to the targeted file (example: "644"). By default, the rights match those of the original file. If it is absent, the rights match those of the template file.

  • chown=user:group - the owner and/or group of the targeted file (example: "root:root").

Conditions

  • variable[>|<|==|!=|>=|<=]value ... - the conditions for transferring the template file into the system. Arithmetic operations can be combined with the "AND" (&) condition (for calculate-lib>=2.2, the "AND" (&&) condition) and the "OR" (||) condition. In this case, the AND condition takes precedence. Several conditions separated by a space are combined with the "AND" condition; if one of the conditions is not met, the rest will not be evaluated. Thus cl_ver>=3.5 os_linux_shortname==CLDX||os_linux_shortname==CLD is handled as cl_ver>=3.5 AND (os_linux_shortname==CLDX OR os_linux_shortname==CLD).
Tags

You can configure the system based on the computer's hardware requirements, network settings and other conditions. To do this, in the template file you can set tags of variables instead of constant values.

Example of the /etc/conf.d/hostname file:

HOSTNAME="#-os_net_hostname-#"

To use variables from another module, specify the module before the variable, separated by a dot:

Example:

#-install.os_install_root_dev-#
Conditional blocks

A template file can contain conditional blocks.

Conditional blocks - highlighted template text that is substituted when a regular expression matches.

Regular expression - a method for checking the values of expressions. The following data types can be used as values:

  • variables - built-in Calculate variables.

  • numbers - integer and fractional numbers, with a dot "." as the fractional separator.

  • strings - letters, digits, special characters.

  • version numbers - numbers and one or two dots separating the version number (for example, 8.5.1).

  • version ranges - two version numbers separated by a comma

The checking method is an arithmetic operation >, <, ==, !=, >=, <= (greater than, less than, equal to, not equal to, greater than or equal to, less than or equal to). The data type is determined before the comparison operation.

You can also check whether a version falls within a range. The check uses the following operators:

  • == - the version is >= the lower value and the version is <= the higher value

  • <= - the version is > the lower value and the version is <= the higher value

  • => - the version is >= the lower value and the version is < the higher value

  • <> - the version is > the lower value and the version is < the higher value

  • != - the version is not in the specified range

Example:

The version of the utilities is greater than or equal to 3.3 and less than 4
#?pkg(sys-apps/calculate-utils)=>3.3,4#

Arithmetic operations can be combined with the "AND" (&) condition and the "OR" (||) condition. In this case, precedence will be given to the "AND" condition.

The block must have a closing tag, and for a function in the condition the tag is the function name - #pkg#; without it the engine reports Cannot find closing tag #pkg# and the file remains empty, so the example above is incomplete. With the closing tag, the operators ==, <=, =>, <> and != work exactly as described above, including in the file header. An "else" branch is also possible: #!pkg#.

A conditional block must begin with the tag "#?variable1==value1(...)#" and end with "#variable1#", both written at the beginning of a line.

Example of a conditional block in the /etc/make.conf file:

#?os_arch_march==i686&&os_linux_shortname==CLD#
   CFLAGS="-O2 -march=i686 -pipe" 
   CHOST="i686-pc-linux-gnu" 
#os_arch_march#

In the given example, the setup_march and setup_sys_shortname variables are compared with the string values "i686" and "CLD" respectively. If the values of both variables match, the block text will be substituted into the resulting file.

As written, the block does not work: os_arch_march is not defined in the system configuration context, the engine reports Variable os_arch_march not found and the file comes out empty; the setup_march and setup_sys_shortname variables do not exist at all. The same construct works with variables that really do exist: #?os_linux_shortname==CLD&&os_net_hostname==box# ... #os_linux_shortname# substitutes the block text.

Functions

Functions serve to build complex files that require calculation during processing. Like variables, functions are inserted into the template text with the "#-function()-#" construct.

Functions that take a file path in their arguments (path) can use the user home directory ~

In addition to those listed, the administrator can define their own functions - as a file in the <location>/scripts/functions/ directory, where <location> comes from /etc/portage/repos.conf. A custom function takes precedence over a built-in one: when names match, the call goes to your file instead of the utilities code, so the list below describes built-in names and is not exhaustive - if a function behaves differently from what is stated here, check whether it has been overridden (how to write one - in Custom template functions in an overlay).

Available functions:

belong - (not used) - the purpose is the same as merge, except that it works only with the package name, ignoring the category.

merge([category/pkg_name]) - checks the name of the package being installed, if a package is being installed. In all other cases, the function will return a positive result.

category - the package category.

pkg_name - the package name.

If the function has no argument, the package name becomes the template name (for directories, the directory name), and the category becomes the parent directory. If the category name or the package name contains a version and/or a sorting number (20-mc,40-xfce-4.6), they are dropped.

Examples:
sys-apps/15-portage-2.2/.calculate_directory, category=sys-apps,pkg_name=portage
sys-fs/udev, (portage file), category=sys-fs,pkg_name=udev

The result depends on the value of the template variable cl_merge_pkg (in versions below 3.1.1, cl_belong_pkg)

  • значение cl_merge_pkg - '' результат '1', независимо от того, есть или нет аргумент у функции

  • значение cl_merge_pkg - 'имя_пакета' если совпадают значения cl_merge_pkg и аргумента функции, результат - '1' иначе ''

  • if the function has no argument, the value of cl_merge_pkg is compared with the name of the directory in which the template with the merge() function is located; on a match, the result is '1' otherwise ''

When templates run to modify package source code (ac_install_patch), the function returns the version number instead of 1 on a positive result.

Example. Template1 header:

# Calculate merge(sys-auth/nss_ldap)!=

Template2 header:

# Calculate merge(kde-libs/kdm)!=

  • Merge the template for the sys-auth/nss_ldap program: set the value of the cl_merge_pkg variable to sys-auth/nss_ldap. Only template1 will be applied

  • Merge all templates. The default value of the cl_merge_pkg variable is ''. Both template1 and template2 will be applied.

If the parameter specified for merge (or defined by the template path) is a nonexistent package, the function returns an empty value.

merge() does not check that the package exists: #-merge(sys-auth/nosuchpkg)-# yields 1 both with an empty cl_merge_pkg and when cl_merge_pkg equals that same fictitious name; #-merge(x11-misc/nosuch)-# in the 40-xfce-4.6 directory also yields 1. The result is empty only on a mismatch with the cl_merge_pkg value. mergepkg() checks that the package exists: #-mergepkg(cat/nosuchpkg)-# with cl_merge_pkg=["cat/nosuchpkg"] yields an empty value, while on an installed package it returns the version - 2.18-r1 for sys-apps/baselayout.

mergepkg(category/package) - a combined call of merge and pkg. Returns the version of the installed (or being installed) package in the system when configuring this particular package or when reconfiguring the whole system.

case(type,var) - prints the value of a template variable with a change of letter case, where:

  • type - the type of case change: upper - upper case, lower - lower case, capitalize - the first letter in upper case. The capitalize mode not only raises the first letter but also lowers the rest: tESTbOX gives Testbox.

  • var - the name of the template variable.

Example. Print the host name in upper case:

#-case(upper,os_net_hostname)-#

cut(number,delimiter,data) - splits a string into substrings and returns the specified one.

  • number - the number of the substring to return (starting from 0). If the function is called without parameters, the number is 0.

  • delimiter - the delimiter; if the parameter is given but empty, the delimiter is a comma. If the parameter is not given, the delimiter is -.

  • data - the string; it can be the result of a function or the value of a variable. If the parameter is not given, the value of the cl_pass_file variable is used (the template file name).

Example.

#os_audio_default holds the sound card number and the device number separated by a comma, get the device number
#-cut(1,,#-os_audio_default-#)-#
#Get the number from the template name (05-rebuild_openrc)
#-cut()-#
#Get the template name without the digit
#-cut(1)-#

disk(mount_point,name) - prints the value of a hard disk parameter during system installation.
The function gets the value from a variable ('os_install_disk_' + name, or 'os_disk_'+ name if there is no such variable), and it looks up the required value using the os_install_disk_mount variable (mount points during installation).

  • mount_point - the mount point during installation.

  • name - the last element of the variable names starting with os_install_disk_/os_disk ('os_install_disk_'/'os_disk_' + name).

variable values

os_install_disk_mount = ['swap', '/', '', '', '/var/calculate']

os_disk_grub ['0,0', '0,1', '0,2', '0,3', '0,4']

function

disk(/var/calculate,grub)

  • in the os_install_disk_mount variable we find /var/calculate and get index 4

  • in the os_disk_grub variable at index 4 we get the value '0,4' the result of the function disk(/var/calculate,grub) '0,4'

function

disk(/boot,grub)

  • /boot is not found in the os_install_disk_mount variable, there is no index

  • if there is no index, we find / in the os_disk_install variable and get index 1

  • in the os_disk_grub variable at index 1 we get the value '0,1' the result of the function disk(/boot,grub) '0,1'

Example. Print the disk for the grub bootloader:

#-disk(/boot,grub)-#

we get the value 0,1

The example assumes that the lists of mount points and the corresponding list are collected consistently.
If their lengths differ, the merge is aborted with an error like install.os_install_disk_mount does not match install.os_disk_grub in size and the file is not created: this
message means not a typo in the call, but an incomplete or inconsistent set of installation variables.

elog(pkg) - gets the installation time (timestamp) of the specified package. If no package is specified, the time of the last installed package is returned. The information is retrieved from emerge.log. The function is used to determine whether the user profile needs to be configured when the user logs into a session.

where:

pkg - the full package name with the category

env(module.var_name) - reads the value of a module variable from calculate.env files.

  • module - the module name.

  • var_name - the service variable. the separator is a dot '.'

  • we read the name of the domain the machine is joined to from the calculate.env files

    #-env(client.os_remote_auth)-#
    

we get the value domain-server for example, if /etc/calculate/calculate.env contains

[client]
os_remote_auth = domain-server

exists(path,opt) - checks whether a file or directory exists.

If the file or directory exists, it outputs '1', otherwise ''. Instead of 1, it returns the file type designation:

  • d - directory

  • f - file

  • l - symbolic link

  • s - socket

  • b - buffered block device

  • c - unbuffered block device

  • p - FIFO

path - the path in the filesystem.

opt - an optional option.

Possible values of opt:

  • root - the path to the file will not contain the chroot path. (Whatever path is specified is the one that will actually be used - regardless of the cl_chroot_path and cl_root_path variables)

Example. Check the existence of the /etc directory:

#-exists(/etc)-#

The result will be 'd'.

grep(file,regex) - gets the value from the file file that matches the regular expression regex. If the regular expression uses grouping of values, the function returns the content of the first group.

\xFF is converted, where FF is the two-digit hexadecimal code of a character. All spaces are cut from the argument even before the regular expression is parsed, so key = "(.*?)" and key="(.*?)" behave the same and both fail to find the string key = "V1"; a space in the searched text is set with \s, \s+, . or [\x20].

Example. Get the value of nofscks from dracut.conf.

#-grep(/etc/dracut.conf,nofscks="(.*?)")-#

Special regular expression (regex) characters:

"." - matches any character except a newline. With the dotall mode enabled, it matches any character.
"^" - matches the beginning of the file. With the multiline mode enabled, it matches the beginning of a line.
"$" - matches the end of the file. With the multiline mode enabled, it matches the end of a line.
"*" - matches 0 or more repetitions of the preceding regex. The regex will match the largest possible part of the text.
"*?" - the "non-greedy" version of using the previous character. The regex will match the smallest possible part of the text.
"+" - matches 1 or more repetitions of the preceding regex. The regex will match the largest possible part of the text.
"+?" - the "non-greedy" version of using the previous character. The regex will match the smallest possible part of the text.
"?" - matches 0 or 1 repetition of the preceding regex. The regex will match the largest possible part of the text.
"??" - the "non-greedy" version of using the previous character. The regex will match the smallest possible part of the text.
"{m,n}" - matches from m to n repetitions of the preceding regex.
"{m,n}?" - the "non-greedy" version of using the previous construct. The regex will match the smallest possible part of the text.
"\" - escaping of special characters
"[]" - matches any character from the specified set.
"[^]" - matches any character not from the specified set.
"A|B" - create a regex that matches either A or B: (zz|CC) gives CC, while (zz|aa11) gives aa11.
"(...)" - regex grouping with the groups preserved (grep returns the content of the first group)
"(?ims)" - sets the regex modes: case-insensitive, multiline, dotall. The flag works only if it stands at the beginning of the expression: (?i)cc and (?m)^CC give a match, while the same flag inside a group (((?i)cc), ((?m)^CC)) leads to Wrong regular expression and an empty substitution.
"(?:...)" - regex grouping without preserving the groups
"(?=...)" - checks the text after the regex for a match.
"(?!...)" - checks the text after the regex for no match.
"(?<=...)" - checks the text before the regex for a match (this regex must have a fixed length).
"(?<!...)" - checks the text before the regex for no match (this regex must have a fixed length).

"\w" - matches any character from the set [a-zA-Z0-9_]
"\W" - matches any character outside the set [a-zA-Z0-9_], that is, the same as [^a-zA-Z0-9_]; the newline is one of them as well

"\s" - matches any whitespace character
"\S" - matches any non-whitespace character
"\d" - matches any decimal digit [0-9]
"\D" - matches any character that is not a decimal digit [^0-9]

The behavior matches Python: for text where the lines are aa11bb and CC22dd, \w+ gives aa11bb, \d+ gives 11, \D+ gives aa, \W+ gives the newline; for the string k1="a b c" \s+ gives a space, and \S+ gives k1="a.

groups(group1,group2,..groupN) - checks whether the user belongs to the groups group1,group2, ..groupN

If the user belongs to at least one of the groups, it outputs '1', otherwise ''

group1 .. groupN - the group names.

Example. Check whether the user belongs to the wheel group:

#-groups(wheel)-#

If the user belongs to the wheel group, the result will be '1'.

ini(var, value, opt) - writes and reads a variable from the user's configuration file (~/.calculate/ini.env).

When configuring the system, the write goes to <chroot>/var/lib/calculate/ini.env, while /etc/calculate/ini.env remains a read layer: after #-ini(mytest,42)-# the value appears in var/lib/calculate/ini.env, and the etc/calculate/ini.env file is not changed.

  • var - the name of the function variable. The name must start with a letter and may contain Latin letters and digits, as well as a dot. The dot serves as the separator between the section and the variable name for placement in the configuration file.

  • value - the value of the function variable, the value is assigned to the function variable and written to the configuration file (the function meanwhile returns an empty value). If the second argument is missing, the variable is read from the configuration file; if the variable name is missing from the configuration file, an empty value is written to the variable. If the argument is an empty string without quotes, the variable is deleted. If the argument is an empty string in quotes, the value of the variable in the ini file is cleared.

  • opt - the option for converting the variable value, an optional parameter; possible values url, purl, unicode, hexcode. When this argument is used, the second argument of the function must be empty.

Examples:
1. Create the "test" variable, assign it the value 15 and write it to the configuration file:

#-ini(test,15)-#

  1. Read the value of the test variable previously written to the configuration file, replace the function with the value of the variable read, in our case "15":

    #-ini(test)-#
    

  2. Using the ini function with three arguments. Assume that the ~/.calculate/ini.env file contains the section

    [test]
    param = Тестовый параметр
    

then the function

#-ini(test.param,,unicode)-#

will return

\u0422\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440

function

#-ini(test.param,,hexcode)-#

will return

\x422\x435\x441\x442\x43e\x432\x44b\x439 \x43f\x430\x440\x430\x43c\x435\x442\x440

function

#-ini(test.param,,url)-#

will return

%d0%a2%d0%b5%d1%81%d1%82%d0%be%d0%b2%d1%8b%d0%b9%20%d0%bf%d0%b0%d1%80%d0%b0%d0%bc%d0%b5%d1%82%d1%80

The purl option differs from url in that it converts '/' into the code '%2F'

In the current implementation, the result is different. The value Тестовый параметр gives: unicode → естовый параметр, hexcode → естовый параметр (without any \x422… escaping), url → '%d0%a2%d0%b5%d1%81%d1%82%d0%be%d0%b2%d1%8b%d0%b9%20%d0%bf%d0%b0%d1%80%d0%b0%d0%bc%d0%b5%d1%82%d1%80, purl for /a/b/c → '%2fa%2fb%2fc. The reason is a known defect of the current implementation: unicode and hexcode take the repr() of the value and cut off the first two characters, expecting the u'…' prefix from Python 2, which does not exist in Python 3, so the slice eats the first character of the value; url and purl cut the repr() of the byte string and leave the leading single quote, while purl encodes the slash in lowercase (%2f, not %2F).

  1. placing the sshd service in autostart with a check and a mark in ini.env
    # Calculate path=/etc/runlevels/default name=sshd link=/etc/init.d/sshd symbolic ini(runlevels.openssh)!=on&&ini(runlevels.openssh,on)==
    

livemenu(mode) - a special-purpose function for creating the multiboot menu for Flash. mode - the operating mode of the function, and can be the following:

  • submenu - returns the list of systems in the following format:

    system identifier;
    full name in the boot menu;
    path to the kernel;
    boot parameters;
    path to initrd;
    splash boot parameters;
    
    Example:
    cl-2;
    Calculate Linux Desktop Xfce;
    /boot/vmlinuz-2;
    root=live:LABEL=CALCULATE;
    /boot/initrd-2;
    splash;
    

  • xorg - returns the list of systems where xorg-server is installed. For example cl-1 cl-2 cl-3.

  • video - returns the list of systems where proprietary drivers are present. For example cl-2 cl-3

The function is used in the 6_ac_builder_iso/0_bootmenu/desktop.config templates, and also for generating gfxboot.cfg.

ls(dir,pattern) - gets the list from the specified directory dir and converts it according to pattern. If pattern is not specified, the list is printed space-separated.

  • dir - the directory or a path pattern to files (/etc/conf.d or /etc/*.conf)

  • pattern - the pattern for converting the list of files from the directory.

If pattern contains \1, then the text of pattern is printed instead of the file name, but \1 is replaced with the file name.

If pattern does not contain \1, it is used as a separator between file names.

\n is converted to a newline. If you need to print \n, use \\n. \\n gives a backslash and a real newline - the separator becomes net\ and a new line, not the two printable characters \n; they cannot be obtained via ls().

Example.

#-ls(/etc/openldap/slapd.conf.d/*.conf,include \1\n)-#

In this case, /etc/openldap/slapd.conf.d contains the files unix.conf and samba.conf

include /etc/openldap/slapd.conf.d/unix.conf
include /etc/openldap/slapd.conf.d/samba.conf

The function prints real file paths, that is include /etc/openldap/slapd.conf.d/unix.conf and include /etc/openldap/slapd.conf.d/samba.conf. The line order follows the directory traversal and is not sorted, so you should not swap it - the engine returns the files as the filesystem sees them.

Example 2

files = #-ls(/etc/conf.d,,)-#

In this case, /etc/conf.d contains the files net, modules, root
files = /etc/conf.d/net,/etc/conf.d/modules,/etc/conf.d/root

server(service.option,var) - reads the value of a service parameter. The information is obtained by processing the file /var/calculate/remote/server.env,

  • service - the service name.

  • option - the service option.

  • var - the function variable name (optional parameter). The separator between service and option: '.' - a dot. If var - the function variable name - is used, the obtained service option value will be written to the function variable var. If var is not used, the obtained service option value will be inserted into the configuration file text.

  • read the port value for connecting to the jabber service

    #-server(jabber.port)-#
    

get the value 5223

The separator between the service and the option is a dot: #-server(jabber,port)-# removes the template with the error error, template term 'server(jabber,port)', while #-server(jabber.port)-# gives 5223. A comma separates the function arguments.

  • read the port value for connecting to the jabber service and put it in the function variable jabber_port
    #-server(jabber.port,jabber_port)-#
    

#-jabber_port-# must be read in this same template file: the variable that the second argument creates,
belongs to the current template and is not available in another file of the pass.

The value of the function variable jabber_port is 5223. The dot form also works with a variable name: #-server(jabber.port,jabber_port)-# writes 5223 to the function variable jabber_port, while the label itself is replaced with an empty string; the variant with a comma in the first argument gives the same error.

list(var,index) - prints the value at an index from a variable.
where:

  • var - the name of a function variable or a template variable (the variable value must be a list).

  • index - the index for looking up the value in a function variable or a template variable (the first element has index 0, and so on).

Example. The variable value

os_disk_dev = ['/dev/sda1', '/dev/sda2', '/dev/sda3', '/dev/sda4', '/dev/sda5']

#-list(os_disk_dev,1)-#

The function label will be replaced with '/dev/sda2'.

If the requested element is absent from the list, the function returns an empty string.

in(var,value1,value2...) - checks whether there is at least one value from value among the values of the variable var. If a value is found, it returns "1", otherwise an empty string. The variable can be either a list or a string.

  • var - the variable name

  • valueX - the list of values for comparison

Example:

The variable value is a string

os_install_linux_shortname = CLDX

#-in(os_install_linux_shortname,CLDX,CLD,CLDG)-#

Example 2:

The variable value is a list

os_linux_pkglist = CLDX,base

#-in(os_linux_pkglist,CLDX,CLD,CLDG)-#

It will return 1, because there is a common value - CLDX.

The function label will be replaced with 1; the value CLDX does not reach the insertion point.

kernel(kernel_opt) - gets the value of a kernel configuration parameter. It returns "y","m" or an empty string. y - the option is built into the kernel, m - a kernel module, empty string - the option is disabled.

kernel_opt - the case-insensitive option name without the CONFIG_ prefix

Not only y/m/empty is returned: string options are returned without quotes (CONFIG_LOCALVERSION="-calc" → -calc), and the lookup is by substring, so a line like # CONFIG_EXT4_FS is not set standing above the needed one stops the search and gives an empty value.

Example 1. Is ext4 enabled:

kernel(ext4_fs)!=

Example 2. reiserfs is a kernel module, while ext4 is built into the kernel

kernel(reiserfs_fs)==m&&kernel(ext4_fs)==y

load(arg,path,opt) - displays information from a file.
where:
arg - the type of the file content;
path - the path to the file;
opt - the optional option

  • root - the path to the file will not contain chroot paths. (Whichever path is specified is the one actually used, regardless of the cl_chroot_path and cl_root_path variables.)

The possible values of "arg":

  • ver - the file content is a version number

  • num - the file content is a number

  • char - the file content is a string

  • empty - the result is the file content without commented lines (comments are # or ;) и пустых строк.

  • key - is accepted in the list of valid values, but has no separate handling: it behaves like char and returns the file content as is - for the file /etc/g2 with the line k1="a b c" the call #-load(key,/etc/g2)-# gives k1="a b c". There are handler differences only for empty (comment lines # and ; and empty lines are dropped) and for ver with num: an empty, whitespace-only or missing file gives them 0, whereas char, key and empty give an empty value on the same input.

The possible values of path:

  • path - an absolute or relative path to the file.

Example. Print the content of /proc/cpuinfo in place of the function declaration:

#-load(char,/proc/cpuinfo)-#

module(module_name) - gets the version of a Calculate Utilities module. If the module is missing -returns an empty value. If templates are being run for the system being installed, the function will return the lowest module version.

The function returns the "lowest version" only if the system being installed has the directory usr/lib/python3.10/site-packages/calculate/<module>/variables - the Python number is baked into the path, and on a system with a different Python the check fails; the package version, in turn, is looked up strictly in the sys-apps/calculate-utils:3 slot. Inside chroot, under these conditions #-module(core)-# gives an empty value, and outside chroot - the utilities version (3.7.6.8).

Example. Query the version of the client module

#-module(client)-#

If the system has the utilities installed with the client module (for example, version 3.5.0_alpha1), it will return 3.5.0_alpha1.

pkg (category/package) - prints the version of an installed package; if several versions of this package are installed in the system, the version of the highest slot is printed.
where:

  • category - the package category

  • package - the package name

  • The package slot can be specified with a colon: pkg(kde-base/kdelibs:4)

  • You can check the presence of USE flags of a package. The USE flags to check are given in square brackets, separated by commas. Specifying "-" before a USE flag means that the flag must be disabled on the package.

As a compatibility mode, you can specify only the package name; in that case the template processing speed will be lower.

Example. Print the version of the installed package (for example 4.2.4):

#-pkg(kde-base/kdelibs)-#

So, the kdelibs-4.2.4 package is installed in the system.

Example of using USE. Print the version of the installed package if it was built with the desktop flag enabled and the client flag disabled.

#-pkg(sys-apps/calculate-utils[desktop,-client])-#

print (message) - displaying an informational message on the screen while the template is running

warning (message) - displaying a warning message on the screen while the template is running

error (message) - displaying an error message on the screen while the template is running

push(var, value) - putting the value of a variable onto the template function variable stack.

  • var - the name of the function variable. The name must start with a letter and may contain Latin letters and digits. The variable is created for the duration of the configuration file processing.

  • value - the value of a function variable: the value is assigned to the function variable and written to the template function variable stack. If the second argument is missing, the value of the variable is written to the template function variable stack.

  • Create the "test" variable, assign it the value 15, and write it to the template function variable stack.

    #-push(test,15)-#
    

  • Write the value of the previously created test variable to the template function variable stack:

    #-push(test)-#
    

Here "previously created" means in the same template: a function variable lives only for the time it takes to process
a single file, and without #-push(test,15)-# earlier in the same file the tag will remove the template with the error
error, template term 'push(test)'.

pop(var) - retrieving a value from the template function variable stack and assigning it to a variable.

  • var - the name of the function variable. The name must start with a letter and may contain Latin letters and digits. The variable is created for the duration of the configuration file processing.

  • Create the "test" variable, assign it the value 15, and write it to the template function variable stack.

    #-push(test,15)-#
    

  • Get the value from the template function variable stack and assign it to the test2 variable:

    #-pop(test2)-#
    

You can retrieve a value from the template function variable stack both in the current template and in any other one. After the value is retrieved, it is removed from the stack.

Other template functions read the variable created by pop() - for example list() or sum();обычная метка
#-name-# will not see it, because it addresses template variables, not function variables, and will remove
the template with the error Variable not found.

replace(old, new, var) - replacing the text old in the value of the var variable with new.
where:

  • old - the text whose every occurrence in the value of the variable will be replaced with the text new

  • new - the text that the old text will be replaced with in the value of the variable

  • var - the name of a function variable or of a template variable

The old and new text must be enclosed in double or single quotes.

In text inside double quotes, control characters (\', \", \n, \r, \t, \\) are processed. In double quotes, \xFF is also processed, where FF is a two-digit hexadecimal character code. In single quotes, the text is not processed.

Example. the value of the template variable ur_signature

Variables of the ur_* kind appear only when converting /var/calculate/remote/calculate.env:
ur_signature is taken from the signature field of the mail service. In installation events there is no such variable, and
the tag removes the template with the error template variable 'ur_signature' not found - this is not replace() failing,
but a reference to a variable of another context.

Calculate Company\nRussia, Saint Petersburg, Stachek Square, 4\nhttp://www.calculate.ru\n+7 812 3363632\n+7 495 7727678

when running the function

#-replace('\n',"\n",ur_signature)-#

the following text will be inserted at the insertion point (the "\n" character will be replaced with a line break)

Calculate Company
Russia, Saint Petersburg, Stachek Square, 4
http://www.calculate.ru
+7 812 3363632
+7 495 7727678

The example below converts the space in the value of hr_board_model into an underscore character.

...
|main.hr_board_model | rs  |            |P8H77-V LE|
...

#?replace("\x20","_",main.hr_board_model)==P8H77-V_LE#
...
#replace#

rnd(type,len) - outputting a random combination of characters.
where:

  • type - the characters used; possible values: num - digits, pas - digits and letters, uuid - digits and letters from a-f. The name uuid has been renamed to hex, while uuid generation follows the UUID format. The rename did not remove the old name - both work, and they behave differently: hex gives a flat string of [0-9a-f], while uuid gives the UUID form with hyphens, so #-rnd(uuid,16)-# returns not 16 but 18 characters (cc842c8f-a93d-406c): the hyphens count towards the length as well, and the argument sets the number of hex digits, but not the final string length. The uuid length cannot exceed 32 - rnd(uuid,40) is rejected, and len is mandatory for all types except uuid.

  • len - the number of characters (a number). You can omit it when generating uuid in utilities 3.5.

Example. Print three random numbers (for example 372):

#-rnd(num,3)-#

Example for 3.5. Generate half a UUID and a full UUID.

#-rnd(uuid,16)-#
#-rnd(uuid)-#

sum(var,sum_print, sum_out) - computed offset values. The function was developed for configuring Plasma (KDE).

  • var - the name of the "sum" function variable. The name must start with a letter and may contain Latin letters and digits. The variable is created for the duration of the configuration file processing.

  • sum_print - an arithmetic expression whose result will be displayed at the place where the function is declared. If the argument is missing, the value will not be output. The addition "+", subtraction "-", division "/" and multiplication "*" operations are supported. Other function variables can take part in the arithmetic expression, as well as template variables.

  • sum_out - an arithmetic expression whose result will be assigned to the "var" variable (the first argument of the function). If the third argument is missing, the computed value of the second argument is assigned to the "var" variable.

  • Create the "clock" variable and assign it the value 15, without outputting the result.

    #-sum(clock,,15)-#
    

  • Create the "bt" variable, assign it the value of the "clock" variable, and print the value.

    #-sum(bt,clock)-#
    

  • Place a button on a panel "35" pixels wide, leaving a "4" pixel margin at the edges:

    #-sum(bt,bt+2,bt+35+2)-#
    

wallpaper(resolution, wallpapers_path, file) - the function selects the image from the folder that best matches the given resolution. The function returns the full path. The third parameter is used to get the file name.

  • resolution - the required resolution (the current resolution can be obtained from the os_x11_resolution, os_install_x11_resolution variables)

  • wallpapers_path - the path where the image is located in different resolutions. File format: resolution.extension. For example: 1024x768.jpg

  • file - can take only file as a value, in which case the function returns only the file name.

wallpapers_path can be specified as a file. In this case the function returns the specified image.

Example:

The /usr/share/wallpapers/1 folder contains the following images:

  • 1024x768.jpg

  • 1280x1024.jpg

  • 1680x1050.jpg

  • 1920x1080.jpg

#-wallpaper(1280x720,/usr/share/wallpapers/1)-#

returns /usr/share/wallpapers/1/1920x1080.jpg as the best match by proportions

#-wallpaper(1280x720,/usr/share/wallpapers/1,file)-#

returns 1920x1080.jpg

You can use the variables given above to get the current resolution

#-wallpaper(#-install.os_install_x11_resolution-#,/usr/share/wallpapers/1)-#

profile() - the function is used when configuring a user profile and returns its state.

  • configured the profile is configured by the utilities

  • empty the profile is empty, or contains only /etc/skel files

  • custom the profile is not configured by Calculate Utilities

The empty and custom values are used only for the first determination of the user profile state: in the first case the profile will be configured by the utilities, in the second case it will get a note in .calculate/ini.env that the profile does not need to be configured in the future. A profile that contains .calculate/ini.env is always configured.

world(category) - the function is used to build the world file. Returns the list of packages of the specified category that are available for installation. If the category contains no packages for installation or is specified incorrectly, a warning message will be output.

Example:

#-world(dev-lang)-#
...
dev-lang/orc:0
dev-lang/perl:0
dev-lang/php:8.2
...

Merge methods

There are several ways to merge an installation template with the original system file:

  • join - the main merge method, when the two files are merged together. It is described in detail in the "join scheme".

  • before - the template is written to the beginning of the original file

  • after - the template is written to the end of the original file

  • replace - the template is written, replacing the original file

  • delete - no merge takes place, the original file is removed

  • remove - instead of merging, the original file is removed

Modifying the template before merging, for the before, after, replace merge methods:

  • if control elements exist, they are processed

  • if a header exists, it is processed

  • если существует параметр format в заголовке то происходит обработка управляющих символов: "+, -, !"

Default rules

By default, the merge method is set according to the file format. For the file formats of the main applications samba, bind and the like, the join merge applies by default; for the raw and bin formats - the replace merge. For an empty file the delete merge rule applies by default - the targeted file is removed from the system.

There is a third case as well: for patch, diff, dconf, ldif, contents, sqlite, backgrounds the default merge is patch, and specifying append=join for them is not allowed - the engine responds Wrong option 'append=join' in template. An empty template does not delete the file: with raw the file is truncated to zero, with join formats (kde, samba) the target remains untouched, and the engine has no append=delete value at all - such a header is rejected. append=remove serves for deletion.

The merge rules can be changed by setting the append parameter of the template file header.

Location

File naming rules

Template file names can contain conditional operators that define the rules under which the template file will be transferred into the system. As with a link to a site page, the conditions are separated from the name by a question mark (?), after which conditional operators may follow, described in detail in the conditional blocks (see above).

Arithmetic operations can be combined by the AND (&) and OR (?) conditions. In this case, priority will be given to the AND condition.

A single & as "AND" is not accepted in a header: os_linux_shortname==CLD&cl_ver>=99 gives template header not valid; only && works, and || is subordinate to it under the "AND" precedence. The ? character is not an OR operator: in a file name it separates conditions, each of which must be met - grub.conf?os_linux_shortname==CDS?os_linux_shortname==CLD is applied under CLD and is not applied under CLDG.

Example:

grub.conf?os_linux_shortname==CDS?os_linux_shortname==CLD

In the given example, the template file will configure the bootloader for both Calculate Linux Desktop systems and Calculate Directory Server.

If the template file header contains conditional operators, both conditional expressions must be met for the template file to be transferred into the system.

Directory naming rules

Directory naming rules are similar to file naming rules. When the conditions set by the conditional operators are met, the directory will be transferred into the system; otherwise the directory will be skipped with all its contents.

Access rights

The access rights of a configuration file after it is merged with the template file are set according to the following priorities:

  • if the configuration file exists in the system, the rights will be kept unchanged;

  • if the original configuration file is absent, the rights will be set to 644 for the file and 755 for the directory;

  • if the value of the chmod or chown variable of the template file header is set, the rights of the configuration file will be changed according to the value set.

To create symbolic links, use the "link + symbolic" parameters of the template file header.

If, in addition to the header, the template file contains a template body, the original file will be modified according to the merge rules.

Calculate will not transfer so-called "broken links" - links pointing to no file (directory), unless the force parameter is explicitly specified.

A broken link is transferred as well: a template directory with link= copies a dangling symlink to the target without any force, and symbolic with link= to a nonexistent file also creates a link that points nowhere (resolves: False). At the same time, force in a directory header is not accepted (incorrect header parameter: 'force'), so the described exception cannot be expressed in this case.

Merge scheme

The merge changes the settings of the original settings file in accordance with the settings of the template file.

During the merge, all entries of the original file and of the template file are broken down into elements: sections, variables, lists, separated lists, comments, control elements (see below).

The template file must be written using the syntax of the original file. The merge preserves the position of the original file's elements. During the merge, comments from the template file are not transferred.

Merge rules

The operations Join, Replace, Delete can be performed on elements:

Join
  • Elements missing from the original file are appended to the end of the section. In this case, if there is a newline before the inserted element, a newline is added after the inserted element. Otherwise, a newline is added before the inserted element.

  • When merging a separated list, the missing elements are added right after the last element of the configuration file's separated list.

Replace
  • The element values are replaced with new ones. In this case, the formatting is carried over from the template file.
Delete
  • The element is deleted together with the newline that precedes it.

Default merge rules

The merge rules apply to elements with the same name located in the same template section.

When differences are found, the following rules apply by default:

  • Sections - the contents of two sections are joined (+).

  • Variables - variable values are replaced (-).

  • Lists - the contents of lists are replaced (-).

  • Separated lists - as with the merge rule for variables - the list values are replaced (-).

Changing the merge rules

  • "+" - join the elements (for sections and lists); after the merge, only unique elements remain

  • "-" - the element value is replaced

  • "!" - the element is deleted. In CXmlConf template file descriptions, these rules are described by the tag "<action>".

CXmlConf format

Note. This section describes a historical format: the CXmlConf implementation is absent from the current utilities and the format is not supported.

CXmlConf is a universal format for describing configuration files. It is designed for selective modification of settings of most common types of Linux/Unix OS configuration files.

The XML settings description file breaks the configuration file down into logical structures - elements suitable for subsequent merging. After the merge, the file can be converted back to its original state, with some exceptions (see Merge scheme).

Element descriptions are nested inside the construct:

<cxmlconf>
  <head>
    <ver>format version</ver>
    <format>configuration file format</format>
  </head>
  <body>
    [<area>...</area>... <field>..</field>]
  </body>
</cxmlconf>

  • ver - carries the markup version number

  • format - the configuration file format (determined by common programs).

All elements (see below) are placed inside the <body/> element.

Sections

Configuration file sections delimit the variable namespace. Sections can contain logical structures, including other sections (example: named.conf).

Sections are placed inside the construct:

<area>
  <caption>
    <name>Section title</name>
    <action>join|replace|drop</action>
    <quote>Beginning part of the section (title)</quote>
    <quote>Closing part of the section description</quote>
  </caption>

  [<field></field>...]

</area>

Variables

Variables are written in the form:

<field type="var">
  <name>variable name</name>
  <value>variable value</value>
  <action>join|replace|drop</action>
  <quote>Original description text</quote>
</field>

Some configuration files, for example /etc/openldap/slapd.conf, contain this construct:

index   cn              pres,sub,eq
index   sn              pres,sub,eq
index   uid             pres,sub,eq

In this case, the variable name consists of the first and second parts, and the value - of the third.

The line

index   cn              pres,sub,eq

In XML, this will look like:

<field type="var">
  <name>indexcn</name>
  <value>pres,sub,eq</value>
  <quote>index   cn              pres,sub,eq</quote>
</field>
<field type="br"/>

Lists

In the named.conf file example, the "listen-on" block can contain only values - values of the block, not of variables.

The construct for denoting values is:

<field type="list">
  <name>hostsallow</name>
  <value>192.168.0.0/24</value>
  <value>127.</value>
  <action>join|replace|drop</action>
  <quote>Original list text</quote>
</field>

where inside the "<quote>" block the original text of the value description is preserved, without the trailing newline.

Separated lists

The settings file of the Apache web server can contain an "Include" directive, which allows the source file to be made modular. Such cases are described in "CXmlConf" as "Separated lists".

Separated lists are described by the following construct:

<field type="seplist">
  <name>Include</name>
  <value>/etc/apache2/modules.d/*.conf</value>
  <action>join|replace|drop</action>
  <quote>Original list text</quote>
</field>

Comments

When configuration files are merged, the comments of the original file are preserved unchanged.

All comment types are placed in the "<comment>" construct. The text placed in the "<quote/>" keeps the comment characters and the newline:

<field type="comment">
  <quote>Original comment text</quote>
</field>

Comments cannot be nested (be described in other comment constructs).

Control elements

The construct for denoting newlines is:

<field type="br">
  <quote>separator elements (spaces, tabs)</quote>
</field>

  • "quote" contains formatting elements (spaces, tabs)

XML format

Supported XML formats

Currently, support is implemented for the formats xml_xfce (XML file for configuring the XFCE window manager), xml_xfcepanel (XML file for configuring the panels of the XFCE window manager), xml_gconf (XML file for configuring GNOME); the current release also includes a fourth one - xml_gconf_tree (described below).

Differences from the CXmlConf format

  • XML files are stored and processed without conversion to another format.

  • All rules, functions and variables apply to the XML template file just as they do to a regular template, except for the XML element join operations

Joining XML elements

To join XML elements in the XML template text, the XML element attribute 'action' is used

Allowed attribute values

  • action="join" - the elements are joined (applies by default)

  • action="replace" - the template element replaces the file element

  • action="drop" - the file element is deleted

xml_xfce format

The format consists of channel and property elements.

The channel attributes hold the file name and the file version.

Inside the channel element there are property elements.

Example of a "channel" element:

<channel name="xfwm4" version="1.0">
  <property name="general" type="empty">
  .....
  </property>
</channel>

Example of a "property" element:

<property name="wrap_workspaces" type="bool" value="false"/>

Every property element has a type attribute.

If type="array", this element and its inner elements are replaced by the elements from the template. Otherwise the elements are merged.

Example of type="array":

<property name="workspace_names" type="array">
  <value type="string" value="Workspace 1"/>
  <value type="string" value="Workspace 2"/>
  <value type="string" value="Workspace 3"/>
  <value type="string" value="Workspace 4"/>
</property>

xml_xfcepanel format

The format consists of the following elements: panels, panel, properties, property, items, item.

If the element is items, this element and its inner elements are replaced by the elements from the template. Otherwise the elements are merged.

Example of an "items" element:

<items>
  <item name="xfce4-mixer-plugin" id="9"/>
  <item name="clock" id="10"/>
  <item name="separator" id="52"/>
  <item name="actions" id="12"/>
</items>

xml_gconf format

The format consists of entry elements.

If an entry element has an ltype attribute (a list) or a type="string" attribute, this element and its inner elements are replaced by the elements from the template; otherwise the elements are merged.

Replacement happens only for elements without child tags: <entry name="dpi" type="float" value="96"/> in the existing file gets value="86". If the configuration file being merged already has an <entry> with a child <stringvalue> (that is, the type="string" or ltype case), the merge aborts with Failed to join the template, and the file stays untouched. This is a known defect of the current implementation of the format; the workaround used by the overlay is append=replace, under which the file is overwritten with the template content. A file created "from scratch" with the same template is generated normally, and its mtime is replaced with the current time.

The mtime attribute of an entry element, when the entry element changes, shows the time when the change occurred, in seconds.

Example of an xml_gconf template:

# Calculate format=xml_gconf
<?xml version="1.0"?>
<gconf>
        <entry name="rgba_order" mtime="1235158855" type="string">
              <stringvalue>rgb</stringvalue>
       </entry>
       <entry name="dpi" mtime="1235162438" type="float" value="86">
       </entry>
       <entry name="hinting" mtime="1235266915" type="string">
               <stringvalue>full</stringvalue>
       </entry>
       <entry name="antialiasing" mtime="1235266915" type="string">
               <stringvalue>rgba</stringvalue>
       </entry>
</gconf>

xml_gconf_tree format

The format consists of dir and entry elements and their attributes.

The element attributes are merged in the case of a join merge.

When a template is merged with a configuration file, the entry elements of the configuration file are replaced by the corresponding entry elements of the template.

The mtime attribute of an entry element, when the entry element changes, shows the time when the change occurred, in seconds.

When merging with an already existing file, the same defect applies as for xml_gconf: Failed to join the template; append=replace works, leaving only the template elements in the target. The example below is marked up correctly and parses as XML with a gconf root. If you deliberately break the closing root tag, leaving <gconf>, the engine answers The template content is not XML; after </gconf> is restored, the example parses and merges again.

Example of an xml_gconf template:

# Calculate format=xml_gconf_tree
<?xml version="1.0"?>
<gconf>
    <dir name="desktop">
        <dir name="gnome">
            <dir name="volume_manager">
                <entry name="percent_used" mtime="1285580987" schema="/schemas/desktop/gnome/volume_manager/percent_used"/>
                        </dir>
                </dir>
        </dir>
</gconf>

Usage examples

Template file:

# Calculate format=xml_xfce
<?xml version="1.0" encoding="UTF-8"?>
<channel name="xfce4-session" version="1.0">
  <property name="general" type="empty" action="drop">
    <property name="FailsafeSessionName" type="empty"/>
    <property name="SessionName" type="string" value="Default"/>
    <property name="SaveOnExit" type="bool" value="true"/>
  </property>   
</channel>

The line <property name="general" type="empty" action="drop"> means that this element and all elements inside it are removed.

The resulting file is as follows:

<?xml version="1.0" encoding="UTF-8"?>
<channel name="xfce4-session" version="1.0">
</channel>

Note: the engine takes the name attribute of <channel> not from the template but from the name of the target file - for the file
xfceplain.xml you get <channel name="xfceplain" version="1.0"> with the same template text. If the name
of the channel must differ from the file name, set it with a separate property entry inside the channel.

The content matches: the general element with its inner elements is removed, action="drop" works. The name attribute of channel is taken from the configuration file name (xfce4-session.xml → name="xfce4-session", xf.xml → name="xf"), and the created file gets a Calculate provenance header (<!-- Modified Calculate Utilities … -->), которого в примере выше нет.

'patch' format

The patch format processes configuration files using regular expressions of the Python programming language.

Features

The patch format processes the configuration file based on the template (the patch merge type); no merge of the template and the configuration file takes place.

The source file is processed as a whole, not line by line, so the characters '^' and '$' mean the beginning and the end of the file respectively. The character '.' means any character except a newline.

The header parameters for format=patch include the multiline and dotall options. With multiline enabled, '^' and '$' denote the beginning and the end of a line. With dotall enabled, '.' includes the newline.

Both options are accepted only with format=patch: in a header, format=raw multiline makes the engine answer Option multiline should be used for format=patch only, and format=raw dotall - Option dotall should be used for format=patch only; with format=patch both work as described.

Description

A template in the patch format:

# Calculate format=patch
<reg>python regular expression 1</reg>
<text>text 1 to replace the regular expression with</text>
<reg>python regular expression 2</reg>
<text>text 2 to replace the regular expression with</text>
...

In the content of the reg and text tags, the characters &amp;, <, > must be replaced with &amp;, &lt;, &gt; respectively.

Example:

# Calculate format=patch
<reg>TEXT&amp;DATA</reg>
<text>TEXT_CONFIG</text>

This template will replace TEXT&DATA with TEXT_CONFIG in the configuration file.

'diff' format

The diff format applies diff patches to the source code of a package. The file itself is not created in the system; the resulting content is processed relative to the directory specified in the path= parameter.

path does not affect the file lookup: the patch is applied from the system root (cl_root_path inside cl_chroot_path), where the engine passes cwd to the patch program, picking the path-component strip level from -p0 to -p3. The file must lie at the path given in the patch headers relative to the root: panel-plugin/xkb-cairo.c at the root is patched (Appling patch), while the same patch with the file in usr/src/xfce/panel-plugin/xkb-cairo.c and path=/usr/src/xfce gives Correction failed.

Example:

# Calculate format=diff
--- panel-plugin/xkb-cairo.c    2012-07-17 16:23:24.997030066 +0400
+++ panel-plugin/xkb-cairo.c    2012-07-17 16:47:34.107054590 +0400
@@ -27,7 +27,7 @@
 #include "xkb-util.h" 
 #include "xfce4-xkb-plugin.h" 

-#define XKB_PREFERRED_FONT "Courier New, Courier 10 Pitch, Monospace Bold %d" 
+#define XKB_PREFERRED_FONT "Droid Sans, Courier New, Courier 10 Pitch, Monospace Bold %d"

The hunk must be complete: the header @@ -27,7 +27,7 @@ means seven lines before the change - three context
lines at the top, one removed line and three context lines at the bottom. If the trailing context lines are omitted, patch
rejects the hunk and the merge aborts with Correction failed; with a complete hunk the patch is applied
(Appling patch), and the engine itself tries the path-strip level from -p0 to -p3.

'kernel' format

The kernel format merges kernel configuration files without preserving comments.

Example:

# Calculate format=kernel
CONFIG_XFS_FS=m
CONFIG_REISERFS_FS=y
# CONFIG_EXT3_FS is not set
!CONFIG_EXT3_FS_POSIX_ACL=
!CONFIG_EXT3_FS_SECURITY=
!CONFIG_EXT3_FS_XATTR=

'dconf' format

The dconf format is used to modify user settings stored in the dconf database. The dconf format supports the dconfpath header parameter so you can change the base path of the settings.

The header parameter is named dconf, as in the example below; the spelling dconfpath is not accepted: # Calculate format=dconf dconfpath=/org/x/ … gives incorrect header parameter: 'dconfpath' (that is the name of an internal format attribute, not a header parameter). dconf= is allowed only together with format=dconf; in another header it gives Option dconf should be used for format=dconf only.

Example:

# Calculate format=dconf dconf=/org/gnome/eog/
[view]
background-color='#000000'
use-background-color=true

[ui]
statusbar=true
toolbar=true
sidebar=false

To apply templates in the dconf format, the utilities use the gnome-base/dconf package.

This format is merged only in the user profile event. In the tree, such templates lie in 6_ac_desktop_profile/2-user/<category>/<package>/…, where the .calculate_directory of the event directory contains # Calculate env=desktop path=~ name= chown=#-main.ur_login-#:#-main.ur_group-# ac_desktop_profile==on, and the .calculate_directory of the 2-user directory - # Calculate append=skip ur_login!=root. The action variable must be at the first level: if you place the template deeper and leave the condition in the second directory, the engine answers No conditions for checking the value of an action variable and shows Skipped directories:. You can trigger the event with the command cl-core --method=desktop -u <user>; the created database lies in ~/.config/dconf/user, belongs to the user themselves, and is read with the command su - <user> -c 'dbus-run-session -- dconf dump /org/gnome/eog/'.

The format is unavailable if /usr/bin/dconf, dbus-run-session and su are not found: the template ends with the message The 'dconf' format is unavailable.

'json' format

The json format is used to modify settings in json format (for example, Preferences of the www-client/chromium package).

json example

{"google": {"services": {"signin": {"LSID": "", "SID": ""}}},
 "intl": {"accept_languages": "ru-RU,ru,en-US,en", "status": 1}}

When merging, top-level values are replaced by the given ones, and the nested branch of the same name from the template replaces the file branch entirely: the other keys of that branch disappear. If you need to keep the content of a branch, specify it in the template in full.

To change the merge rules in effect by default, control characters are added at the beginning of the element name in the template file:

  • "-" - the branch is replaced

  • "!""!"** - the branch is removed

Both characters work only at the top level of the document: {"!intl":""} removes the intl branch, {"-intl":{…}} replaces it entirely, {"intl": 5} replaces the value. At a nested level the prefixes are not read: {"a": {"b": {"-c": ""}}} gives the key "-c" as is. The file is always written with four-space indentation; the compact form of the source file is not preserved.

Merge example

# Calculate format=json
{"intl":{"accept_languages": "en"}}

{
    "google": {
        "services": {
            "signin": {
                "LSID": "",
                "SID": ""
            }
        }
    },
    "intl": {
        "accept_languages": "en"
    }
}

Removal example

# Calculate format=json
{"!intl":""}

{
    "google": {
        "services": {
            "signin": {
                "LSID": "",
                "SID": ""
            }
        }
    }
}

Replacement example

# Calculate format=json
{"-intl":{"accept_languages": "en"}}

{
    "google": {
        "services": {
            "signin": {
                "LSID": "",
                "SID": ""
            }
        }
    },
    "intl": {
        "accept_languages": "en"
    }
}

A settings branch is also replaced entirely if the template contains a value.

Replacement example

# Calculate format=json
{"intl": 5}

{
    "google": {
        "services": {
            "signin": {
                "LSID": "",
                "SID": ""
            }
        }
    },
    "intl": 5
}

The 'contents' format

The contents format is used to modify the packages that files belong to. It allows you to add files to a package, remove them, and change the package a file belongs to. Each line of the template is an instruction describing an action on files. Empty lines are ignored, as well as comment lines starting with #.

Adding a file to a package.
<package> <path>
  • package - the package the file will be added to. The package can be specified with a version or a slot, for precision.

  • path - a path in the filesystem. Glob characters are supported (*, [], [!], ?)

A file is added to a package even if it already belongs to another package. If the system has two packages and the rule does not specify a slot, the file will be added to the package with the higher version. The checksum of the file is calculated when it is added.

Removing a file's ownership by a package.
!<package> <path>

When getting the list of files to be removed (using glob characters), the package's file list is used, not the filesystem. If the system has two packages and the rule does not specify a slot, the file will be removed from both packages.

Moving a file from one package to another
<source>,<target> <path>
  • source - the package the file will be removed from

  • target - the package the file will be added to

  • path - a path in the filesystem. Glob characters are supported (*, [], [!], ?)

When getting the list of files, just as with removal, the file list of the source package is used, not the filesystem. The checksum of the files will be transferred from the source package. Thus, if a file was edited by the user while it belonged to the source package, after being bound to the target package it will be seen as modified by the system.

Examples
# Calculate format=contents

# add files from /etc/conf.d starting with dhcp to the openrc package
sys-apps/openrc /etc/conf.d/dhcp*

# add to the udisks package, second slot
sys-fs/udisks:2 /etc/polkit-1/rules.d/60-*

# add to the udisks package with version 1.0.5-r1
sys-fs/udisks-1.0.5-r1 /etc/polkit-1/rules.d/60-*

# remove the ownership of /etc/conf.d/hostname by the openrc package
!sys-apps/openrc /etc/conf.d/hostname

# move files belonging to sys-apps/baselayout from /etc/conf.d to the openrc package
sys-apps/baselayout,sys-apps/openrc /etc/conf.d/*

The 'backgrounds' format

It requires the media-gfx/imagemagick package.

Without media-gfx/imagemagick, any template of this format ends with the message The 'backgrounds' format is unavailable. Need to install virtual/imagemagick-tools, while no images are created. The convert= and stretch parameters are accepted only here: in another header the engine responds Option convert should be used for format=backgrounds only and Option stretch should be used for format=backgrounds only.

The backgrounds format is used to create multiple background images of different resolutions from a source image.

The following header parameters are used:

  • link= parameter pointing to the source image, if the parameter is not specified or points to a nonexistent file, images will not be created

  • convert= the format and extension of the resulting background images (jpg, png, gif, gfxboot), by default the format of the source image is the same as the extension of the source file.

  • stretch create images even if the source image is smaller than required

  • mirror if the source image is missing, all images previously created by this template will be removed

  • path= the directory into which the created images will be placed

  • name= a prefix added to the file name

Image names are formed as follows: (prefix)(resolution).(format), where prefix is the name taken from the name= parameter, resolution is the resolution of the image being created, format is the image format (jpg, png, gif or gfxboot). Gfxboot - a jpeg with certain parameters that are suitable for installing the image as a background image for syslinux-gfxboot.

Besides the images, the template creates a checksum file: name=bg- yields bg.md5 next to them. If name= is left empty, the checksum file gets the name md5sum.

The content of the format is a set of lines containing the resolutions of the images to be created. If no content is specified, the list of standard resolutions given in the main.cl_resolutions variable will be used.

If the resolution of the source image is smaller than the target one, the image will not be created, and a warning will be displayed. If the stretch parameter is specified instead, the source image will be stretched to the required one.

To prevent the template from running again, a file with the checksum of the source image is used.

All created images (as well as the checksum file) are "bound" to the package that the templates configure.

If only one resolution is specified, only one file with the required resolution will be created, and the name of the resulting file will consist of path/name. The checksum file will not be created.

Instead of a resolution, you can specify original, which means the resolution of the source image. It can be used, for example, to convert an image from one format to another.

Examples.

Create images in /usr/share/wallpapers/Calculate_Linux/images/contents/images, named like 1920x1080.jpg, from /usr/share/backgrounds/bg.png, without creating images with a resolution larger than the source one.

# Calculate format=backgrounds convert=jpg link=/usr/share/backgrounds/bg.png \
path=/usr/share/wallpapers/Calculate_Linux/images/contents/images name=

Create images in /etc/splash/calculate/images, named like silent-1920x1080.jpg, from /usr/share/backgrounds/bg.png, the source image will be stretched if necessary.

# Calculate format=backgrounds convert=jpg stretch \
link=/usr/share/backgrounds/bg.png path=/etc/splash/calculate/images name=silent-

Create a single image /boot/grub/grub-calculate.png with a resolution of 1920x1440.

# Calculate format=backgrounds path=/boot/grub name=grub-calculate.png \
 link=/usr/share/backgrounds/bg.png stretch
1920x1440

The 'world' format

The format for modifying the world file. It contains a list of packages that must either be added to the file or removed from it. For removing a package from world, the syntax is !<пакет>. For removing with verification (if the required package is missing, a warning message will be displayed) - !!<package>. If the file with the list is named the same as the category, you can omit the category for packages inside it.

For removing a package in all slots, the syntax is !<пакет>:*.

The removal syntax: !sys-apps/foo removes the line from world, while !!dev-db/postgresql:* displays a warning when the package is missing: Not found dev-db/postgresql:* in world. The targeted file is set with the pair path=/var/lib/portage name=world: if path= points to the world file itself instead of the directory, the engine addresses the file inside the world directory, while world itself remains unchanged. The category prefix is taken from the template file name, not from name=: the file sys-apps with the body calculate-utils, portage, sed yields sys-apps/calculate-utils, sys-apps/portage and sys-apps/sed, while a file named world yields world/eix.

Examples.

Add sys-apps/calculate-utils to world

# Calculate format=world path=/var/lib/portage name=world
sys-apps/calculate-utils

Remove all dev-db/postgresql from world with verification

# Calculate format=world path=/var/lib/portage name=world
!!dev-db/postgresql:*

Add calculate-utils, portage, sed from the sys-apps category

sys-apps

# Calculate format=world path=/var/lib/portage name=world
calculate-utils
portage
sed

The sys-apps line above the third example is the template file name, not its content: it is exactly from the file name that the category prefix is taken, so the lines get into world already as sys-apps/calculate-utils, sys-apps/portage, sys-apps/sed.

All three examples are a file inside an event directory, not a file at the root of the template tree. The action variable is carried by the .calculate_directory of the directory itself: for the examples above the tree looks like this - a 7_ac_install_merge/ directory with a .calculate_directory file, where # Calculate append=skip env=install ac_install_merge==on is written, and a nested template sys-apps/calculate-utils/world with one of the given headers. Without such a file the engine reports No conditions for checking the value of an action variable and creates nothing. Ready-made templates are arranged the same way: 6_ac_install_config/dev-db/postgresql/world begins with the line # Calculate protected format=world path=/var/lib/portage name=world, while ac_install_config==on sits in the .calculate_directory of the 6_ac_install_config directory.

See also