NAME
kpkg runfile - Main package format of kpkg
DESCRIPTION
kpkg runfiles are the main package format of kpkg. They are basic scripts with specific variables and functions that enable kpkg to build packages.
RUNFILE STRUCTURE
Runfiles are simply named run3 and must be placed inside the package directory. It is a specialized custom format.
Example Runfile
name: "test-v3"
version: "0.0.1"
release: "1"
sources:
- "https://test.file/source/testfile.tar.gz"
- "git::https://github.com/kreatolinux/src::543ee30eda806029fa9ea16a1f9767eda7cab4d1"
- "https://test.file/sources/v${version.split('.')[0:2].join('.')}/testfile.tar.gz"
depends:
- "testpackage1"
- "testpackage3"
- "testpackage4"
depends_test2:
- "testpackage5"
- "testpackage6"
no_chkupd: false
replaces:
- "test-v2"
backup:
- "etc/test-v3/main.conf"
- "etc/test/settings.conf"
opt_depends:
- "optional-dependency: This is a test optional dependency"
- "optional-dependency-2: This is a second optional dependency."
build_depends:
- "testpackage5"
- "testpackage6"
- "testpackage10"
sha256sum:
- "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
- "SKIP"
- "ab37404db60460d548e22546a83fda1eb6061cd8b95e37455149f3baf6c5fd38"
sha512sum:
- "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
- "SKIP"
- "fce866720603d30cbefe5c0df9c6bacf70cbdb27caef5bcf15f125901cb23a9681ec9f87410a7d2f763af5a89c2b4e43685196ce3b0674868bf81cb3688e47c8"
b2sum:
- "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce"
- "SKIP"
- "64fed8bce19ef14ed2d8434229dc2ec5307e06205610b1859b81b8090ae5ba7001988de896ff4878a15a7b7334e4a06e5889270b2e755fe130f7c80960e66ba2"
license:
- "GPL-3.0-or-later"
description: "Test package"
func custom_func {
print "This is a test custom function"
}
prepare {
custom_func # We can run custom functions just like commands
env TEST=1
exec tar -xvf testfile.tar.gz
# Or you can use:
# macro extract --autocd=true
# to extract all the archives in sources.
}
build {
cd testfile
echo "Insert build instructions here"
}
check {
macro test --ninja
# exec ninja -C build test
}
preupgrade {
echo "run before upgrade"
}
preinstall {
echo "run before first install"
}
package {
cd testfile
macro package --meson
}
package_test2 {
cd testfile
exec make install_test2 # External commands require exec
}
postinstall {
echo "Insert postinstall instructions here"
}
postupgrade {
echo "run after upgrade"
}
postremove {
echo "Insert postremove instructions here"
}
SYNTAX AND LANGUAGE FEATURES
VARIABLES
Variables must be declared at the top of the runfile. They can be any type (list, string, int, bool, etc.). Variables can be referenced in if statements, for loops, and inside functions. On commands, simple referencing is done via $variable or ${variable}. Complex manipulation (splitting, slicing) works via ${variable.method()} (or variable.method() on a non-command context) (see VARIABLE MANIPULATION below).
test1: true
test2:
- this is a test
- test2
# and so on...
Variables can be referenced in if statements, for loops, inside variables, and inside functions (including in macros and exec commands).
test1: true
# Additional stuff...
echo $test1
# Result: true
List variables can be filtered using [start:end] and can be indexed using [index]. Note that this cannot be used with the $variable syntax, only inside ${variable}. See the example below.
test2:
- IGNORE1
- IGNORE2
- IGNORE3
echo ${test2[0:3].join('')}
# Result: IGNORE1IGNORE2IGNORE3
echo ${test2[0]}
# Result: IGNORE1
IF ELSE STATEMENTS
If-else statements can be used inside all functions. You can utilize all variables defined in the runfile.
build {
if test1 {
print hello!
} else {
print bye!
}
}
You can also use any variable manipulation methods in if statements, including inline exec to execute commands and use their output or exit code in conditions. See VARIABLE MANIPULATION for details on available methods.
CONDITION OPERATORS
The following operators are supported in conditions:
- == (equality):
if "$var" == "value" { ... } - != (inequality):
if "$var" != "value" { ... } - =~ (regex match):
if "$var" =~ e"pattern" { ... } - || (OR):
if "$var" == "a" || "$var" == "b" { ... } - && (AND):
if "$var1" == "a" && "$var2" == "b" { ... }
REGEX MATCHING
Use the =~ operator with e"pattern" syntax for regex matching. The pattern uses standard regex syntax with | for alternatives.
package {
for APPLET in applets {
# Skip applets provided by other packages
if "$APPLET" =~ e"clear|grep|egrep|fgrep|tar|bzip2" {
continue
}
exec "ln -s /bin/busybox $ROOT/bin/$APPLET"
}
}
COMBINING CONDITIONS
You can combine multiple conditions using || (OR) and && (AND):
build {
# OR: true if any condition is true
if "$ARCH" == "x86_64" || "$ARCH" == "amd64" {
print "Building for 64-bit x86"
}
# AND: true only if all conditions are true
if "$DEBUG" == "true" && "$VERBOSE" == "true" {
print "Debug mode with verbose output"
}
}
VARIABLE MANIPULATION
Variables can be manipulated directly within strings using object-style methods. This is particularly useful for constructing source URLs that require specific version formatting (e.g., extracting “Major.Minor” from a full version string). You can also use inline exec to execute commands and use their output or exit code.
The syntax for manipulation is ${variable.method(arguments)} or ${exec("command").method()}.
Note: Global variables (defined at the top of the runfile) cannot use exec directly. Exec can only be used within function blocks (like build, prepare, package, etc.) or inside custom functions.
AVAILABLE METHODS
join(delimiter) Joins a list into a string using the given delimiter. Only works with lists.
- Example:
version: "2.78.1" ${version.split('.').join('!')}returns2!78!1${version.split('.')[0:2].join('.')}returns2.78
- Example:
split(delimiter) Splits the string by the given delimiter and returns the segments as a list. Only works with strings.
- Example:
version: "2.78.1" ${version.split('.')[0]}returns2${version.split('.')[1]}returns78
- Example:
cut(start, end) Slices the string from the
startindex up to (but not including) theendindex. Only works with strings.- Example:
commit: "543ee30eda80..." ${commit.cut(0, 7)}returns543ee30
- Example:
replace(old, new) Replaces all occurrences of
oldsubstring withnew. Only works with strings.- Example:
version: "1.0.5" ${version.replace('.', '_')}returns1_0_5
- Example:
exec(command).output() Executes a shell command and returns its output. Can be used in conditionals, variable assignments, and string interpolation. Only works within function blocks, not in global variable definitions.
- Example:
build { if ${exec("test -f config.h").output()} { print "config.h exists" } } ${exec("ls -1 | head -n 1").output()}returns the first line of directory listing
- Example:
exec(command).exit() Executes a shell command and returns its exit code (0 for success, non-zero for failure). Can be used in conditionals and comparisons. Only works within function blocks, not in global variable definitions.
- Example:
build { if ${exec("test -f config.h").exit()} == 0 { print "config.h exists" } } ${exec("ls nonexistent").exit()}returns a non-zero exit code if the file doesn’t exist
- Example:
EXAMPLES
Combining methods to construct complex URLs:
version: "2.78.1"
sources:
- "https://download.acme.org/sources/acme/${version.split('.')[0:2].join('.')}/acme-$version.tar.xz"
Using inline exec in conditionals and variable assignments:
build {
if ${exec("test -f config.h").exit()} == 0 {
print "config.h exists"
}
local first_file = ${exec("ls -1 | head -n 1").output()}
print "First file: $first_file"
}
FOR LOOPS
For loops can be used inside all functions. You can access all variables defined in the runfile.
build {
for i in test2 {
print $i
}
}
You can also use inline list literals directly in for loops:
package {
for file in ["tzselect", "zdump", "zic"] {
exec "rm -f $ROOT/usr/bin/$file"
}
}
VARIABLE EXPRESSIONS IN FOR LOOPS
For loops support variable expressions that resolve to lists. This is useful when iterating over dynamic content like command output:
package {
# Iterate over lines from command output
for APPLET in "${exec(\"$ROOT/bin/busybox --list\").output()}" {
print "Processing applet: $APPLET"
}
# Iterate over a variable that contains newline-separated values
local items: "${exec(\"ls -1\").output()}"
for item in "$items" {
print "Item: $item"
}
}
LOOP CONTROL: CONTINUE AND BREAK
Use continue to skip to the next iteration and break to exit the loop entirely:
package {
for APPLET in applets {
# Skip certain applets
if "$APPLET" =~ e"grep|tar|bzip2" {
continue
}
# Stop processing if we hit a specific applet
if "$APPLET" == "STOP" {
break
}
exec "ln -s /bin/busybox $ROOT/bin/$APPLET"
}
}
BUILTIN COMMANDS
These are the built-in commands available in the runfile environment:
- exec: Spawn shell commands. Usage:
exec [COMMAND] - macro: Use macros specifically made for extracting, building, packaging, and testing packages. Supported build systems include cmake, ninja, meson, and GNU Automake. Usage:
macro [NAME] [FLAGS] - print: Print output to stdout. Usage:
print [STRING] - cd: Change directory. Usage:
cd [DIRECTORY] - echo: Alias to
print. Usage:echo [STRING] - local: Allows you to set a local variable inside a function (see CUSTOM FUNCTIONS). Usage:
local [VAR]=[VALUE] - global: Allows you to set and override a global variable inside a function (see CUSTOM FUNCTIONS). Usage:
global [VAR]=[VALUE] - env: Allows you to set and override environment variables inside a function. Usage:
env [VAR]=[VALUE] - write: Write content to a file. Overwrites the file if it exists. Usage:
write [FILE] [STRING] - append: Append content to a file. Creates the file if it does not exist. Usage:
append [FILE] [STRING] - continue: Skip to the next iteration in a for loop. Usage:
continue - break: Exit from a for loop immediately. Usage:
break
See STRINGS for information on multi-line content.
The rest of the shell commands (should you need them) can only be accessed using the exec parameter.
MACROS
Macros are helper commands that simplify common build operations. They are invoked using macro [NAME] [FLAGS].
EXTRACT MACRO
Extracts all archive files in the current directory.
Usage: macro extract [--autocd=true|false]
Flags:
- –autocd: When
true, automatically changes into the extracted directory if there is exactly one directory after extraction. Default isfalse.
Supported archive formats: .tar, .gz, .tgz, .xz, .txz, .bz2, .tbz2, .zip
Example:
prepare {
macro extract --autocd=true
}
This is useful when you need to manually control the extraction process in the prepare function instead of relying on automatic extraction.
STRINGS
Strings can be enclosed in double quotes (") or single quotes (').
For multi-line strings, use triple quotes (""").
write "file.txt" """
Line 1
Line 2
"""
VARIABLES AND FUNCTIONS
CUSTOM FUNCTIONS
Users can define their own reusable functions to avoid repetition. These function blocks follow the same syntax as lifecycle functions (like build or prepare) but require the func keyword.
SYNTAX
Custom functions are defined at the top level of the runfile. They use standard POSIX-like shell argument handling ($1, $2, $@).
func test_function {
print "Hello $1"
}
USAGE
Once defined, custom functions can be called inside any other function block (build, prepare, package, etc.) by simply typing their name and arguments.
build {
test_function "Kreato"
}
SCOPE AND VARIABLES
- Global Variables: Custom functions can access (and modify using the
globalkeyword) all variables defined in the YAML header. This way you can create subpackages that have different properties to the main package. - Local Variables: You can define local variables inside a function using the
localkeyword to prevent exposing them to the rest of the script. - Environment Variables: You can define environment variables inside a function using the
envkeyword to pass that automatically.
func test_variables {
local awesome="yes!"
global name="test2"
env EXAMPLE="test"
print "Is this local? $awesome"
print "The package is named: $name"
exec "echo you know this is a \$EXAMPLE right?"
}
REQUIRED VARIABLES
- name: Name of your package. Displayed in info command output.
- version: Version of your package. Displayed in info command output. Updating this will trigger package upgrade.
- release: Release number of your package. Displayed in info command output. Updating this will trigger package upgrade.
- description: Description of the package. Displayed in info command output.
REQUIRED FUNCTIONS
- package: The installation function that defines how the package should be installed.
SOURCE AND DEPENDENCY VARIABLES
- sources: Source URLs of your package. Can be specified as a list. Supports git URLs as shown in the example.
- depends: Runtime dependencies of your package. Supports version specifications like:
test<=1.8.1: Less than or equal to version 1.8.1test=1.8.1: Exactly version 1.8.1test>=1.8.1: Greater than or equal to version 1.8.1test<1.8.1: Less than version 1.8.1test>1.8.1: Greater than version 1.8.1
- build_depends: Build-time dependencies of your package.
- depends_packagename: Specify dependencies for a specific sub-package. Can be modified using:
depends_packagename+: "packagename"to add a dependencydepends_packagename-: "packagename"to remove a dependencydepends_packagename: "packagename"to replaces dependencies completely
CHECKSUM VARIABLES
- sha256sum: SHA-256 checksums of the sources. Should align with the sources in order.
- sha512sum: SHA-512 checksums of the sources. Should align with the sources in order.
- b2sum: BLAKE2 checksums of the sources. Should align with the sources in order.
Do mind that Git repositories don’t have the checksum ability. You can use SKIP for git sources as this value is ignored.
OPTIONAL VARIABLES
- epoch: Only use when versioning logic fails for the package.
- no_chkupd: Disables auto-updating through chkupd. Default is
false. - extract: Controls whether source archives are automatically extracted before building. Default is
true. Set tofalsefor packages that handle extraction manually or don’t need it. - autocd: Controls whether kpkg automatically changes into the extracted directory after extraction. Default is
truewhenextractistrue, andfalsewhenextractisfalse. When enabled and there is exactly one directory after extraction, kpkg will automaticallycdinto it. - replaces: Specifies packages that this package replaces.
- opt_depends: Optional dependencies for the package, with description after colon.
- conflicts: Specifies packages that conflict with this package.
- is_group: Indicates if the package is a group package. Default is
false. - backup: Preserves files (such as configuration files) during upgrades. Don’t include leading slash (use
etc/bluetooth/main.confinstead of/etc/bluetooth/main.conf). - license: List of SPDX license identifiers for the package (e.g., “MIT”, “GPL-3.0-or-later”, “Apache-2.0”).
OPTIONAL FUNCTIONS
- build: Main build function. Only optional for packages that don’t need to be built (e.g., binary-only packages).
- prepare: Custom preparation procedure. Files from sources are extracted by default unless this function is defined.
- check: Function to test the package.
- preinstall: Runs when the package is installed for the first time (not during upgrades).
- postinstall: Runs after the package is installed.
- preupgrade: Runs before an upgrade occurs.
- postupgrade: Runs after an upgrade completes.
- postremove: Runs after the package is removed.
- package_packagename: Installation function for a sub-package. Allows packaging multiple components in the same runfile.
NAMING CONVENTIONS
Runfile variables are case-insensitive and support multiple naming styles:
- camelCase (e.g.,
buildDepends) - PascalCase (e.g.,
BuildDepends) - kebab-case (e.g.,
build-depends) - snake_case (e.g.,
build_depends)
snake_case is recommended for most runfiles.
Important: Functions are case-sensitive and do not support this flexibility.
AUTHOR
Written by Kreato.
COPYRIGHT
kpkg is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
kpkg is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with kpkg. If not, see https://www.gnu.org/licenses/.