aboutsummaryrefslogtreecommitdiff
path: root/docs/cpt.txt
diff options
context:
space:
mode:
Diffstat (limited to 'docs/cpt.txt')
-rw-r--r--docs/cpt.txt1109
1 files changed, 1109 insertions, 0 deletions
diff --git a/docs/cpt.txt b/docs/cpt.txt
new file mode 100644
index 0000000..48c954d
--- /dev/null
+++ b/docs/cpt.txt
@@ -0,0 +1,1109 @@
+ _______________________
+
+ CARBS PACKAGING TOOLS
+ User Manual
+
+ Cem Keylan
+ _______________________
+
+
+ February 04, 2021
+
+
+Table of Contents
+_________________
+
+1. Copying
+2. Preface
+3. Usage
+.. 1. cpt-alternatives
+.. 2. cpt-build
+.. 3. cpt-checksum
+.. 4. cpt-download
+.. 5. cpt-install
+.. 6. cpt-list
+.. 7. cpt-remove
+.. 8. cpt-search
+.. 9. cpt-update
+.. 10. Global Flags
+4. Environment Variables
+.. 1. `CPT_PATH'
+..... 1. Repository preferences
+..... 2. Setting the `CPT_PATH'
+.. 2. `CPT_COMPRESS'
+.. 3. `CPT_FORCE'
+.. 4. `CPT_PID'
+5. Hooks
+.. 1. Editing the `build' file during pre-build
+6. Packaging System
+.. 1. `build'
+.. 2. `sources'
+.. 3. `checksums'
+.. 4. `version'
+.. 5. `depends'
+.. 6. `post-install'
+.. 7. `message'
+.. 8. `test'
+7. Rsync Repositories
+.. 1. Setting up an Rsync repository
+8. CPT Library
+.. 1. Calling the library
+.. 2. Option parsing
+..... 1. Defining a parser
+..... 2. `global_options()'
+.. 3. Message functions
+..... 1. `out()'
+..... 2. `log()'
+..... 3. `die()'
+..... 4. `warn()'
+..... 5. `prompt()'
+.. 4. Text functions
+..... 1. `contains()'
+..... 2. `regesc()'
+..... 3. `pop()'
+..... 4. `sepchar()'
+.. 5. Portability functions
+..... 1. `_seq()'
+..... 2. `_stat()'
+..... 3. `_readlinkf()'
+.. 6. TODO System Functions
+..... 1. `as_root()'
+.. 7. TODO Package Functions
+..... 1. `pkg_owner()'
+..... 2. `pkg_isbuilt()'
+..... 3. `pkg_lint()'
+..... 4. TODO `pkg_find()'
+..... 5. TODO `pkg_gentree'
+
+
+This is a reference document containing both the user-guide and the
+development manual for *Carbs Packaging Tools*. For development logs see
+[the git repository].
+
+
+[the git repository] <https://git.carbslinux.org/cpt>
+
+
+1 Copying
+=========
+
+ Copyright (c) 2020 Cem Keylan
+
+ Permission is granted to copy, distribute and/or modify
+ this document under the terms of the GNU Free
+ Documentation License, Version 1.3 or any later version
+ published by the Free Software Foundation; with no
+ Invariant Sections, with no Front-Cover Texts and no
+ Back-Cover Texts. A copy of the license is included in the
+ section entitled "GNU Free Documentation License."
+
+
+2 Preface
+=========
+
+ Carbs Linux uses its own package management toolchain named `cpt'
+ which was initially forked from the [kiss] package manager. Unlike
+ `kiss', however, its main goal is being easily extendable. Instead of
+ being a single file package manager, it revolves around the shell
+ library `cpt-lib', and many tools that wrap around it. This document
+ aims to document both the usage of the distributed tools and document
+ the library functions.
+
+
+[kiss] <https://github.com/kisslinux/kiss>
+
+
+3 Usage
+=======
+
+ `cpt' is formed of many tools combined in a single environment,
+ similar to `git'. When you run `cpt' without any arguments, it will
+ show all available tools and their explanations. Here is an example
+ call with extra scripts on my system:
+
+ ,----
+ | -> Carbs Packaging Tool
+ | -> add Commit the current directory as a new package
+ | -> alternatives List and swap to alternatives
+ | -> build Build a package
+ | -> bump Commit the current directory as a version bump
+ | -> cargo-urlgen Create static cargo sources for Rust packages
+ | -> cargolock-urlgen Convert the given Cargo.lock file to sources
+ | -> cat Concatanate package files in the installed package database
+ | -> changelog Print the git log of the specific package
+ | -> chbuild Create/destroy temporary chroots
+ | -> checkmissing Verify package manifests
+ | -> checksum Generate checksums
+ | -> chroot Enter a chroot
+ | -> commit Commit a package without the prefix of 'package:'
+ | -> depends Display a package's dependencies
+ | -> download Download sources for the given package
+ | -> exec Execute a command inside the alternatives system
+ | -> export Turn an installed package into a CPT tarball
+ | -> fork Fork a package to the current directory
+ | -> getchoice Prints the full path to a file in the alternatives system.
+ | -> install Install a package
+ | -> link Link a forked package's files to the other repository
+ | -> list List installed packages
+ | -> maintainer Find the maintainer of a package
+ | -> manifest Display all files owned by a package
+ | -> manifest-tree Display all files owned by a package with a tree view
+ | -> new Create a boilerplate CPT package
+ | -> orphans List orphaned packages
+ | -> owns Check which package owns a file
+ | -> rel Bump the release number of a package
+ | -> remove Remove a package
+ | -> repodepends Display a package's dependencies in the repository
+ | -> reporevdepends Display packages on the repository which depend on package
+ | -> reset Remove all packages except for the base
+ | -> revdepends Display packages which depend on package
+ | -> search Search for a package
+ | -> size Show the size on disk for a package
+ | -> source Extract sources of a given package to the current directory
+ | -> update Check for updates
+ `----
+
+
+3.1 cpt-alternatives
+~~~~~~~~~~~~~~~~~~~~
+
+ You can list and swap to alternatives using `cpt-alternatives', or
+ `cpt a' for short. When run without alternatives, it will list
+ alternatives. It can read from standard input if `-' is given as an
+ argument.
+
+ *Examples*
+
+ 1. List alternatives.
+
+ ,----
+ | $ cpt-alternatives
+ | ncurses /usr/bin/clear
+ | ncurses /usr/bin/reset
+ `----
+
+ 1. Swap to `clear' from `ncurses'.
+
+ ,----
+ | $ cpt-alternatives ncurses /usr/bin/clear
+ | -> Swapping '/usr/bin/clear' from 'busybox' to 'ncurses'
+ `----
+
+ 1. Swap in bulk (all of `sbase').
+
+ ,----
+ | $ cpt a | grep ^sbase | cpt a -
+ `----
+
+
+3.2 cpt-build
+~~~~~~~~~~~~~
+
+ `cpt-build' will build given packages and their dependencies. If
+ multiple packages are specified, it will ask to install the packages
+ as well.
+
+ Flags Explanation
+ -----------------------------
+ `-t', `--test' Run tests
+
+
+3.3 cpt-checksum
+~~~~~~~~~~~~~~~~
+
+ `cpt-checksum' will generate a `checksums' file from the package's
+ sources.
+
+
+3.4 cpt-download
+~~~~~~~~~~~~~~~~
+
+ `cpt-download' will download the sources of a package.
+
+
+3.5 cpt-install
+~~~~~~~~~~~~~~~
+
+ `cpt-install' will install given packages.
+
+
+3.6 cpt-list
+~~~~~~~~~~~~
+
+ When called without arguments, `cpt-list' will print all installed
+ packages. You can add package names as arguments to check whether they
+ are installed or not. In success, `cpt-list' will exit with status 0
+ if all given packages are installed, it will return 1 if any of the
+ given packages aren't installed.
+
+ Flags Explanation
+ -----------------------------------------------------------
+ `-c', `--current' Use the current directory as a package
+
+
+3.7 cpt-remove
+~~~~~~~~~~~~~~
+
+ `cpt-remove' will remove given packages.
+
+
+3.8 cpt-search
+~~~~~~~~~~~~~~
+
+ `cpt-search' will search for packages, it accepts regular expressions
+ as well.
+
+ Flags Explanation
+ -------------------------------------------------------------
+ `-s', `--single' Only show the first instance of a package
+
+
+ ,----
+ | $ cpt-search 'alsa-*'
+ | /var/db/cpt/repo/extra/alsa-lib
+ | /var/db/cpt/repo/extra/alsa-utils
+ | /var/db/cpt/installed/alsa-lib
+ | /var/db/cpt/installed/alsa-utils
+ |
+ | $ cpt-search emacs
+ | /home/cem/repos/main/community/emacs
+ | /home/cem/repos/kiss-community/community/emacs
+ | /var/db/cpt/installed/emacs
+ |
+ | $ cpt-search --single emacs
+ | /home/cem/repos/main/community/emacs
+ `----
+
+
+3.9 cpt-update
+~~~~~~~~~~~~~~
+
+ `cpt-update' will update the packages on your system. It fetches
+ remote repositories, and builds, and installs packages that have
+ versions different from the ones installed on the system. It doesn't
+ check if the version string is actually higher, it only checks whether
+ they differ.
+
+ Flags Explanation
+ ------------------------------------------------------------
+ `-d', `--download' Only download updatable packages
+ `-n', `--no-fetch' Do not update remote repositories
+ `-o', `--only-fetch' Only fetch the repositories and exit
+
+
+3.10 Global Flags
+~~~~~~~~~~~~~~~~~
+
+ Flags Explanation
+ ---------------------------------------------------------
+ `-f', `--force' Force operation, [See `CPT_FORCE']
+ `-y', `--no-prompt' Do not prompt for confirmation
+ `-root CPT_ROOT' Use an alternate root directory
+ `-h', `--help' Show this help message
+ `-v', `--version' Print version information
+
+
+[See `CPT_FORCE'] See section 4.3
+
+
+4 Environment Variables
+=======================
+
+ Since there is no configuration file for cpt, the package manager is
+ configured through environment variables. These can be set per
+ operation, or be set to your shell configuration or `~/.profile'. Here
+ are the environment variables that alter the behaviour of `cpt':
+
+ ENVIRONMENT VARIABLE Effects
+ -----------------------------------------------------------------------------------------------------
+ `CPT_PATH' Set the locations of your repositories. It is similar to the `PATH' variable.
+ `XDG_CACHE_HOME' Unless this is set, the `~/.cache' directory will be used instead.
+ `CPT_CACHE' The cache directory for `cpt'. Default: `$XDG_CACHE_HOME/cpt'
+ `CPT_CHOICE' If this is set to 0, a package installation will be aborted on conflicts.
+ `CPT_COMPRESS' Program used to compress package tarballs.
+ `CPT_DEBUG' If set to 1, temporary directories will not be removed after the operation.
+ `CPT_FETCH' If set to 0, `cpt-update' will not fetch repositories.
+ `CPT_FORCE' Force operation.
+ `CPT_HOOK' Location for the hook file.
+ `CPT_KEEPLOG' If set to 1, cpt will keep logs regardless of operation success.
+ `CPT_PID' Set the temporary build directory name.
+ `CPT_PROMPT' If set to 0, `cpt' will not prompt you for anything.
+ `CPT_ROOT' If this variable is set, `cpt' will assume this as the system root.
+ `CPT_TEST' If set to 1, `cpt-build' will run tests whenever available.
+ `CPT_TMPDIR' The directory to create the temporary directories.
+
+
+4.1 `CPT_PATH'
+~~~~~~~~~~~~~~
+
+ Similar to the `PATH' variable, `cpt' find repositories from the
+ `CPT_PATH' variable. Here is an example:
+
+ ,----
+ | CPT_PATH=$HOME/repos/repo1:$HOME/repos/repo2:$HOME/repos/repo3
+ `----
+
+ This is a simplistic and a structured example for repository
+ locations, but it doesn't necessarily need to be as tidy as the
+ example above. Here is an example for something a little more complex.
+
+ ,----
+ | CPT_PATH=$HOME/repos/overrides:/var/db/cpt/repo/core:/var/db/cpt/repo/extra:$HOME/repos/personal
+ `----
+
+ This example brings us to the next section of this document.
+
+
+4.1.1 Repository preferences
+----------------------------
+
+ When you are using multiple repositories from multiple vendors, you
+ will find out that some repositories have the same packages. `cpt'
+ doesn't care about conflicting packages. If you want to build a
+ package that exists on multiple repositories, `cpt' will build the
+ first matching package. This means that if `grep' package (for the
+ sake of an example) exists on both `$HOME/repos/personal' and
+ `$HOME/repos/carbs/extra', and you want to install from your personal
+ repository, you must set `CPT_PATH' so that your personal repository
+ is listed before the `extra' repository.
+
+ ,----
+ | CPT_PATH=$HOME/repos/personal:$HOME/repos/carbs/extra
+ `----
+
+
+4.1.2 Setting the `CPT_PATH'
+----------------------------
+
+ You can set the `CPT_PATH' variable on your shell configuration or
+ your `.profile' file in a way that is easy to read.
+
+ The below example sets `CPT_PATH' in a way that is easy to understand
+ which repository comes first:
+
+ ,----
+ | CPT_PATH=$HOME/repos/overrides
+ | CPT_PATH=$CPT_PATH:$HOME/repos/carbs/core
+ | CPT_PATH=$CPT_PATH:$HOME/repos/carbs/extra
+ | CPT_PATH=$CPT_PATH:$HOME/repos/carbs/xorg
+ | CPT_PATH=$CPT_PATH:$HOME/repos/personal
+ | export CPT_PATH
+ `----
+
+
+4.2 `CPT_COMPRESS'
+~~~~~~~~~~~~~~~~~~
+
+ When setting the `CPT_COMPRESS' value, you should set the name of the
+ default suffixes for the program. Available values are:
+
+ - `gz'
+ - `zst'
+ - `bz2'
+ - `xz'
+
+ Defaults to `gz'.
+
+
+4.3 `CPT_FORCE'
+~~~~~~~~~~~~~~~
+
+ If this is set to 1, some of the `cpt' tools will continue regardless
+ of errors or skip certain checks. Here are some examples:
+
+ - `cpt-install' will install a package without verifying its manifest.
+ - `cpt-install' will install a package even when there are missing
+ dependencies.
+ - `cpt-remove' will remove packages even when there are other packages
+ that depend on the current package.
+
+ Defaults to 0.
+
+
+4.4 `CPT_PID'
+~~~~~~~~~~~~~
+
+ If this variable is set, the temporary files will be created with this
+ variable as the suffix, instead of the PID of the `cpt' process. The
+ advantage is that you can know exactly where the build directory is
+ located, while the disadvantage is that there will be issues with
+ multiple operations at the same time. So the best way to use this
+ variable is during one-time `cpt' calls.
+
+ ,----
+ | CPT_PID=mesa cpt b mesa
+ `----
+
+ By running the above, you will know that the created build directories
+ will end with the `*-mesa' suffix.
+
+
+5 Hooks
+=======
+
+ Hooks can be used in order to change the runtime behaviour of the
+ package manager. There are a variety of package hooks, mostly self
+ explanatory:
+
+ - pre-build
+ - post-build
+ - build-fail
+ - pre-test
+ - test-fail
+ - pre-install
+ - post-install
+ - pre-remove
+ - post-remove
+ - pre-fetch
+ - post-fetch
+ - post-package
+
+ In order to use hooks, you will need to set the `CPT_HOOK' variable
+ pointing to your hook file. Your hook file *MUST* be a POSIX shell
+ script as its contents are sourced by the package manager.
+
+ The hook is given 3 variables when it is executed. Those are:
+
+ Variable Explanation
+ ------------------------------------------------------------------------
+ `$TYPE' The type of the hook, (`pre-build', `post-build', etc.)
+ `$PKG' The package that `cpt' is currently working on. Can be null.
+ `$DEST' The destination of the operation. Can be null.
+
+
+5.1 Editing the `build' file during pre-build
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ You can edit the `build' file during pre-build. The file is copied
+ from the repository to the build directory named as `.build.cpt'. You
+ can use `sed' or any other tool to edit the build file. After the
+ build is complete, a `diff' file will be placed to the package
+ database named as `build.diff'. Here is an example `build' file
+ manipulation during the pre-build hook.
+
+ ,----
+ | cat <<EOF> .build.cpt
+ | #!/bin/sh -e
+ |
+ | for patch in bash50-0??; do
+ | patch -p0 < "\$patch"
+ | done
+ |
+ | export LDFLAGS=-static
+ |
+ | ./configure \
+ | --prefix=/usr \
+ | --without-bash-malloc \
+ | --disable-nls
+ |
+ | export MAKEFLAGS="TERMCAP_LIB=/usr/lib/libncursesw.a $MAKEFLAGS"
+ |
+ | make
+ | make DESTDIR="\$1" install
+ |
+ | ln -s bash "\$1/usr/bin/sh"
+ | EOF
+ `----
+
+
+6 Packaging System
+==================
+
+ A package is formed of several files, these are:
+
+ - 6.1
+ - 6.2
+ - 6.3
+ - 6.4
+ - 6.5
+ - 6.6
+ - 6.7
+ - 6.8
+
+ Any other file can be added to the package directory at the discretion
+ of the package maintainer. Everything in the package directory will
+ also be added to the package database that is located on
+ `/var/db/cpt/installed'. These can be patches, configuration files,
+ etc.
+
+
+6.1 `build'
+~~~~~~~~~~~
+
+ Typically `build' files are shell scripts that run commands to prepare
+ the source code to be installed on the target system. Even though we
+ will be assuming that the `build' file is a POSIX shell script (for
+ portability's sake), `build' files can be any executable program from
+ binary programs to `perl' scripts.
+
+ The contents of a build script do not need to follow a certain rule
+ for the package manager, except for the fact that the user needs the
+ permission to execute the file.
+
+ An important advice is to append an '-e' to the shebang (#!/bin/sh -e)
+ so that the build script exits on compilation error.
+
+ Build is run with three arguments (`$#')
+
+ - Location of the package directory (DESTDIR)
+ - Package version
+ - System architecture
+
+
+6.2 `sources'
+~~~~~~~~~~~~~
+
+ `sources' file is a list of files and sources that will be put to the
+ build directory during the build process. Those can be remote sources
+ (such as tarballs), git repositories, and files that reside on the
+ package directory.
+
+ The syntax is pretty simple for the `soures' file; `src dest'. The
+ `dest' parameter is optional. It is the directory that the source will
+ be placed in. Here is the `sources' file for the `gst-plugins'
+ package:
+
+ ,----
+ | https://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins-good-1.16.2.tar.xz good
+ | https://gstreamer.freedesktop.org/src/gst-plugins-bad/gst-plugins-bad-1.16.2.tar.xz bad
+ | https://gstreamer.freedesktop.org/src/gst-plugins-ugly/gst-plugins-ugly-1.16.2.tar.xz ugly
+ | https://gstreamer.freedesktop.org/src/gst-libav/gst-libav-1.16.2.tar.xz libav
+ `----
+
+ This file is read from the package manager as space seperated. Files
+ that begin with a `#' comment are ignored. The first value points to
+ the location of the source.
+
+ If it starts with a protcol url, (such as <ftp://> <http://>
+ <https://>) it will be downloaded with `curl'.
+
+ If the source is a git repository, it shall be prefixed with a `git+'
+ git(1) will be used to do a shallow clone of the repository. If the
+ commit is suffixed by a history pointer, git will checkout the
+ relevant revision. So,
+
+ `git+git://example.com/pub/repo@v1.2.3'
+ will checkout the tag named "v1.2.3"
+ `git+git://example.com/pub/repo#development'
+ will checkout the branch named "development"
+ `git+git://example.com/pub/repo#1a314s87'
+ will checkout the commit named "1a314s87"
+
+ Other files are assumed to be residing in the package directory. They
+ should be added with their paths relative to the package directory.
+
+
+6.3 `checksums'
+~~~~~~~~~~~~~~~
+
+ checksums file is generated by the `cpt c pkg' command. It is
+ generated according to the order of the sources file. That's why you
+ shouldn't be editing it manually. The checksums file is created with
+ the digests of the files using the sha256 algorithm.
+
+
+6.4 `version'
+~~~~~~~~~~~~~
+
+ The version file includes the version of the software and the release
+ number of of the package on a space seperated format. The contents of
+ the file should look like below.
+
+ ,----
+ | 1.3.2 1
+ `----
+
+
+6.5 `depends'
+~~~~~~~~~~~~~
+
+ This is a list of dependencies that must be installed before a package
+ build. You can append "make" after a dependency to mark a package is
+ only required during the build process of a package. Packages marked
+ as a make dependency can be removed after the build. There are also
+ "test" dependencies. These dependencies are only installed if either
+ the `CPT_TEST' is set to 1, or the build is run with the `-t' or
+ `--test' options. So, a package package could have the following
+ `depends' file:
+
+ ,----
+ | linux-headers make
+ | python test
+ | zlib
+ `----
+
+
+6.6 `post-install'
+~~~~~~~~~~~~~~~~~~
+
+ `post-install' files have the same requirements as the build
+ script. They will be run after the package is installed as root (or as
+ the user if the user has write permissions on `CPT_ROOT').
+
+
+6.7 `message'
+~~~~~~~~~~~~~
+
+ This plaintext file will be outputted with `cat' after every package
+ is installed.
+
+
+6.8 `test'
+~~~~~~~~~~
+
+ Test files are mainly for the repository maintainer to test the
+ packages, and will only run if the user has the `CPT_TEST' variable
+ set, or the build is run with the `-t' or `--test' options. This
+ script is run on the build directory. It is run right after the build
+ script is finished.
+
+
+7 Rsync Repositories
+====================
+
+ Rsync repositories are simple to serve and simple to use. In the
+ repository directory, there needs to be a `.rsync' file that points to
+ the remote of the repository. This is used in order to fetch changes
+ from the upstream. `.rsync' file looks like this for the core
+ repository:
+
+ ,----
+ | rsync://carbslinux.org/repo/core
+ `----
+
+ Rsync repositories have some few distinctions when it comes to
+ fetching them. They can be either synced individually or as a
+ "root". There are 2 important files, those are `.rsync' and
+ `.rsync_root'. Here is the Carbs Linux rsync repository structure.
+
+ ,----
+ | /
+ | -----------------
+ | | |
+ | .rsync core/
+ | ----------------
+ | | |
+ | .rsync .rsync_root
+ `----
+
+ Unlike git repositories, they don't have a defined "root"
+ directory. This is both an advantage and a disadvantage. This way, we
+ can sync individual repositories, but that also means we need extra
+ files to define root directories and repository locations. Here is the
+ content for each of these files:
+
+ ,----
+ | /.rsync: rsync://carbslinux.org/repo
+ | /core/.rsync: rsync://carbslinux.org/repo/core
+ | /core/.rsync_root: ..
+ `----
+
+ The `.rsync_root' file on the core repository points to the upper
+ directory. If a `.rsync' file exists on the upper directory, this
+ means that is the whole repository and will sync the entire repository
+ instead of each individual repository.
+
+ If the upper directory doesn't have this `.rsync' file, this means
+ that this is an individual repository, and the package manager will
+ fetch accordingly.
+
+
+7.1 Setting up an Rsync repository
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Carbs Linux repositories automatically sync from the git repostitories
+ and serve it through the rsync daemon. Here is a sample shell script
+ that I use in order to sync repositories. Feel free to customize for
+ your own use.
+
+ ,----
+ | #!/bin/sh
+ | HOSTNAME="rsync://carbslinux.org/repo"
+ | GITDIR="/pub/git/repo"
+ | SHAREDIR="/pub/share/repo"
+ | git -C "$GITDIR" pull
+ |
+ | rsync -avcC --delete --include=core --exclude=.rsync,.rsync_root "$GITDIR/." "$SHAREDIR"
+ |
+ | printf '%s\n' "$HOSTNAME" > "$GITDIR/.rsync"
+ | for dir in "$GITDIR/"*; do
+ | [ -d "$dir" ] || continue
+ | [ -f "$dir/.rsync" ] ||
+ | printf '%s/%s\n' "$HOSTNAME" "${dir##*/}" > "$dir/.rsync"
+ | printf '..\n' > "$dir/.rsync_root"
+ | done
+ `----
+
+ You can then create an *rsync* user for serving the repositories.
+
+ ,----
+ | $ adduser -SD rsync
+ `----
+
+ Create `/etc/rsyncd.conf' and a service configuration as well.
+
+ ,----
+ | uid = rsync
+ | gid = rsync
+ | address = example.com
+ | max connections = 10
+ | use chroot = yes
+ |
+ | [repo]
+ | path = /pub/share/repo
+ | comment = My repository
+ `----
+
+ Create a service file at `/etc/sv/rsync/run' (runit):
+
+ ,----
+ | #!/bin/sh -e
+ | exec rsync --daemon --no-detach
+ `----
+
+
+8 CPT Library
+=============
+
+ `cpt-lib' is the library of Carbs Packaging Tools which can be used to
+ extend the functionality of the package manager. This is the API
+ documentation of the package manager library.
+
+
+8.1 Calling the library
+~~~~~~~~~~~~~~~~~~~~~~~
+
+ You can call the library on your scripts by adding the following line
+ to your files:
+
+ ,----
+ | #!/bin/sh -e
+ | . cpt-lib
+ `----
+
+ This will load the library inside your script, and will set some
+ environment variables that are used inside the package manager.
+
+
+8.2 Option parsing
+~~~~~~~~~~~~~~~~~~
+
+ `cpt-lib' includes a POSIX-shell option parser inside named
+ `getoptions'. You can see its own [documentation] for writing an
+ option parser. The built-in version of the `getoptions' library is
+ 2.0.1 and there are no plans for updating it apart from bug fixes.
+
+
+[documentation]
+<https://github.com/ko1nksm/getoptions/blob/v2.0.1/README.md>
+
+8.2.1 Defining a parser
+-----------------------
+
+ Some functions are called and set automatically when you call
+ `cpt-lib', so you shouldn't define the option parser after calling the
+ library, as some of the variables will already be set.
+
+ If the function `parser_definition()' as defined when `cpt-lib' is
+ called, cpt-lib will handle the option parsing itself by calling
+ `getoptions' inside. Here is the proper way of doing it.
+
+ ,----
+ | #!/bin/sh -e
+ |
+ | parser_definition() {
+ | # The rest arguments MUST be defined as 'REST'
+ | setup REST help:usage -- "usage: ${0##*/} [options] [pkg...]"
+ | msg -- '' 'Options:'
+ | flag CPT_TEST -t export:1 init:@export -- "Enable tests"
+ |
+ | global_options
+ | }
+ |
+ | . cpt-lib
+ `----
+
+
+8.2.2 `global_options()'
+------------------------
+
+ The `global_options()' function is a simple convenience call to
+ include flags that can be used inside most `cpt' tools. It defines the
+ following flags:
+
+ Flag Long Option Calls
+ ---------------------------------
+ -f --force `CPT_FORCE'
+ -y --no-prompt `CPT_PROMPT'
+ --root `CPT_ROOT'
+ -h --help `usage()'
+ -v --version `version()'
+
+
+8.3 Message functions
+~~~~~~~~~~~~~~~~~~~~~
+
+ `cpt' has various functions to print information to users.
+
+
+8.3.1 `out()'
+-------------
+
+ `out()' is a really simple function that prints messages to the
+ standard output. It prints every argument with a newline. It is not
+ meant to communicate with the user, it just exists to have a simple
+ function to interact with other functions.
+
+ ,----
+ | $ out "This is an example call" "How are you?"
+ | This is an example call
+ | How are you?
+ `----
+
+
+8.3.2 `log()'
+-------------
+
+ `log()' is the most commonly used message function in the package
+ manager. It is used to pretty print messages with visual cues, so it
+ is easier to read and understand for the users. It changes message
+ output for each argument it receives (takes up to three arguments).
+
+ - If it takes a single argument, it prints a yellow leading arrow
+ followed by colorless text.
+ - If it takes two arguments, it prints a yellow leading arrow followed
+ by the first argument (colored blue), and then followed by colorless
+ second argument.
+ - If it takes three arguments, instead of a yellow arrow, it prints
+ the third argument in yellow, followed by the same two arguments as
+ above.
+
+
+8.3.3 `die()'
+-------------
+
+ `die()' wraps the `log()' function and exits with an error (1). It
+ takes one or two arguments, which are sent to the `log()'
+ function. The third argument for `log()' is set as `!>'.
+
+
+8.3.4 `warn()'
+--------------
+
+ `warn()' is another function that wraps `log()'. In place of the third
+ argument, it uses the word `WARNING'.
+
+
+8.3.5 `prompt()'
+----------------
+
+ `prompt()' is an interactive function that waits for user input to
+ continue. It takes a single argument string to print a message, and
+ then asks the user whether they want to continue or not. Prompts can
+ be disabled by the user if they use a flag to disable them or set
+ `CPT_PROMPT' to 0.
+
+
+8.4 Text functions
+~~~~~~~~~~~~~~~~~~
+
+ Following functions are used to manipulate, check, or interact with
+ text.
+
+
+8.4.1 `contains()'
+------------------
+
+ `contains' function can be used to check whether a list variable
+ contains a given string. If the string is inside the list, it will
+ return 0, otherwise 1.
+
+ ,----
+ | # Usage
+ | contains "$LIST" foo
+ |
+ | contains "foo bar" foo # Returns 0
+ | contains "foo bar" baz # Returns 1
+ `----
+
+
+8.4.2 `regesc()'
+----------------
+
+ `regesc()' can be used to escape regular expression characters that
+ are defined in POSIX BRE. Those characters are, `$', `.', `*', `[',
+ `\\', and `^'.
+
+ ,----
+ | regesc '^[$\' # Returns \^\[\$\\
+ `----
+
+
+8.4.3 `pop()'
+-------------
+
+ `pop()' can be used to remove a word from a "string list" without a
+ `sed' call. Word splitting is intentional when using this function.
+
+ ,----
+ | # Usage
+ | pop foo from $LIST
+ |
+ | pop foo from foo baz bar # Returns baz bar
+ `----
+
+
+8.4.4 `sepchar()'
+-----------------
+
+ This function can be used to separate characters from the given string
+ without resorting to external resources.
+
+ ,----
+ | sepchar mystring
+ | # Prints:
+ | # m
+ | # y
+ | # s
+ | # t
+ | # r
+ | # i
+ | # n
+ | # g
+ `----
+
+
+8.5 Portability functions
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ These helper functions are used so that we don't depend on non-POSIX
+ programs for certain functionality. They are prefixed with the `_'
+ character.
+
+
+8.5.1 `_seq()'
+--------------
+
+ This function is similar to `seq(1)' except that it only takes a
+ single argument and doesn't print any newlines. It is suitable to be
+ used in `for' loops.
+
+ ,----
+ | _seq 5
+ | # Prints:
+ | # 1 2 3 4 5
+ `----
+
+
+8.5.2 `_stat()'
+---------------
+
+ This function imitates `stat %U'. `stat' isn't defined by POSIX, and
+ this is also a GNU extension. This function returns the owner of a
+ file. If the owner cannot be found, it will return `root'.
+
+
+8.5.3 `_readlinkf()'
+--------------------
+
+ This function was taken from [POSIX sh readlinkf library by Koichi
+ Nakashima]. `readlink' is also not defined by POSIX, so this function
+ uses `ls' to follow symbolic links until it reaches the actual file.
+
+
+[POSIX sh readlinkf library by Koichi Nakashima]
+<https://github.com/ko1nksm/readlinkf>
+
+
+8.6 TODO System Functions
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ - [ ] Add description
+
+
+8.6.1 `as_root()'
+-----------------
+
+ `as_root()' calls the rest of the arguments as a different
+ user. Unless a `user' environment variable is set, it will call the
+ following arguments as the root user. It supports the following
+ programs for privilege escalation with the following order:
+
+ 1. `sls'
+ 2. `sudo'
+ 3. `doas'
+ 4. `su'
+
+
+8.7 TODO Package Functions
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Obviously, package functions are the most important ones for
+ `cpt-lib', those are the ones you will use to build, to query, to
+ manipulate, or to otherwise interact with packages.
+
+
+8.7.1 `pkg_owner()'
+-------------------
+
+ This function can be used to determine the owner of a package. The
+ first argument is used for flags that will be passed to `grep', and
+ the second one is for the file query. Rest of the arguments can be
+ used in order to specify the manifests to be used, but it is
+ optional. `pkg_owner()' will search for all the installed packages if
+ no other arguments are given.
+
+ ,----
+ | # Example
+ | pkg_owner -lFx /usr/bin/grep # Returns 'busybox'
+ |
+ | # An example call made by `pkg_fix_deps()` to figure out whether the built
+ | # package contains the file it depends.
+ | pkg_owner -l "/${dep#/}\$" "$PWD/manifest" >/dev/null && continue
+ | pkg_owner -l "/${dep#/}\$" "$@" ||:
+ `----
+
+
+8.7.2 `pkg_isbuilt()'
+---------------------
+
+ This function returns with success when the given package has a built
+ tarball with the matching version and release strings from the
+ repository.
+
+
+8.7.3 `pkg_lint()'
+------------------
+
+ This function checks whether a given package fits the proper package
+ specification. This function *does not return with failure, it exits
+ outright* if it fails.
+
+
+8.7.4 TODO `pkg_find()'
+-----------------------
+
+ `pkg_find()' is the tool for searching packages. It accepts up to 3
+ arguments.
+
+ $1: Query
+ This is the only mandatory argument. It accepts globbing,
+ meaning that shell wildcards can be used in the query.
+ $2: Match
+ If this exists `pkg_find()' will print every single match found
+ in the search path. If it doesn't, `pkg_find()' will print the
+ first match and exit.
+ $3: Type
+ This is the argument to be passed to the `test' function. Unless
+ this argument is given, it defaults to `-d', which tests for
+ directories.
+
+ ,----
+ | pkg_find cpt
+ `----
+
+
+8.7.5 TODO `pkg_gentree'
+------------------------
+
+ Keep in mind /etc/cpt-base