Adding sections about spec files and `packaging`.
parent
acb59721d3
commit
68537c60f6
|
@ -272,15 +272,13 @@ There is a strict separation between core system and third party software.<br />
|
|||
All our tools are designed to be simple to use, to understand, to read.
|
||||
<u>Feel free to provide a feedback.</u>
|
||||
|
||||
<red>TODO: spec files, the file format used in `package`, `packaging` and `service`.</red>
|
||||
|
||||
---
|
||||
|
||||
<a name="spec-format"></a>
|
||||
**Spec files.** *our declarative format*<br />
|
||||
Before presenting our tools, here a file format named `spec` that we tend to use when relevant.
|
||||
It is *declarative*: we tend not to tell instructions how to do things (copy this file here, download this, etc.) but to describe something (url of the project is `https://example.com/xxx`).
|
||||
This way, we can provide an easy to understand format which looks like YAML a lot, but allows us to do much more.
|
||||
The `spec format` is only composed of variables, lists, code block and named sections.
|
||||
Here a quick example.
|
||||
|
||||
```yaml
|
||||
|
@ -299,14 +297,14 @@ list:
|
|||
- c
|
||||
```
|
||||
|
||||
And now, we can add `block sections` to it: sometime we <u>do</u> want to tell instructions.
|
||||
This looks a lot like YAML, but now we add `code block` to it: because sometimes we <u>do</u> want to tell instructions.
|
||||
|
||||
```yaml
|
||||
# We have the URL of the tarballs for a software
|
||||
software-url: 'https://example.com/my-software/'
|
||||
|
||||
# ... and we want to get its last version number
|
||||
# "@watch" is a section, the name "watch" has a meaning in the application reading the file
|
||||
# "@watch" is a block, the name "watch" has a meaning in the application reading the file
|
||||
@watch
|
||||
# the following is simple shell scripting
|
||||
curl %{software-url} -o- 2>/dev/null | \
|
||||
|
@ -314,23 +312,27 @@ software-url: 'https://example.com/my-software/'
|
|||
tail -1
|
||||
```
|
||||
|
||||
Sometime, we want to refer to a file (or directory), and add metadata to it.
|
||||
Sometimes, we want to refer to a file (or directory) and add metadata to it: here `named sections`.
|
||||
|
||||
```yaml
|
||||
# as for "@watch", "%configuration" has a meaning in the application reading the file
|
||||
# this time, the block is named
|
||||
# this time, the block has an arbitrary name
|
||||
%configuration postgresql.conf
|
||||
# within a named block, we find simple declarations as outside the block
|
||||
# within a named section, we find simple declarations as outside the block
|
||||
name: database configuration
|
||||
creation-command: my-script.sh -a -b -c
|
||||
```
|
||||
|
||||
Next, the usage in practice: [packaging](#packaging), [service](#service).
|
||||
|
||||
---
|
||||
|
||||
<red>TODO: explains why it's different / better than other package managers.</red>
|
||||
|
||||
<a name="package"></a>
|
||||
**[Package][package]: our package manager.**<br />
|
||||
Package covers the basics: install, remove, search and provide informations about a package, and it creates rootfs.
|
||||
Package knows the minimal set of binaries and configuration required to build the target, so it only installs the minimal environment to perform compilation.
|
||||
`Package` covers the basics: install, remove, search and provide informations about a package.
|
||||
`Package` can create minimal rootfs, to bootstrap BaguetteOS on another system or to create test environments for example.
|
||||
|
||||
Package provides slotting by default: no need for custom environments for each software.
|
||||
|
||||
|
@ -339,37 +341,37 @@ The database format contains `world`, `installed`, `[package-name]/[slot]/manife
|
|||
|
||||
Package's configuration is a list of repositories, authorized package signing keys and packaging variables (cflags, makeflags, and so on).
|
||||
|
||||
Finally, `Package` can easily be expanded, as it only relies on a few hundred lines of Crystal code.
|
||||
|
||||
---
|
||||
|
||||
<a name="packaging"></a>
|
||||
**[Packaging][packaging]: to create packages.**<br />
|
||||
Packaging uses simple, declarative recipe files, here some examples: [hello][recipe-hello], [dhcpcd][recipe-dhcpcd], [alsa-utils][recipe-alsautils].
|
||||
The only required parameters are `name` and `sources`.
|
||||
**[Packaging][packaging]: creates packages.**<br />
|
||||
Any OS needs a way to create packages to share software, either by sharing sources that need to be compiled or by sharing pre-compiled binaries.
|
||||
As BaguetteOS is design to provide quickly usable systems, we choose to provide binaries.
|
||||
`Packaging` uses simple, declarative recipe files with the `spec format` [as we saw earlier](#spec-format).
|
||||
`Packaging` has a few advantages compared to most used packaging tools:
|
||||
- declarative recipes abstact OS specifics<br />
|
||||
The same recipe may work for many **native packaging systems** (many OSs), given that packagers provide the right target running dependencies.
|
||||
This only requires to provide a backend for the target package manager.
|
||||
- recipe readability is great<br />
|
||||
A few variable declarations are better than a dozen lines of code.
|
||||
- trivial shell script patterns become automated<br />
|
||||
`Autotools` and `cmake` build systems are detected; packagers should only provide specific parameters for each project.
|
||||
- tooling may evolve, very few recipes will be require to change<br />
|
||||
Everybody wants to change its build system?
|
||||
*(Besides possibly broken tools and possible workarounds,)* this is not a problem for the recipe, just `packaging`.
|
||||
- it creates hash'ed and signed packages by default<br />
|
||||
You need your own set of cryptographic keys, which is created at first use.
|
||||
- it creates repositories (automatic at first compilation), helping people maintaining their own set of tools<br />
|
||||
Change the first `prefix` in your [packaging configuration](#packaging-host-config), compile your first package and you have your repository.
|
||||
That is that simple.
|
||||
|
||||
```yaml
|
||||
# GNU Hello example program
|
||||
name: hello
|
||||
version: 2.10
|
||||
release: 2
|
||||
sources: https://ftp.gnu.org/gnu/hello/hello-%{version}.tar.gz
|
||||
|
||||
dependencies:
|
||||
- gettext
|
||||
|
||||
build-dependencies:
|
||||
- make
|
||||
|
||||
options:
|
||||
- configure: --disable-nls
|
||||
|
||||
@watch
|
||||
curl 'https://ftp.gnu.org/gnu/hello/' -o- 2>/dev/null |
|
||||
sed -n "/hello-.*\.tar\.gz/{s/\.tar\.gz.*//;s/.*hello-//;p}" |
|
||||
tail -1
|
||||
```
|
||||
<img src="/shell-scripting-is-lava.png" alt="shell script is lava" />
|
||||
|
||||
<a name="packaging-build-env"></a>
|
||||
Packaging creates build environments to test packages before validation.
|
||||
**`Packaging` build environments**<br />
|
||||
`Packages` creates build environments to test packages before validation.
|
||||
It works as follow:
|
||||
1. creation of a `/tmp/packaging/build-UUID/` directory
|
||||
2. sources are downloaded, extracted then compiled<br />
|
||||
|
@ -379,14 +381,152 @@ It works as follow:
|
|||
|
||||
|
||||
`Packaging` uses `package` to create low-cost build environments since we hardlink binaries into the building rootfs, which is inspired by the [proot][proot] tool on OpenBSD.
|
||||
In this case, `package` only installs the minimal set of binaries required by the package to build.
|
||||
Besides the target application, a building environment size is <u>only a few kilobytes</u>.
|
||||
|
||||
<red>TODO.</red>
|
||||
<a name="packaging-host-config"></a>
|
||||
Packaging configuration is simple.
|
||||
**`Packaging` configuration**. *common configuration for your packages*<br />
|
||||
`Packaging` may be configured globally for your system with the file `/etc/packaging.conf` which contains the following:
|
||||
|
||||
<red>TODO.</red>
|
||||
<a name="packaging-host-config"></a>
|
||||
Packaging recipes.
|
||||
```YAML
|
||||
# Configuration file for `packaging`
|
||||
|
||||
# where to send built packages
|
||||
packages-directory: /usr/local/pkg/
|
||||
# where to download sources
|
||||
sources-directory: /usr/local/src/
|
||||
|
||||
# prefixes for `packaging` running environment and child processes
|
||||
prefixes:
|
||||
# the first prefix is the default slot used for building application
|
||||
- /usr/baguette/
|
||||
- /
|
||||
|
||||
# list of environment variables we want to have when building
|
||||
environment:
|
||||
# you may choose another compiler, provide some CFLAGS, etc.
|
||||
- CC: clang
|
||||
- CFLAGS: -Os -Wall
|
||||
|
||||
# next three have special meaning
|
||||
# to provide parameters to the `./configure` script when building
|
||||
- configure: --disable-nls --without-gettext
|
||||
|
||||
# to provide parameters to the `make` command
|
||||
- make:
|
||||
|
||||
# to provide parameters to the final `make install` command
|
||||
- make install:
|
||||
|
||||
# wanna build for another system? not a problem, just add the backend (we currently have `apk` and `package`)
|
||||
package-manager: package
|
||||
```
|
||||
That's it. You know all about `packaging` configuration.
|
||||
These parameters may be override by recipes.
|
||||
|
||||
<a name="recipes"></a>
|
||||
**`Packaging` recipes.** *we need to create packages*<br />
|
||||
A recipe is the way to reproduce something; here we want to create a package, the recipe should provide all data necessary to be able to reproduce the package.
|
||||
This means at least having a name for the software and a version (they appear in the package name) and sources (software code).
|
||||
Let's take an example.
|
||||
|
||||
|
||||
```yaml
|
||||
# GNU Hello program
|
||||
name: hello # software name
|
||||
version: 2.10 # software version
|
||||
release: 2 # recipe release: incremented when the recipe change for the current version of the software
|
||||
|
||||
# the description will appear in the package information we can retrieve with `package`
|
||||
description: "This is the GNU Hello program."
|
||||
|
||||
# sources may be multiple: you may want to add arbitrary files along the tarball
|
||||
sources: https://ftp.gnu.org/gnu/hello/hello-%{version}.tar.gz
|
||||
|
||||
# we provide running dependencies: the program needs these to `run`
|
||||
dependencies:
|
||||
- gettext
|
||||
|
||||
# we provide build dependencies: the program needs these to `be compiled` for the package
|
||||
# no need to require these dependencies for a simple user installing the program
|
||||
build-dependencies:
|
||||
- make
|
||||
|
||||
# if we want to add or override compilation options
|
||||
options:
|
||||
- configure: --disable-nls
|
||||
|
||||
# feels like déjà vu, right?
|
||||
# "watch" code block helps to check if the recipe covers the last software version
|
||||
@watch
|
||||
curl 'https://ftp.gnu.org/gnu/hello/' -o- 2>/dev/null |
|
||||
sed -n "/hello-.*\.tar\.gz/{s/\.tar\.gz.*//;s/.*hello-//;p}" |
|
||||
tail -1
|
||||
```
|
||||
|
||||
This was [a real example][recipe-hello], and not the simplest one.
|
||||
Most of our recipes currently look like this:
|
||||
|
||||
```YAML
|
||||
name: dhcpcd
|
||||
version: 8.0.3
|
||||
sources: https://roy.marples.name/downloads/dhcpcd/dhcpcd-%{version}.tar.xz
|
||||
```
|
||||
That's it.
|
||||
Yes, we can add a few meta-data, but this is a working recipe.
|
||||
Configuration, compilation and packaging are done without providing anything else.
|
||||
The only required parameters are `name`, `sources` and `version`.
|
||||
|
||||
|
||||
<a name="packaging-manual-operations"></a>
|
||||
Sometimes, developers are assholes and force you to fix their build system.
|
||||
When manual operations <u>really are required</u>, you can use `@configure`, `@build` and `@install` code blocks.
|
||||
Let's see an example with a special snowflake… like `perl`.
|
||||
```YAML
|
||||
# in our example, we want to configure the build
|
||||
@configure
|
||||
# we set some script execution parameters: exit at any error, print everything you do
|
||||
set -e -x
|
||||
|
||||
# we currently are in `/tmp/packaging/build-UUID/`
|
||||
# now we enter the directory created by the tarball extraction, where the build occurs
|
||||
cd perl-%{version} # we can interpolate variables with this: %{}
|
||||
|
||||
# Perl needs a few environment variables for configuration
|
||||
BUILD_ZLIB=0
|
||||
BUILD_BZIP2=0
|
||||
BZIP2_LIB=/usr/lib
|
||||
BZIP2_INCLUDE=/usr/include
|
||||
export BUILD_ZLIB BUILD_BZIP2 BZIP2_LIB BZIP2_INCLUDE
|
||||
|
||||
# now we can launch the `configure` script…
|
||||
# … but wait kids, that's not `configure`, that is `Configure` (see the capitalized C?)
|
||||
# this is a totally different and very special script, but you should love it anyway
|
||||
./Configure -des -Dcccdlflags='-fPIC' \
|
||||
-Dcccdlflags='-fPIC' \
|
||||
-Dccdlflags='-rdynamic' \
|
||||
# ... some long and uninteresting list of very specific parameters because we are Perl, we are historic and stuff
|
||||
```
|
||||
|
||||
Now you know how to deal with `@configure`, `@build` and `@install`: these are code blocks allowing you to fix this kind of problems.
|
||||
Non standard build operations happen from time to time, and code blocks help you overcome this.
|
||||
When a lot of packages have the same workarounds, we think about detection and integration into `packaging`, so we can keep only specifics into recipes.
|
||||
|
||||
If you want to investigate a bit more, you can check [our recipe repository][recipes].
|
||||
Feel free to improve these recipes with meta-data, `@watch` code blocks… contributions are welcome.
|
||||
|
||||
<a name="packaging-own-repository"></a>
|
||||
<red>TODO: talk about creating a repository.</red>
|
||||
|
||||
<a name="packaging-future"></a>
|
||||
**Future of `packaging`.** *let's be even more declarative*<br />
|
||||
As we saw, `packaging` allows maintainers to create very simple and **readable** recipes.
|
||||
Sometimes we have to confront ourselves to poorly designed build systems, but we can hack a bit.
|
||||
In the future, manual operations should be reduced even more:
|
||||
- by adding a few other parameters to the environment<br />
|
||||
This imply to check for patterns in the recipes and to provide workarounds.
|
||||
- by adding new code blocks *before* the `configuration`, `build` and `install` steps<br />
|
||||
This would allow performing a few hacks in the directory (a quick `sed` in a file for instance) and still keeping automatic operations: the best of the two worlds.
|
||||
|
||||
---
|
||||
|
||||
|
@ -561,6 +701,7 @@ We currently aim at providing a rootfs with our tools, when we will have enough
|
|||
[baguette-rc]: https://git.baguette.netlib.re/Baguette/recipes/src/branch/master/rc
|
||||
[baguette-profile]: https://git.baguette.netlib.re/Baguette/recipes/src/branch/master/rc/profile
|
||||
|
||||
[recipes]: https://git.baguette.netlib.re/Baguette/recipes/
|
||||
[recipe-hello]: https://git.baguette.netlib.re/Baguette/recipes/src/branch/master/hello/recipe.spec
|
||||
[recipe-dhcpcd]: https://git.baguette.netlib.re/Baguette/recipes/src/branch/master/dhcpcd/recipe.spec
|
||||
[recipe-alsautils]: https://git.baguette.netlib.re/Baguette/recipes/src/branch/master/alsa-utils/recipe.spec
|
||||
|
|
Loading…
Reference in New Issue