@c This document is part of Carbs Linux Documentation. @c See the top.texi file for LICENSE information. @c ----------------------------------------------------------------------------- @c Macros @macro optbehsingle{opt} This behaviour can also be achieved by adding @option{\opt\} as an argument @end macro @macro optbeh{opt, opt2} This behaviour can also be achieved by adding @option{\opt\} or @option{\opt2\} as an argument @end macro @c ----------------------------------------------------------------------------- @c TODO add extending the package manager @node Package Manager @chapter Package Manager Carbs Linux uses its own package managing toolchain named @code{cpt}. It is a fork of the @url{https://github.com/kisslinux/kiss, kiss} package manager. Unlike @command{kiss}, however, its main goal is being easily extendable. Instead of being a single file package manager, it revolves around the shell library @command{cpt-lib}, and many tools that wrap around it. @menu * Usage:: Using Carbs Packaging Tools * Environment Variables:: Values that affect the operation of CPT * Hooks:: Using hooks to customize the package manager operations * Packaging System:: More detail on creating packages * Rsync Repositories:: Information on using or creating rsync repositories @end menu @c ----------------------------------------------------------------------------- @node Usage @section Usage @command{cpt} is formed of many tools combined in a single environment, similar to @command{git}. When you run @command{cpt} without any arguments, it will show all available tools and their explanations. Here is an example call with extra scripts on my system: @example -> 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 -> fetch Fetch repositories -> 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 @end example @menu * @command{cpt-alternatives}:: * @command{cpt-build}:: * @command{cpt-checksum}:: * @command{cpt-download}:: * @command{cpt-fetch}:: * @command{cpt-install}:: * @command{cpt-list}:: * @command{cpt-remove}:: * @command{cpt-search}:: * @command{cpt-update}:: @end menu @c ----------------------------------------------------------------------------- @node @command{cpt-alternatives} @subsection @command{cpt-alternatives} You can list and swap to alternatives using @command{cpt-alternatives}, or @command{cpt a} for short. When run without alternatives, it will list alternatives. It can read from standard input if @option{-} is given as an argument. @c ----------------------------------------------------------------------------- @unnumberedsubsubsec Examples List alternatives @example $ cpt-alternatives ncurses /usr/bin/clear ncurses /usr/bin/reset @end example Swap to @command{clear} from @command{ncurses}. @example $ cpt-alternatives ncurses /usr/bin/clear -> Swapping '/usr/bin/clear' from 'busybox' to 'ncurses' @end example Swap in bulk (all of sbase). @example $ cpt a | grep ^sbase | cpt a - @end example @c ----------------------------------------------------------------------------- @node @command{cpt-build} @subsection @command{cpt-build} @command{cpt-build} will build given packages and their dependencies. If multiple packages are specified, it will ask to install the packages as well. @c ----------------------------------------------------------------------------- @unnumberedsubsubsec Options @table @option @item -y --no-prompt Do not prompt for confirmation @item -t --test Run tests (if it exists) @end table @c ----------------------------------------------------------------------------- @node @command{cpt-checksum} @subsection @command{cpt-checksum} @command{cpt-checksum} will generate a @file{checksums} file from the package's sources. @c ----------------------------------------------------------------------------- @node @command{cpt-download} @subsection @command{cpt-download} @command{cpt-download} will download the sources of a package. @c ----------------------------------------------------------------------------- @node @command{cpt-fetch} @subsection @command{cpt-fetch} @command{cpt-fetch} will fetch remote repositories. @c ----------------------------------------------------------------------------- @node @command{cpt-install} @subsection @command{cpt-install} @command{cpt-install} will install given packages. @c ----------------------------------------------------------------------------- @unnumberedsubsubsec Options @table @option @item -f --force Force installation. @xref{cptforce,,@env{CPT_FORCE}}. @item --root Set an alternative root directory. @xref{cptroot,,@env{CPT_ROOT}}. @end table @c ----------------------------------------------------------------------------- @node @command{cpt-list} @subsection @command{cpt-list} When called without arguments, @command{cpt-list} will print all installed packages. You can add package names as arguments to check whether they are installed or not. In success, @command{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. @c ----------------------------------------------------------------------------- @node @command{cpt-remove} @subsection @command{cpt-remove} @command{cpt-remove} will remove given packages. @c ----------------------------------------------------------------------------- @unnumberedsubsubsec Options @table @option @item -f --force Force removal. @xref{cptforce,,@env{CPT_FORCE}}. @item --root Set an alternative root directory. @xref{cptroot,,@env{CPT_ROOT}}. @end table @c ----------------------------------------------------------------------------- @node @command{cpt-search} @subsection @command{cpt-search} @command{cpt-search} will remove given packages. @c ----------------------------------------------------------------------------- @unnumberedsubsubsec Options @table @option @item -s --single Only show the first instance of a package. @end table @c ----------------------------------------------------------------------------- @node @command{cpt-update} @subsection @command{cpt-update} @command{cpt-update} will update the packages on your system. @c ----------------------------------------------------------------------------- @unnumberedsubsubsec Options @table @option @item -d --download Only download updatable packages. @item -n --no-fetch Do not fetch remote repositories. @item -y --no-prompt Do not prompt for confirmation. @item --root Use an alternate root directory. @xref{cptroot,,@env{CPT_ROOT}}. @end table @c ----------------------------------------------------------------------------- @node Environment Variables @section 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 @file{~/.profile}. Here are the environment variables that alter the behaviour of @command{cpt}: @table @env @item CPT_PATH Set the locations of your repositories. This is set similar to the @env{PATH} variable. @item XDG_CACHE_HOME Unless this is set, the @file{~/.cache} directory will be used instead. @item CPT_CACHE The cache directory for @command{cpt}. Default: @file{$XDG_CACHE_HOME/cpt} @item CPT_CHOICE If this is set to 0, a package installation will be aborted on conflicts. Default: 1 @item CPT_COMPRESS Program used to compress package tarballs. The values should be the default suffixes for the program. Available values are: @itemize @item @command{gz} @item @command{zst} @item @command{bz2} @item @command{xz} @end itemize Default: @command{gz} @item CPT_DEBUG If this is set to 1, temporary build directories will not be removed after the given operation. Default: unset @item CPT_FETCH If this is set to 0, @command{cpt-update} will not fetch the repositories. @optbeh{-n, --no-fetch}. Default: 0 @item @anchor{cptforce}CPT_FORCE If this is set to 1, some of the @command{cpt} tools will continue regardless of errors or skip certain checks. Here are some examples: @itemize @item @command{cpt-install} will install a package without verifying its manifest. @item @command{cpt-install} will install a package even when there are missing dependencies. @item @command{cpt-remove} will remove packages even when there are other packages that depend on the current package. @end itemize @optbeh{-f, --force} to those utilities. Default: 0 @item CPT_HOOK Location for the hook file @xref{Hooks}. Default: unset @item CPT_KEEPLOG Normally, logs are deleted if the package is built successfully. If set to 1, logs will be kept even when the packages are built as intended. Default: 0 @item 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 @command{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 @command{cpt} calls. @example CPT_PID=mesa cpt b mesa @end example By running the above, you will know that the created build directories will end with the @verb{|*-mesa|} suffix. @item CPT_PROMPT If set to 0, the package manager will not prompt you for anything and will continue with the default action. @optbeh{-y, --no-prompt} to some utilities. Default: 1 @item @anchor{cptroot}CPT_ROOT If this variable is set, @command{cpt} will assume this as the system root, and will install/remove/update/list packages assuming this is the system root. @optbehsingle{--root} to some utilities. @item CPT_TEST If set to 1, @command{cpt-build} will run tests where a package has the @file{test} build file. @optbeh{-t, --test} to @command{cpt-build}. Default: 0 @item CPT_TMPDIR The directory to create the build files. This can be changed (for example to /tmp) for building on RAM, saving SSD space, etc. Default: @env{$CPT_CACHE} @end table @c ----------------------------------------------------------------------------- @node Hooks @section 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: @itemize @item pre-build @item post-build @item build-fail @item pre-test @item test-fail @item pre-install @item post-install @item pre-remove @item post-remove @item pre-fetch @item post-fetch @item post-package @end itemize In order to use hooks, you will need to set the @env{CPT_HOOK} variable pointing to your hook file. Your hook file @strong{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: @table @env @item $TYPE The type of the hook, (pre-build, post-build, etc.) @item $PKG The package that @command{cpt} is currently working on. Can be null. @item $DEST The destination of the operation. Can be null. @end table @c There are many ways to deal with hooks. @menu * Editing the @file{build} file during pre-build:: @end menu @c ----------------------------------------------------------------------------- @node Editing the @file{build} file during pre-build @subsection Editing the @file{build} file during pre-build You can edit the @file{build} file during pre-build. The file is copied from the repository to the build directory named as @file{.build.cpt}. You can use @command{sed} or any other tool to edit the build file. After the build is complete, a @command{diff} file will be placed to the package database named as @file{build.diff}. Here is an example @file{build} file manipulation during the pre-build hook. @example cat < .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 @end example @c ----------------------------------------------------------------------------- @node Packaging System @section Packaging System A package is formed of several files, these are: @itemize @item @file{build} @item @file{sources} @item @file{checksums} @item @file{version} @item @file{depends} @item @file{post-install} @item @file{message} @item @file{test} @end itemize 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. @c ----------------------------------------------------------------------------- @subsection @file{build} Typically @file{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 @file{build} file is a POSIX shell script (for portability's sake), @file{build} files can be any executable program from binary programs to @command{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 (@env{$#}) @enumerate @item Location of the package directory (DESTDIR) @item Package version @item System architecture @end enumerate @c ----------------------------------------------------------------------------- @subsection @file{sources} @file{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 @file{soures} file; @verb{|src dest|}. The @env{dest} parameter is optional. It is the directory that the source will be placed in. Here is the @file{sources} file for the @command{gst-plugins} package: @example 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 @end example 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 @command{curl}. If the source is a git repository, it shall be prefixed with a @verb{|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, @table @indicateurl @item git+git://example.com/pub/repo#v1.2.3 will checkout the tag named 'v1.2.3' @item git+git://example.com/pub/repo#development will checkout the branch named 'development' @item git+git://example.com/pub/repo#1a314s87 will checkout the commit named '1a314s87' @end table Other files are assumed to be residing in the package directory. They should be added with their paths relative to the package directory. @c ----------------------------------------------------------------------------- @subsection @file{checksums} checksums file is generated by the @file{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. @c ----------------------------------------------------------------------------- @subsection @file{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. @example 1.3.2 1 @end example The version should always match to the number of the upstream release. For drastic changes that require a rebuild Those can be, @itemize @item update of libraries that forces the package to be relinked @item change in the build scripts that affect the output of the package @end itemize When a version bump occurs, the release should be reset to 1. @c ----------------------------------------------------------------------------- @subsection @file{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 @env{CPT_TEST} is set to 1, or the build is run with the @option{-t} or @option{--test} options. So, a package package could have the following @file{depends} file: @example linux-headers make python test zlib @end example @c ----------------------------------------------------------------------------- @subsection @file{post-install} @file{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 @env{CPT_ROOT}). @c ----------------------------------------------------------------------------- @subsection @file{message} This plaintext file will be outputted with @command{cat} after every package is installed. @c ----------------------------------------------------------------------------- @subsection @file{test} Test files are mainly for the repository maintainer to test the packages, and will only run if the user has the @env{CPT_TEST} variable set, or the build is run with the @option{-t} or @option{--test} options. This script is run on the build directory. It is run right after the build script is finished. @c ----------------------------------------------------------------------------- @node Rsync Repositories @section 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: @example rsync://carbslinux.org/repo/core @end example 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 @file{.rsync} and @file{.rsync_root}. Here is the Carbs Linux rsync repository structure. @example / ----------------- | | .rsync core/ ---------------- | | .rsync .rsync_root @end example 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: @example /.rsync: rsync://carbslinux.org/repo /core/.rsync: rsync://carbslinux.org/repo/core /core/.rsync_root: .. @end example The @file{.rsync_root} file on the core repository points to the upper directory. If a @file{.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 @file{.rsync} file, this means that this is an individual repository, and the package manager will fetch accordingly. @menu * Setting up an rsync repository for distribution:: @end menu @c ----------------------------------------------------------------------------- @node Setting up an rsync repository for distribution @subsection Setting up an rsync repository for distribution 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. @verbatim #!/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 @end verbatim You can then create an @strong{rsync} user for serving the repositories. @example $ adduser -SD rsync @end example Create @file{/etc/rsyncd.conf} and a service configuration as well. @verbatim uid = rsync gid = rsync address = example.com max connections = 10 use chroot = yes [repo] path = /pub/share/repo comment = My repository @end verbatim Create a service file at @file{/etc/sv/rsync/run} (runit): @example #!/bin/sh exec rsync --daemon --no-detach @end example @c -----------------------------------------------------------------------------