aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmmett1 <me@emmett1.my>2026-06-04 03:57:18 +0000
committerEmmett1 <me@emmett1.my>2026-06-04 03:57:18 +0000
commit6ceffed1c24416b38af1c2c1be4c65a120cd5d26 (patch)
treedab6723d6dc37e37441e3116ff3d6c0390548742
parentd55b6466e59794f44a0c0c4e66ca55066c7205d0 (diff)
parent3b0d90838e369ecbb112753999f98591b4d2a5b0 (diff)
downloadalicelinux-6ceffed1c24416b38af1c2c1be4c65a120cd5d26.tar.gz
alicelinux-6ceffed1c24416b38af1c2c1be4c65a120cd5d26.zip
Merge branch 'main' of https://codeberg.org/emmett1/alicelinux
-rw-r--r--404.html3
-rw-r--r--404.md5
-rw-r--r--docs/apkg_helpers.md86
-rw-r--r--docs/bootloader.md88
-rw-r--r--docs/install.md88
-rw-r--r--docs/networking.md27
-rw-r--r--docs/packagemanager.md.new397
-rw-r--r--docs/readme.md3
-rw-r--r--docs/using_autils.md245
-rw-r--r--docs/writing_abuild.md229
-rw-r--r--repos/extra/ssu/.files7
-rw-r--r--repos/extra/ssu/.shasum1
-rw-r--r--repos/extra/ssu/abuild4
-rw-r--r--repos/extra/ssu/info4
-rwxr-xr-xutils/buildsite.sh4
15 files changed, 1109 insertions, 82 deletions
diff --git a/404.html b/404.html
deleted file mode 100644
index 0423c04e..00000000
--- a/404.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<h1>404</h1>
-<p>Page not found.</p>
-<p><a href="/">Back to home</a></p>
diff --git a/404.md b/404.md
new file mode 100644
index 00000000..0e7ee30c
--- /dev/null
+++ b/404.md
@@ -0,0 +1,5 @@
+# 404
+
+Page not found.
+
+[Back to home](/)
diff --git a/docs/apkg_helpers.md b/docs/apkg_helpers.md
new file mode 100644
index 00000000..bbc54648
--- /dev/null
+++ b/docs/apkg_helpers.md
@@ -0,0 +1,86 @@
+# apkg helper scripts
+
+autils includes several helper scripts that work alongside `apkg` for package inspection, cleanup, and maintenance. See `man <program>` for full details on each command.
+
+## apkg-chroot
+
+Enter a chroot environment with virtual filesystems mounted. Useful for building packages or performing system maintenance inside an alternative root.
+
+```sh
+apkg-chroot /mnt/alice # launch interactive shell
+apkg-chroot /mnt/alice apkg -i mypkg # run a command inside the chroot
+```
+
+Must be run as root. Mounts `/dev`, `/proc`, `/sys`, `/run`, copies `/etc/resolv.conf`, and cleans up all mounts on exit.
+
+## apkg-clean
+
+List stale `.spm` package files and orphaned source tarballs that are no longer referenced by any current package recipe. Pipe to `xargs rm` to actually clean up.
+
+```sh
+apkg-clean # list all unreferenced files
+apkg-clean -p # list only stale packages
+apkg-clean -s # list only stale sources
+apkg-clean | xargs rm # remove them
+```
+
+## apkg-deps
+
+Show runtime library dependencies of an installed package. Uses `ldd` to find shared libraries needed by the package's binaries, then maps those libraries back to the packages that provide them.
+
+```sh
+apkg-deps mypkg
+```
+
+Useful for discovering implicit runtime dependencies not listed in the formal `depends` file. Excludes the package itself and base system packages (gcc, musl, binutils, glibc).
+
+## apkg-foreign
+
+List installed packages that are not found in any configured repository. These may have been installed from an external source or had their recipes removed.
+
+```sh
+apkg-foreign
+```
+
+Takes no arguments; outputs one package name per line.
+
+## apkg-genabuild
+
+Scaffold a new package recipe from a source URL. Parses the name and version from the URL and creates a directory with skeleton `abuild` and `info` files.
+
+```sh
+apkg-genabuild https://example.com/mypkg-1.2.3.tar.gz
+apkg-genabuild https://github.com/user/repo/archive/v1.0.tar.gz myname
+```
+
+Special handling for GitHub tag archives, PyPI packages (prefixes `python-`), and CPAN packages (prefixes `perl-`). An optional second argument overrides the derived package name.
+
+## apkg-orphan
+
+List orphan packages: packages that are installed and exist in a repository, but have no other installed package depending on them. These may be safe to remove.
+
+```sh
+apkg-orphan
+```
+
+Takes no arguments; outputs one package name per line.
+
+## apkg-purge
+
+Remove a package and all its dependencies that are no longer needed by any other installed package. This is a "deep" removal compared to `apkg -r` which only removes the specified package.
+
+```sh
+apkg-purge mypkg # dry-run: show what would be removed
+apkg-purge -p mypkg # actually purge from the system
+```
+
+## apkg-redundantdeps
+
+Find redundant entries in `depends` files. A dependency is redundant if another listed dependency already pulls it in transitively.
+
+```sh
+apkg-redundantdeps mypkg # check one package
+apkg-redundantdeps # check all packages
+apkg-redundantdeps -f mypkg # fix by removing redundant entries
+apkg-redundantdeps -f # fix all packages
+```
diff --git a/docs/bootloader.md b/docs/bootloader.md
new file mode 100644
index 00000000..bc6bbd47
--- /dev/null
+++ b/docs/bootloader.md
@@ -0,0 +1,88 @@
+# Bootloader
+
+This document covers installing and configuring the two bootloaders available in Alice Linux: Limine and GRUB.
+
+## Limine
+
+Limine is a modern, lightweight bootloader supporting BIOS and UEFI.
+
+Install the package:
+
+```
+# apkg -I limine
+```
+
+### BIOS
+
+Deploy Limine to the target disk:
+
+```
+# limine bios-install /dev/sdX
+```
+
+### UEFI
+
+Copy the Limine EFI executable to the EFI system partition:
+
+```
+# mkdir -p /boot/EFI/BOOT
+# cp /usr/share/limine/BOOTX64.EFI /boot/EFI/BOOT
+```
+
+### Configuration
+
+Create `/boot/limine.conf`:
+
+```
+timeout: 5
+
+/Alice Linux
+ protocol: linux
+ kernel_path: boot():/vmlinuz
+ cmdline: root=/dev/sda2 rw loglevel=3 quiet
+ module_path: boot():/initrd-linux
+```
+
+Use `boot()` to reference the partition where `/boot` resides, or specify the partition directly with `uuid()` or a path like `hd(0,2)`.
+
+For full configuration options, see the [Limine documentation](https://github.com/limine-bootloader/limine/blob/trunk/CONFIG.md).
+
+## GRUB
+
+GRUB is the GNU Grand Unified Bootloader, supporting UEFI on x86_64 only.
+
+Install the package:
+
+```
+# apkg -I grub
+```
+
+### Install
+
+Install GRUB for UEFI (requires the EFI system partition mounted at `/boot`):
+
+```
+# grub-install --target=x86_64-efi --efi-directory=/boot
+```
+
+### Configuration
+
+Generate the GRUB configuration file:
+
+```
+# grub-mkconfig -o /boot/grub/grub.cfg
+```
+
+GRUB settings are controlled by `/etc/default/grub`. Key options:
+
+- **`GRUB_DEFAULT`**: Default menu entry (default: `0`)
+- **`GRUB_TIMEOUT`**: Seconds before booting the default entry (default: `5`)
+- **`GRUB_CMDLINE_LINUX_DEFAULT`**: Kernel command line arguments
+- **`GRUB_GFXMODE`**: Framebuffer resolution (default: `auto`)
+- **`GRUB_DISABLE_OS_PROBER`**: Disable probing for other operating systems (default: enabled for security)
+
+After editing `/etc/default/grub`, regenerate the config:
+
+```
+# grub-mkconfig -o /boot/grub/grub.cfg
+```
diff --git a/docs/install.md b/docs/install.md
index b37747f6..d032ad51 100644
--- a/docs/install.md
+++ b/docs/install.md
@@ -6,7 +6,7 @@ Here is a guide to installing Alice Linux on your computer using the chroot meth
Get Alice rootfs tarball
------------------------
-Download the Alice rootfs tarball from the [release](https://codeberg.org/emmett1/alicelinux/releases) page, along with its `sha256sum` file.
+Download the Alice rootfs tarball from the [download](https://alicelinux.org/download.html) page, along with its `sha256sum` file.
```
$ curl -O <url>
$ curl -O <url>.sha256sum
@@ -51,29 +51,29 @@ First, chroot into Alice. (Replace `/mnt/alice` with your chosen mount point)
Any further commands after this will be executed inside the Alice environment.
-Configure apkg.conf
--------------------
+Configure apkg
+---------------
-Once we have the repositories cloned, we need to configure `apkg`. `apkg` is Alice's package build system (or package manager). By default, Alice does not provide an `apkg` config file (yes, `apkg` can work without a config file), but we need to create one. The `apkg` config file should be located at `/etc/apkg.conf` by default. Let's create one.
+Once we have the repositories cloned, we need to configure `apkg`. `apkg` is Alice's package build system (or package manager). `apkg` configuration is environment-based -- settings are exported as environment variables. Place them in `/etc/profile.d/apkg.sh` for system-wide configuration, or in `~/.profile` for per-user configuration.
First, we set `CFLAGS` and `CXXFLAGS`. Alice base packages are built using `-O3 -march=x86-64 -pipe`. You can use these settings or change them to your preference.
```
-# echo 'export CFLAGS="-O3 -march=x86-64 -pipe"' >> /etc/apkg.conf
+# echo 'export CFLAGS="-O3 -march=x86-64 -pipe"' >> /etc/profile.d/apkg.sh
```
And use whats in `CFLAGS` for `CXXFLAGS`.
```
-# echo 'export CXXFLAGS="$CFLAGS"' >> /etc/apkg.conf
+# echo 'export CXXFLAGS="$CFLAGS"' >> /etc/profile.d/apkg.sh
```
Next set `MAKEFLAGS`. I will use `6` for my `8 threads` machine.
```
-# echo 'export MAKEFLAGS="-j6"' >> /etc/apkg.conf
+# echo 'export MAKEFLAGS="-j6"' >> /etc/profile.d/apkg.sh
```
I'm also going to set `NINJAJOBS` here. Without it, `ninja` will use all threads of your machine when compiling.
```
-# echo 'export NINJAJOBS="6"' >> /etc/apkg.conf
+# echo 'export NINJAJOBS="6"' >> /etc/profile.d/apkg.sh
```
Next, we need to set the package's build scripts path (I'll call it `package repos`) so `apkg` can find them. The `APKG_REPO` variable can accept multiple values for multiple `package repos`.
@@ -82,14 +82,14 @@ Alice provides two (2) `package repos` (at the time of this writing): `core` and
I'm gonna use directory `/var/lib/repos/core` and `/var/lib/repos/extra` for `core` and `extra` repos respectively.
```
-# echo 'APKG_REPO="/var/lib/repos/core /var/lib/repos/extra"' >> /etc/apkg.conf
+# echo 'export APKG_REPO="/var/lib/repos/core /var/lib/repos/extra"' >> /etc/profile.d/apkg.sh
```
You can also create a directory the community repo.
> NOTE: The community repo is not held to the same standards as the official repos.
> Additionally all repo paths must be declared in the APKG_REPO variable, separated by a single space.
```
-# echo 'APKG_REPO="/var/lib/repos/core /var/lib/repos/extra /var/lib/repos/community"' >> /etc/apkg.conf
+# echo 'export APKG_REPO="/var/lib/repos/core /var/lib/repos/extra /var/lib/repos/community"' >> /etc/profile.d/apkg.sh
```
Next, we will set up directories for `packages`, `sources`, and `work`. By default, these directories are inside the package template, but we will change them to `/var/cache/pkg`, `/var/cache/src`, and `/var/cache/work` respectively. You can change these to any location where you want to store these files.
@@ -101,26 +101,26 @@ First, create the directories.
# mkdir -p /var/cache/work
```
-Then add these paths to `/etc/apkg.conf`.
+Then add these paths to `/etc/profile.d/apkg.sh`.
```
-# echo 'APKG_PACKAGE_DIR=/var/cache/pkg' >> /etc/apkg.conf
-# echo 'APKG_SOURCE_DIR=/var/cache/src' >> /etc/apkg.conf
-# echo 'APKG_WORK_DIR=/var/cache/work' >> /etc/apkg.conf
+# echo 'export APKG_PACKAGE_DIR=/var/cache/pkg' >> /etc/profile.d/apkg.sh
+# echo 'export APKG_SOURCE_DIR=/var/cache/src' >> /etc/profile.d/apkg.sh
+# echo 'export APKG_WORK_DIR=/var/cache/work' >> /etc/profile.d/apkg.sh
```
-Configure reposync.conf
------------------------
+Configure reposync
+--------------------
-`reposync` is a tool to sync package templates from git repositories. Add remote repos for `core` and `extra` into `/etc/reposync.conf`. The format of remote repos in `reposync.conf` is `<gitrepo>|<branch>|<localpath>`.
+`reposync` is a tool to sync package templates from git repositories. Like `apkg`, `reposync` configuration is environment-based. Add remote repos for `core` and `extra` to `/etc/profile.d/reposync.sh` (system-wide) or `~/.profile` (per-user). The format is `<gitrepo>|<branch>|<localpath>`.
```
-# echo 'https://codeberg.org/emmett1/alicelinux|core|/var/lib/repos/core' >> /etc/reposync.conf
-# echo 'https://codeberg.org/emmett1/alicelinux|extra|/var/lib/repos/extra' >> /etc/reposync.conf
+# echo 'export REPOSYNC_CORE="https://codeberg.org/emmett1/alicelinux|core|/var/lib/repos/core"' >> /etc/profile.d/reposync.sh
+# echo 'export REPOSYNC_EXTRA="https://codeberg.org/emmett1/alicelinux|extra|/var/lib/repos/extra"' >> /etc/profile.d/reposync.sh
```
If you also want the community repo, add it as well.
> NOTE: The community repo is not held to the same standards as the official repos.
```
-# echo 'https://codeberg.org/emmett1/alicelinux|community|/var/lib/repos/community' >> /etc/reposync.conf
+# echo 'export REPOSYNC_COMMUNITY="https://codeberg.org/emmett1/alicelinux|community|/var/lib/repos/community"' >> /etc/profile.d/reposync.sh
```
@@ -196,20 +196,6 @@ If your hardware requires firmware, install it using.
# apkg -I linux-firmware
```
-Install bootloader
-------------------
-
-In this guide, I'm going to use `grub` as the bootloader. Install `grub`.
-```
-# apkg -I grub
-```
-
-Then generate grub config.
-```
-# grub-install /dev/sdX
-# grub-mkconfig -o /boot/grub/grub.cfg
-```
-
Hostname
--------
@@ -270,30 +256,6 @@ Set the password for the `root` user.
# passwd
```
-Networking
-----------
-
-You might want to set up networking before rebooting. For wifi connection, install `wpa_supplicant`.
-```
-# apkg -I wpa_supplicant
-```
-
-Configure your SSID.
-```
-# wpa_passphrase <YOUR SSID> <ITS PASSWORD> >> /etc/wpa_supplicant.conf
-```
-
-Enable the service.
-```
-# ln -s /etc/sv/wpa_supplicant /var/service
-```
-
-Then configure & enable `udhcpc` service.
-```
-# vi /etc/sv/udhcpc/conf
-# ln -s /etc/sv/udhcpc /var/service
-```
-
Timezone
--------
@@ -313,6 +275,16 @@ Alternatively, you can copy it and then uninstall `tzdata` to keep your installe
# apkg -r tzdata
```
+Install bootloader
+------------------
+
+See the [bootloader documentation](bootloader.html) for installing and configuring a bootloader.
+
+Networking
+----------
+
+See the [networking documentation](networking.html) for setting up networking.
+
Reboot and enjoy!
-----------------
diff --git a/docs/networking.md b/docs/networking.md
index 186ddfe0..4b1eb702 100644
--- a/docs/networking.md
+++ b/docs/networking.md
@@ -1,12 +1,10 @@
-Networking
-==========
+# Networking
This document describes how to configure networking on **Alice Linux** using `eiwd`/`wpa_supplicant` + `udhcpc`/`dhcpcd`.
---
-Overview
---------
+## Overview
Alice Linux uses simple, modular networking tools:
@@ -22,11 +20,9 @@ Alice Linux uses simple, modular networking tools:
---
-Establish Network Link
-----------------------
+## Establish Network Link
-Wired (LAN)
----------------
+## Wired (LAN)
Bring interface up:
@@ -38,8 +34,7 @@ A physical cable connection is usually sufficient.
> runit service enabled later will automatically bring up the interface.
-Wi-Fi
--------
+## Wi-Fi
Bring interface up first:
@@ -104,8 +99,7 @@ Enable `wpa_supplicant` service:
---
-Obtain IP Address (DHCP)
-------------------------
+## Obtain IP Address (DHCP)
Once the interface is connected (LAN or Wi-Fi), obtain an IP address.
@@ -137,8 +131,7 @@ Enable `dhcpcd` service:
---
-Static Network Configuration
------------------------------
+## Static Network Configuration
To use a static configuration instead of DHCP:
@@ -159,8 +152,7 @@ Set the following variables:
---
-Troubleshooting
----------------
+## Troubleshooting
Check interfaces:
@@ -182,8 +174,7 @@ ping -c 3 google.com
---
-Quick Reference
----------------
+## Quick Reference
LAN (DHCP)
diff --git a/docs/packagemanager.md.new b/docs/packagemanager.md.new
new file mode 100644
index 00000000..5aac8e94
--- /dev/null
+++ b/docs/packagemanager.md.new
@@ -0,0 +1,397 @@
+# Package Manager
+
+In Alice, two package manager are used, [spm](https://codeberg.org/emmett1/spm) and [autils](https://codeberg.org/emmett1/autils). And why two package manager? `spm` was written for generic package manager for linux distribution. And `autils` is written specifically for `Alice` and requires `spm` in order to install, remove and update packages while managing conflicts. The command `apkg` (part of `autils`) is used to fetch and build packages from ports and their `abuild` files.
+
+## spm
+
+`spm` stands for `simple package manager`. It does simple and minimal written in POSIX compliance shell script. It only depends on core utils and tar (or busybox's utils and tar). `spm` only intended for compressing some directory into package, then extract package into system with files being tracked into database. Theres is no build script, recipe or ports in `spm`. You can write your own tools to use with `spm` either like Arch Linux's `makepkg`, CRUX's `pkgmk` or Slackware's `slackbuild` script.
+
+## spm - usage
+
+list `spm` usage:
+```
+-a print all installed packages
+-b <path> build <path> directory into package
+-h print this help message
+-i <file> install <file> package into system
+-l <pkg> list files installed by <pkg>
+-o <file> print owner of <file>
+-r <name> remove installed <name> from system
+-u <pkg> re-install/upgrade <pkg>
+```
+
+list all install package with version:
+```
+$ spm -a
+...
+neofetch 7.1.0-1
+nettle 3.10-1
+nghttp2 1.62.1-1
+ninja 1.12.1-1
+nodejs 22.5.1-1
+nspr 4.35-1
+nss 3.102.1-1
+nsxiv 32-1
+...
+```
+
+build package from directory:
+```
+(build package)
+$ ./configure --prefix=/usr
+$ make
+
+(install into fake directory)
+$ make DESTDIR=$PWD/fakeroot install
+
+(turn fake directory into package (package.spm))
+# spm -b $PWD/fakeroot
+
+(mv 'package.spm' into correct format (name#version-release.spm))
+# mv package.spm pkgname#pkgversion-pkgrelease.spm
+
+(install package into system)
+# spm -i pkgname#pkgversion-pkgrelease.spm
+```
+
+install package into system:
+```
+# spm -i pkgname#pkgversion-pkgrelease.spm
+[pkgname] Verify package...
+[pkgname] Checking for conflicts...
+[pkgname] Installing package...
+[pkgname] Package 'pkgname#pkgversion-pkgrelease' installed.
+```
+
+list files installed by 'packagename'$ spm -l test:
+```
+usr/
+usr/share/
+usr/share/aaa
+usr/bin/
+usr/bin/aaa
+```
+
+list package owner of a file (can use regex):
+```
+$ spm -o gcc$
+ccache usr/lib/ccache/gcc
+gcc usr/bin/gcc
+gcc usr/bin/x86_64-pc-linux-musl-gcc
+linux lib/modules/6.6.41-Alice/build/scripts/dummy-tools/gcc
+```
+
+upgrade/reinstall installed package:
+```
+# spm -u pkgname#pkgversion-pkgrelease.spm
+[pkgname] Verify package...
+[pkgname] Checking for conflicts...
+[pkgname] Upgrading package...
+[pkgname] Package 'pkgname#pkgversion-pkgrelease' upgraded.
+```
+
+## spm - environment
+```
+SPM_ROOT: use custom root location for package installation
+SPM_FORCEINSTALL: set any value to ignore conflicted files
+```
+You can pass these environment to `spm` command, example:
+```
+# SPM_ROOT=/mnt/rootfs spm -i pkgname#pkgversion-pkgrelease.spm
+# SPM_FORCEINSTALL=1 SPM_ROOT=/mnt/rootfs spm -i pkgname#pkgversion-pkgrelease.spm
+```
+
+## autils
+
+`autils` stands for `alice utilitis`. `autils` contains main package manager (apkg), utilities (apkg-<util>) and <random util script>. `autils` is specifically written to manage `Alice` packages.
+
+## apkg
+
+`apkg` is a main package manager that can solve dependencies, batch install/upgrade/remove packages, system upgrades, trigger necessary caches, and etc. `apkg` can be run inside or outside package template.
+
+When running outside package template, `apkg` will need 'package names' as arguments, and those 'package names' will search through `APKG_REPO` environment. Example:
+```
+# apkg testpkg testpkg2 (build testpkg and testpkg2)
+# apkg testpkg testpkg2 -i (build and install testpkg and testpkg2)
+# apkg -u testpkg testpkg2 (upgrade/reinstall testpkg and testpkg2)
+# apkg -f -u testpkg testpkg2 (force rebuild then upgrade/reinstall testpkg and testpkg2)
+```
+
+When running inside package template, `apkg` will do operation for current directory package. Example:
+```
+# cd /path/to/local/testpkg
+# apkg (build testpkg)
+# apkg -i (build and install testpkg)
+# apkg -u (upgrade/reinstall testpkg)
+# apkg -u -f (force rebuild then upgrade/reinstall testpkg)
+```
+
+## apkg - usage
+```
+-i <pkg(s)> install package(s)
+-I <pkg(s)> install packages(s) with dependencies
+-d <pkg> list <pkg> dependencies
+-D <pkg(s)> list all dependencies
+-j <pkg> list all dependents
+-u <pkg(s)> upgrade package(s)
+-t [pkg(s)] trigger system cache/db updates
+-U update system
+-f force rebuild
+-o <pkg(s)> download source
+-p <pkg> print package path
+-s <pattern> search packages
+-h print this help message
+```
+
+I won't explain details on every each options here, but I will give quick tips/tricks to use `apkg`
+
+installing package and its dependencies (mind the uppercase `i`):
+```
+# apkg -I sway
+[...] Solving dependencies...
+[...] Installing 3 package(s): mesa pango sway
+[...] Press ENTER to continue operation.
+[...] Press Ctrl + C to abort.
+```
+
+search available packages:
+```
+$ apkg -s sway
+swaybg
+swaylock
+sway
+swayidle
+swayfx
+```
+
+install all package with 'sway' name and its dependencies:
+```
+# apkg -I $(apkg -s sway)
+...
+[...] Package 'mesa' is installed
+[...] Package 'swaybg' is installed
+[...] Package 'swaylock' is installed
+[...] Package 'swayidle' is installed
+[...] Package 'swayfx' is installed
+[...] Solving dependencies...
+[...] Installing 2 package(s): pango sway
+[...] Press ENTER to continue operation.
+[...] Press Ctrl + C to abort.
+```
+
+install package without solving dependencies (mind the lowercase `i` and theres no prompt for this option):
+```
+# apkg -i wlroots mesa
+[...] Package 'wlroots' already installed.
+[...] Package 'mesa' already installed.
+```
+
+list all installed packages:
+```
+$ apkg -a
+...
+qemu
+ranger
+rdfind
+readline
+rsync
+rtorrent
+rust
+...
+```
+
+list all installed packages with filter (will only print installed package contains word filter):
+```
+$ apkg -a sway
+swaybg
+swayfx
+swayidle
+swaylock
+```
+
+list dependencies of a package:
+```
+$ apkg -d sway
+wlroots
+json-c
+pango
+```
+
+list all dependencies tree of package(s):
+```
+$ apkg -D sway dwm
+...
+wayland
+wayland-protocols
+xkeyboard-config
+xcb-proto
+xorgproto
+util-macros
+...
+```
+
+upgrade/reinstall package(s):
+```
+# apkg -u wlroots cwm pango
+[wlroots] Verify package...
+[wlroots] Checking for conflicts...
+[wlroots] Upgrading package...
+[wlroots] Package 'wlroots#0.17.4-1' upgraded.
+[cwm] Verify package...
+[cwm] Checking for conflicts...
+[cwm] Upgrading package...
+[cwm] Package 'cwm#7.4-1' upgraded.
+[pango] Verify package...
+[pango] Checking for conflicts...
+[pango] Upgrading package...
+[pango] Package 'pango#1.54.0-1' upgraded.
+```
+
+full system upgrades (mind uppercase `u` and will prompt first if theres package updates):
+```
+# apkg -U
+[...] Checking for outdated packages...
+[...] Solving dependencies...
+[...] Upgrading 3 package(s): initscripts mesa sowm
+[...] Press ENTER to continue operation.
+[...] Press Ctrl + C to abort.
+```
+
+make full system rebuild in dependencies order (`-f`: force rebuild, `-u`: upgrade/reinstall, `-D`: solve dependency order, `-a`: list all installed package(s)):
+```
+# apkg -f -u $(apkg -D $(apkg -a))
+...
+(start rebuilding package in dependencies order here)
+...
+```
+
+remove installed packages:
+```
+# apkg -r wlroots pango sway
+[...] Package 'wlroots' removed.
+[...] Package 'pango' removed.
+[...] Package 'sway' removed.
+```
+
+print package path:
+```
+$ apkg -p sway
+/home/emmett/codeberg/alicelinux/repos/wayland/sway
+```
+
+## apkg - environment
+
+You can pass environment to `apkg` to override defaults and in `/etc/apkg.conf`. Available environment and its default value as follows:
+```
+ env default value description
+APKG_ROOT / root for package installation
+APKG_CONF /etc/apkg.conf apkg's config file
+APKG_REPO defaults is empty, template repo path, space separated variable
+APKG_PACKAGE_DIR $PWD prebuilt package directory path
+APKG_SOURCE_DIR $PWD package source directory path
+APKG_WORK_DIR $PWD package working directory path
+APKG_NOPROMPT defaults is empty, skip prompt, use any value
+```
+You can add these environment into `apkg` config file.
+
+## /etc/apkg.conf
+
+`apkg` can work without its config file by using all default value. Default config path for `apkg` is `/etc/apkg.conf`. You can override config path by append `APKG_CONF` to `apkg`, example:
+```
+# APKG_CONF=/etc/apkg-local.conf apkg <args>
+```
+## revdep
+
+`revdep` is script to find broken packages. Its recomended to run after packages is removed or upgraded.
+
+Usage:
+```
+(print out broken packages)
+$ revdep
+
+(verbosely print missing libraries)
+$ revdep -v
+```
+
+You can combine with `apkg` to rebuild broken packages, example;
+```
+# apkg -f -u $(revdep)
+```
+
+> NOTE: `revdep` does not solve dependencies, so you might need manually rebuild broken packages instead combine with `apkg`.
+
+## updateconf
+
+`updateconf` is script to update configuration files inside `/etc` directory. Its recomended to run after packages upgrades.
+
+## apkg-chroot
+Script to entering chroot environment of custom root location.
+```
+# apkg-chroot <customroot path>
+# apkg-chroot <customroot path> <command>
+```
+
+## apkg-clean
+Print out old package and source caches.
+
+Options:
+```
+-s print sources only
+-p print packages only
+```
+
+Usage:
+```
+(to remove old packages)
+# apkg-clean -p | xargs rm
+
+(to remove old sources)
+# apkg-clean -s | xargs rm
+
+(to remove both old packages and sources)
+# apkg-clean | xargs rm
+```
+
+## apkg-deps
+
+Script to find runtime linked dependencies of installed package. Its good to figure out dependenciess when writing package template.
+
+Usage:
+```
+$ apkg-deps <pkg>
+```
+
+## apkg-foreign
+
+Script to list installed package outside package repo.
+
+Usage:
+```
+(print list foreign packages)
+$ apkg-foreign
+
+(remove foreign packages)
+# apkg -r $(apkg-foreign)
+```
+
+## apkg-orphan
+
+Script to print list package without parent dependencies.
+
+Usage:
+```
+$ apkg-orphan
+```
+
+## apkg-redundantdeps
+
+Script to print package's redundant dependencies. Its good to use when writing package template for minimizing dependencies and speed up `apkg` dependencies solving.
+
+usage:
+```
+(print package contains redundant dependencies)
+$ apkg-redundantdeps
+
+(remove redundant dependencies for depends list)
+$ apkg-redundantdeps -f
+```
diff --git a/docs/readme.md b/docs/readme.md
index fb4ef6b6..2ef1aa96 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -1,5 +1,4 @@
-Documentation
-=============
+# Documentation
This section covers the main parts of **Alice Linux**: installation, package
management, networking, service supervision, etc.
diff --git a/docs/using_autils.md b/docs/using_autils.md
new file mode 100644
index 00000000..bbf2ce69
--- /dev/null
+++ b/docs/using_autils.md
@@ -0,0 +1,245 @@
+# Using autils
+
+autils is a collection of POSIX shell scripts for source-based package management on Alice Linux.
+
+For full command details, see the man pages: `man apkg`, `man reposync`, etc.
+
+## Installation
+
+```sh
+make install
+```
+
+This installs all scripts to `/usr/bin` and man pages to `/usr/share/man/man8`. Override with:
+
+```sh
+make install DESTDIR=/tmp/root PREFIX=/usr/local
+```
+
+## Core concepts
+
+The package manager, **apkg**, builds packages from source using `abuild` recipe files and installs them as `.spm` packages via the **spm**(8) backend. Package recipes live in git repositories referenced by the `APKG_REPO` environment variable.
+
+Configuration is done through environment variables: there is no config file.
+
+## Basic usage
+
+### Building a package
+
+From inside a recipe directory:
+
+```sh
+cd /path/to/repo/mypkg
+apkg
+```
+
+This fetches sources, verifies checksums, builds, and creates a `.spm` in `$APKG_PACKAGE_DIR`.
+
+### Installing and upgrading
+
+```sh
+apkg -i mypkg # build and install
+apkg -i # same, from inside the recipe directory
+apkg -I firefox # install with automatic dependency resolution
+apkg -u mypkg # upgrade (rebuild and reinstall)
+apkg -f mypkg # force rebuild even if .spm already exists
+apkg -o mypkg # download sources only, don't build
+```
+
+### Removing packages
+
+```sh
+apkg -r mypkg # remove a package
+apkg-purge mypkg # show what would be removed (dry-run)
+apkg-purge -p mypkg # remove package and its unneeded dependencies
+```
+
+### Searching and listing
+
+```sh
+apkg -s icon # search packages by name pattern
+apkg -s -v icon # search with version info
+apkg -a # list all installed packages
+apkg -a -v # list installed packages with versions
+apkg -S libpng.so # find which package owns a file
+apkg -l # list outdated packages on the system
+```
+
+### Dependency queries
+
+```sh
+apkg -d mypkg # list direct dependencies of a package
+apkg -D mypkg # list all dependencies recursively, in install order
+apkg -j mypkg # list packages that depend on mypkg
+```
+
+### System upgrade
+
+```sh
+apkg -U
+```
+
+This checks all installed packages for outdated versions, resolves the full dependency tree, installs any new packages, then upgrades existing ones. Set `APKG_NOPROMPT=1` to skip the confirmation prompt (useful for scripting). Packages listed in `APKG_MASK` are skipped.
+
+### Checksums and file lists
+
+```sh
+apkg -g mypkg # regenerate .shasum file
+apkg -k mypkg # regenerate .files list from the .spm
+```
+
+### Triggers
+
+After installing or upgrading packages, apkg can refresh system caches:
+
+```sh
+apkg -t # run triggers for all installed packages
+apkg -t mypkg # run only triggers relevant to mypkg
+```
+
+Triggers include: fontconfig cache, GDK-Pixbuf loaders, GIO modules, GSettings schemas, GTK input method modules, icon theme cache, udev hardware database, X font indices, desktop MIME cache, and shared MIME database. Each trigger only fires if the package actually provides files that need it.
+
+## Helper scripts
+
+### Package inspection
+
+```sh
+apkg-deps mypkg # show runtime library dependencies (via ldd)
+apkg-foreign # list installed packages not found in any repo
+apkg-orphan # list packages with no dependents installed
+```
+
+### Cleanup
+
+```sh
+apkg-clean # list stale .spm and source files
+apkg-clean | xargs rm # actually remove them
+apkg-clean -p # list only stale packages
+apkg-clean -s # list only stale sources
+```
+
+### Dependency maintenance
+
+```sh
+apkg-redundantdeps mypkg # find transitive deps listed explicitly
+apkg-redundantdeps # check all packages
+apkg-redundantdeps -f mypkg # fix by removing redundant entries
+```
+
+### Scaffolding
+
+```sh
+apkg-genabuild https://example.com/pkg-1.2.3.tar.gz
+apkg-genabuild https://github.com/user/repo/archive/v1.0.tar.gz
+```
+
+Derives `name` and `version` from the URL and creates a directory with a skeleton `abuild`. Recognizes GitHub tag archives, PyPI packages (prefixes `python-`), and CPAN packages (prefixes `perl-`). An optional second argument overrides the name.
+
+## Standalone utilities
+
+### revdep: find broken library links
+
+Scans system binaries and libraries for missing shared library dependencies. Run after major upgrades, especially those with library version bumps.
+
+```sh
+revdep # plain output
+revdep -v # verbose progress
+```
+
+**Note:** revdep only reports problems; it does not rebuild anything. Use `apkg -f` to rebuild affected packages.
+
+### updateconf: merge .new config files
+
+When packages are upgraded, new default config files are installed with a `.new` suffix to avoid overwriting local changes. Run `updateconf` as root to interactively handle them:
+
+```sh
+updateconf
+```
+
+For each `.new` file it shows a diff and prompts:
+- **U**: update: replace current with new
+- **D**: discard: delete the `.new` file, keep current
+- **E**: edit: open current file in `$EDITOR` (default: `vi`)
+- **K**: keep: leave both files as-is
+
+### reposync: sync git repositories
+
+Syncs git-based package repos using `REPOSYNC_*` environment variables:
+
+```sh
+export REPOSYNC_CORE="https://codeberg.org/emmett1/alicelinux.git|main|/var/lib/alicelinux"
+export REPOSYNC_EXTRA="https://codeberg.org/emmett1/extra.git|main|/var/lib/alicelinux/extra"
+reposync
+```
+
+Options:
+- **`-n`**: dry-run
+- **`-l`**: log to `/var/log/reposync.log`
+- **`-f`**: force fresh clones
+- **`-h`**: help
+
+## Working in a chroot
+
+```sh
+apkg-chroot /mnt/alice # enter interactive shell
+apkg-chroot /mnt/alice apkg -i mypkg # run apkg inside chroot
+```
+
+Mounts `/dev`, `/proc`, `/sys`, `/run`, copies `/etc/resolv.conf`, and cleans up on exit. Must be run as root.
+
+## Environment variables
+
+### Core paths
+
+- **`APKG_REPO`** (default: `$PWD`): Space-separated repo directories, searched in order
+- **`APKG_PACKAGE_DIR`** (default: `$PWD`): Where built `.spm` files are stored
+- **`APKG_SOURCE_DIR`** (default: `$PWD`): Source tarball cache
+- **`APKG_WORK_DIR`** (default: `$PWD`): Build working tree (extraction + fakeroot)
+- **`APKG_ROOT`** (default: `/`): Alternative install root
+
+### Build behavior
+
+- **`APKG_NOPROMPT`**: Skip confirmation prompt in `-I` and `-U`
+- **`APKG_KEEP_WORKDIR`**: Keep build tree on failure (for debugging)
+- **`APKG_ALIAS`**: Dependency substitution: `real:alias` pairs (e.g. `openssl:libressl`)
+- **`APKG_MASK`**: Packages to skip during `-l` and `-U`
+
+### Logging
+
+- **`APKG_LOG`**: Enable build logging
+- **`APKG_LOG_DIR`**: Directory for log files (filename: `$name.log`)
+
+### Compiler
+
+- **`CFLAGS`**, **`CXXFLAGS`**: Compiler flags (used by cmake builds)
+- **`CROSS_COMPILE`**: Prefix for `strip` (e.g. `x86_64-linux-musl-`)
+
+## Common workflows
+
+### Building and installing a new package
+
+```sh
+cd $APKG_REPO
+apkg-genabuild https://example.com/mypkg-1.0.tar.gz
+cd mypkg
+# edit abuild as needed, add depends file
+apkg -I mypkg
+```
+
+### Full system maintenance
+
+```sh
+reposync # sync repos
+apkg -U # system upgrade
+revdep # check for broken libraries
+updateconf # merge config files
+apkg-clean | xargs rm # clean up stale files
+apkg-orphan # review packages to potentially remove
+```
+
+### Debugging a failed build
+
+```sh
+APKG_KEEP_WORKDIR=1 apkg -f mypkg
+# inspect $APKG_WORK_DIR/apkg-src-mypkg and apkg-pkg-mypkg
+```
diff --git a/docs/writing_abuild.md b/docs/writing_abuild.md
new file mode 100644
index 00000000..2a82d86b
--- /dev/null
+++ b/docs/writing_abuild.md
@@ -0,0 +1,229 @@
+# Writing an abuild recipe
+
+An `abuild` file is a POSIX shell snippet that tells apkg how to build a package. The directory containing it must have the same name as the package.
+
+See `man apkg` for full details on all options and environment variables, and `man apkg-genabuild` for the recipe scaffolding tool.
+
+To quickly scaffold a new recipe from a source URL, use `apkg-genabuild`:
+
+```sh
+apkg-genabuild https://example.com/mypkg-1.2.3.tar.gz
+```
+
+This creates the directory and a skeleton `abuild` with `name`, `version`, `release`, and `source` already populated.
+
+## Directory structure
+
+```
+mypkg/
+ abuild - package recipe (required)
+ info - package metadata template (description, homepage, license, maintainer)
+ depends - dependency list, one per line (optional)
+ preinstall - script run before the package is built (optional)
+ postinstall - script run after the package is installed (optional)
+ .shasum - source checksums, auto-generated (regenerate with `apkg -g`)
+ .files - package file list, auto-generated (regenerate with `apkg -k`)
+```
+
+## Minimal recipe
+
+```sh
+name=mypkg
+version=1.2.3
+release=1
+source="https://example.com/$name-$version.tar.gz"
+```
+
+### Required variables
+
+- **`name`**: package name. Must match the directory name exactly.
+- **`version`**: upstream version string. Use the `$name` and `$version` variables in the source URL so updates are easier.
+- **`release`**: an incrementing integer starting at 1. Reset to 1 when `version` changes. Bump when the package needs a rebuild without a source change.
+
+## Source formats
+
+The `source` variable accepts a whitespace-separated list. Five formats are supported:
+
+- **`https://example.com/pkg-1.0.tar.gz`**: A remote URL, downloaded with curl
+- **`mypkg-1.0.tar.gz::https://example.com/v1.0.tar.gz`**: Custom local filename for a remote URL
+- **`https://example.com/pkg.tar.gz::noextract`**: Download but do not unpack
+- **`my-file`**: A local file in the recipe directory (not downloaded)
+- (empty): Create a meta/dummy package with only `/usr`
+
+Multiple sources can be specified:
+
+```sh
+source="https://example.com/$name-$version.tar.gz
+ fix-build.patch
+ default-config::noextract"
+```
+
+If `source` is empty, apkg creates a dummy package: useful for meta packages that exist only to pull in dependencies.
+
+## Optional variables
+
+### Build control
+
+- **`build_type`**: force a specific build system instead of auto-detection. One of: `meson_build`, `configure_build`, `cmake_build`, `python_build`, `perlmodule_build`, `makefile_build`.
+- **`build_dir`**: subdirectory within the extracted source tree to enter before building. Useful when a tarball extracts into a differently-named directory.
+- **`build_opt`**: extra flags appended to the build system command. The defaults (`--prefix=/usr`, `--sysconfdir=/etc`, etc.) are always included; this adds on top.
+- **`skip_patch`**: set to `1` to skip automatic patch application. Use this if you need to call `apply_patch` manually from `build()`.
+- **`patch_opt`**: options for `patch(1)`. Default: `-p1`.
+
+### Package content control
+
+- **`keep_static`**: set to keep `*.a` static libraries (removed by default).
+- **`keep_libtool`**: set to keep `*.la` libtool archives (removed by default).
+- **`keep_locale`**: set to keep locale files in `/usr/share/locale` and `/usr/lib/locale`.
+- **`keep_doc`**: set to keep documentation in `/usr/share/doc` and `/usr/doc`.
+- **`no_strip`**: set to skip ELF binary and library stripping.
+
+### Runit services
+
+- **`sv`**: service files to install into `/etc/sv`. Accepts:
+ - `run` → `/etc/sv/$name/run`
+ - `finish` → `/etc/sv/$name/finish`
+ - `<name>.run` → `/etc/sv/<name>/run`
+ - `<name>.finish` → `/etc/sv/<name>/finish`
+ - `<name>.<ext>` → `/etc/sv/<name>/<ext>`
+
+```sh
+sv="run finish mydaemon.run mydaemon.finish"
+```
+
+## Build hooks
+
+### Custom build function
+
+If a `build()` function is defined, it completely replaces the auto-detected build system. Two variables are available:
+
+- **`$SRC`**: where sources were extracted
+- **`$PKG`**: the fakeroot directory where files must be installed
+
+Several `DESTDIR`-style variables are pre-exported: `DESTDIR`, `DEST_DIR`, `INSTALLROOT`, `install_root`, `INSTALL_ROOT`.
+
+```sh
+build() {
+ cd "$SRC/$name-$version"
+ ./configure --prefix=/usr --sysconfdir=/etc
+ make
+ make DESTDIR="$PKG" install
+}
+```
+
+`build()` runs with `set -ex`, so the script exits on any error and prints each command.
+
+### Pre/post build hooks
+
+Without a `build()` function, you can use `prebuild()` and `postbuild()`:
+
+```sh
+prebuild() {
+ sed -i 's/broken/fixed/g' src/whatever.c
+}
+
+postbuild() {
+ mv "$PKG/usr/bin/wrongname" "$PKG/usr/bin/rightname"
+}
+```
+
+The execution order is: `prebuild()` → auto-detected build system → `postbuild()`.
+
+## Build system auto-detection
+
+When no `build()` is defined and no `build_type` is set, apkg checks for these files in order:
+
+1. `meson.build`: meson with LTO, PIE, `wrap_mode=nodownload`, `buildtype=plain`
+2. `configure`: autotools `./configure --prefix=/usr --sysconfdir=/etc ...`
+3. `CMakeLists.txt`: cmake with `Release` build type, prefers ninja
+4. `setup.py`: `python3 setup.py build && install --root=$PKG`
+5. `Makefile.PL`: `perl Makefile.PL && make && make install`
+6. `Makefile` / `makefile` / `GNUmakefile`: raw make with standard variables
+
+The exact flags for each build system are documented in `doc/defaultbuildopts`.
+
+## Post-build processing
+
+After compilation, apkg automatically:
+
+- Compresses man pages (man1–man8 only, gzip) and info pages
+- Removes common conflict files: `fonts.dir`, `fonts.scale`, `perllocal.pod`, `charset.alias`
+- Removes static libraries (`*.a`), libtool archives (`*.la`), locales, and docs unless the corresponding `keep_*` variable is set
+- Strips ELF binaries (`--strip-all`), shared objects (`--strip-unneeded`), and static archives (`--strip-debug`) unless `no_strip` is set
+- Installs runit service files from the `sv` variable
+
+## The info file
+
+`apkg-genabuild` creates an `info` file alongside the `abuild` with package metadata:
+
+```
+description:
+homepage:
+license:
+maintainer: name <name at mail dot com>
+```
+
+Fill in each field as appropriate. The `maintainer` line uses the format `name <email>`.
+
+## The depends file
+
+One dependency per line. Lines starting with `#` are comments. Dependencies are just package names: no version constraints.
+
+```
+# Direct dependencies of mypkg
+zlib
+libpng
+freetype
+```
+
+Dependencies are recursive: when installing with `-I`, apkg will resolve the full tree. Only list direct dependencies; transitive ones are handled automatically. Use `apkg-redundantdeps` to find and clean up transitive entries.
+
+## preinstall / postinstall scripts
+
+These are optional executable scripts in the recipe directory:
+
+- **`preinstall`**: runs before the package is built (only during `apkg -i` or `apkg -u`). Good for pre-flight checks or preparing the system.
+- **`postinstall`**: runs after the package is installed or upgraded. Good for one-time setup that can't be done at build time.
+
+If `APKG_ROOT` is set (alternative install root), these scripts run inside a chroot.
+
+## Checksums and file lists
+
+- **`.shasum`**: sha3sum of each source file, auto-generated on first build. Regenerate with `apkg -g <pkg>`.
+- **`.files`**: sorted list of every file in the built `.spm`, auto-generated after packaging. Regenerate with `apkg -k <pkg>`. Used by `apkg -S` for file search.
+
+## Complete example
+
+```sh
+name=hello
+version=2.12.1
+release=1
+source="https://ftp.gnu.org/gnu/hello/$name-$version.tar.gz"
+
+build() {
+ cd "$SRC/$name-$version"
+ ./configure --prefix=/usr
+ make
+ make DESTDIR="$PKG" install
+}
+```
+
+With a `depends` file:
+
+```
+zlib
+```
+
+With a `postinstall` script:
+
+```sh
+#!/bin/sh
+echo "hello was installed!"
+```
+
+## Tips
+
+- Use `apkg-genabuild <url>` to scaffold a recipe from a source URL quickly.
+- Use `$name` and `$version` in source URLs so bumping the version only requires changing two variables.
+- Patches (`.patch` / `.diff` files) listed in `source` are applied automatically with `patch -p1` before the build. Use `patch_opt` to change the strip level.
+- Set `APKG_KEEP_WORKDIR=1` in your environment to inspect the build tree when debugging a failed build.
diff --git a/repos/extra/ssu/.files b/repos/extra/ssu/.files
new file mode 100644
index 00000000..5c6d1f71
--- /dev/null
+++ b/repos/extra/ssu/.files
@@ -0,0 +1,7 @@
+drwxr-xr-x root/root usr/
+drwxr-xr-x root/root usr/bin/
+-rwsr-xr-- root/wheel usr/bin/ssu
+drwxr-xr-x root/root usr/share/
+drwxr-xr-x root/root usr/share/man/
+drwxr-xr-x root/root usr/share/man/man1/
+-rw-r--r-- root/root usr/share/man/man1/ssu.1.gz
diff --git a/repos/extra/ssu/.shasum b/repos/extra/ssu/.shasum
new file mode 100644
index 00000000..136a89f7
--- /dev/null
+++ b/repos/extra/ssu/.shasum
@@ -0,0 +1 @@
+729d48bd3c9e8614f3df64de715d14ea12cf72bc6768f850d65d9466 ssu-0.3.2.tar.gz
diff --git a/repos/extra/ssu/abuild b/repos/extra/ssu/abuild
new file mode 100644
index 00000000..067318c3
--- /dev/null
+++ b/repos/extra/ssu/abuild
@@ -0,0 +1,4 @@
+name=ssu
+version=0.3.2
+release=1
+source="https://github.com/illiliti/${name}/archive/${version}/${name}-${version}.tar.gz"
diff --git a/repos/extra/ssu/info b/repos/extra/ssu/info
new file mode 100644
index 00000000..1283353f
--- /dev/null
+++ b/repos/extra/ssu/info
@@ -0,0 +1,4 @@
+description: Extremely simple su utility
+homepage: https://github.com/illiliti/ssu
+license: GPL-3.0-or-later
+maintainer: Emmett1 <me@emmett1.my>
diff --git a/utils/buildsite.sh b/utils/buildsite.sh
index 41bb312d..ccaab39e 100755
--- a/utils/buildsite.sh
+++ b/utils/buildsite.sh
@@ -359,7 +359,7 @@ generate_download_page
cat docs/readme.md > docs/index.md
for f in docs/*.md; do
case $f in */readme.md|*/index.md) continue;; esac
- title=$(head -n1 "$f")
+ title=$(head -n1 "$f" | sed "s/^#* *//")
file=${f##*/}
echo "- [$title](./${file%.md}.html)" >> docs/index.md
done
@@ -376,7 +376,9 @@ find . -type f -name "*.md" ! -path './public/*' | sed 's|^\./||' | while IFS= r
printf 'generating html for %s...\n' "$i"
{
sed "s/@TITLE@/$title/g" files/header
+ case $i in docs/readme.md|docs/index.md) ;; *) case $i in docs/*) printf '<a href="/docs/">&lt;- back to docs</a>\n\n';; esac; esac
cmark "$i"
+ case $i in docs/readme.md|docs/index.md) ;; *) case $i in docs/*) printf '\n<a href="/docs/">&lt;- back to docs</a>\n';; esac; esac
cat files/footer
} > "public/${i%.md}.html"
done