diff --git a/docs/PACKAGING.md b/docs/PACKAGING.md new file mode 100644 index 0000000..e6b58e8 --- /dev/null +++ b/docs/PACKAGING.md @@ -0,0 +1,108 @@ +# Packaging Go Binaries for a Debian OS + +This is a primer on Debian packaging for Go. Contained in this project are Makefile targets that are used to create a binary package (`.deb archive`) of the project. + +## Tooling + +Some key tools should be present on your system before you begin. + +``` +sudo apt-get install build-essential devscripts debhelper +``` + +This command installs: + +- `build-essential`: A meta-package that pulls in the essential tools for compiling software, such as gcc and make. +- `devscripts`: A collection of scripts that are incredibly helpful for Debian package maintainers. +- `debhelper`: A suite of tools that simplifies the packaging process by automating common tasks. + +It is assumed your Golang dependencies are already met. + +## Source vs Binary Packages + +A source package typically contains the source code of the upstream project in a `.tar.gz` file, patches made by the package maintainer, then a Makefile file `debian/rules` is used by the system to compile the code and create a binary package. These source packages cannot be directly installed, but they are highly portable and sometimes required for security auditing. + +You are probably more familiar with binary packages. These are pre-compiled packages that are ready to install. They typically consist of the pre-compiled binary, configuration files, man pages, and other necessary data files. The contents are organized into a specific directory structure that a package manager (.e.g. `apt`) will place on to your file system. + +Binary packages need to be compiled for a specific processor architecture (e.g. x86_64 ARM64). Most times these are built for a specific operating system and version too. A benefit to this process is that dev tools do not need to be installed for a user to make use of the package. + +This project focuses on building a binary package. + +## Package Files and Structure + +When building a Debian package you must create a `debian/` directory which in a typical build process will contain a number of essential files. + +- `debian/control`: Contains essential metadata about the source package and the binary package(s) it will create. This includes the package name, version, dependencies, maintainer information, and a description of the software +- `debian/rules`: This is an executable Makefile that automates the building of the package. It has targets for compiling the software (build), installing it into a temporary directory (install), and creating the final .deb archive(binary). Modern rules files are often very simple, relying on `debhelper` to do the heavy lifting +- `debian/changelog`: This file documents the changes made to the Debian package, not the upstream software. It follows a strict format and is used by the build tools to determine the package version. +- `debian/copyright`: This file specifies the copyright and license of the software. It's a legal requirement and should accurately reflect the licensing terms of the upstream source code and any modifications made for the Debian package. +- `debian/compat`: This file specifies the `debhelper` compatibility level, which ensures that the build process is consistent even as `debhelper` evolves. +- `debian/source/format`: This file indicates the source package format (e.g., 3.0 (quilt)) + +A binary package for can be constructed for Go with as little as a `control` and `changelog` file. Since this primer is focused on a minimal packaging process for your own golang project, we will focus on the `control` file and the `changelog`. + +### Control File + +The `debian/control` file + +- control + +### Changelog + +The change log is not a change log of the upstream, it is a changelog of the Debian package. This file has a specific format that needs to be adhered to, or the build will fail. + +A `debian/changelog` file is a plain text file with a series of entries, where the newest entry is always at the very top. Each entry has a precise format: + +``` +package-name (version) distribution(s); urgency=level + + * Change details for the first change in this version. + (This can wrap to multiple lines if indented). + + * Change details for the second change. This could be a bug fix. + (Closes: #bug-number) + + -- Maintainer Name Day, dd Mon yyyy hh:mm:ss +zzzz +``` + +The `devscripts` package installed earlier can assist in automating the change log changes, and ensure that they correctly formatted. + +## Debian Versioning Scheme + +`[epoch:]upstream_version[-debian_revision]` + +- `epoch`: small, rarely used integer that helps correct mistakes in past versioning by ensuring a new version is seen as "later" than an old one +- `upstream_version`: The main version number from the original software developer, which can contain alphanumeric characters and symbols like periods, hyphens, and colons +- `debian_revision` is appended by the package maintainer to signify changes to the packaging itself, such as updates to dependencies or build scripts, without any change to the upstream software + +When assessing versions `dpkg`'s algorithm evaluates the string from left to right, with special rules for characters like the tilde (~), which indicates a pre-release version and sorts before a final release of the same number. + +## A Manual Packaging Process Example + +Let's assume we have a `foo` v0.1.0 program that we would like to offer as a debian package. + +`go build -o ./build/foo .` + +Create a the debian package structure. + +```bash +mkdir -p ./dist/foo_0.1.0-1/DEBIAN +mkdir -p ./dist/foo_0.1.0-1/usr/local/bin +``` + +Copy the binary to the `usr/local/bin/` directory under our package namespace and ensure it's executable. + +```bash +cp ./build/foo ./dist/foo_0.1.0-1/usr/local/bin/foo +chmod +x ./dist/foo_0.1.0-1/usr/local/bin/foo +``` + +Now create a `control` file under the `DEBIAN/` directory + +```bash +touch ./dist/foo_0.1.0-1/DEBIAN/control +``` + +``` + +``` \ No newline at end of file