# Tips, Hints and useful information ## General maintainability of your packages * Try hard to make all files work on all platforms you support. * Maintaining separate scripts, config, service files, etc for each platform quickly becomes difficult * Put as much conditional logic in the pre/post install scripts as possible instead of trying to build it into the nfpm.yaml * *if* you need to know the packaging system I have found it useful to add a `/etc/path-to-cfg/package.env` that contains `_INSTALLED_FROM=apk|deb|rpm` which can be sourced into the pre/post install/remove scripts * *if/when* you need to ask questions during the installation process, create an `install.sh` || `setup.sh` script that asks those questions and stores the answers as env vars in `/etc/path-to-cfg/package.env` for use by the pre/post install/remove scripts * If you only need to support deb packages you can use the debconf template/config feature, but since rpm does not support this I would try to unify the way you ask questions. ## Pre/post install scripts Here are some useful links for how these scripts work in each packager: * [APK Docs](https://wiki.alpinelinux.org/wiki/Creating_an_Alpine_package#install) * [RPM Docs](https://docs.fedoraproject.org/en-US/packaging-guidelines/Scriptlets/) * [DEB Docs](https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html) ### Examples
Example Multi platform post-install script ```bash #!/bin/sh # Step 1, decide if we should use SystemD or init/upstart use_systemctl="True" systemd_version=0 if ! command -V systemctl >/dev/null 2>&1; then use_systemctl="False" else systemd_version=$(systemctl --version | head -1 | sed 's/systemd //g') fi cleanup() { # This is where you remove files that were not needed on this platform / system if [ "${use_systemctl}" = "False" ]; then rm -f /path/to/.service else rm -f /etc/chkconfig/ rm -f /etc/init.d/ fi } cleanInstall() { printf "\033[32m Post Install of an clean install\033[0m\n" # Step 3 (clean install), enable the service in the proper way for this platform if [ "${use_systemctl}" = "False" ]; then if command -V chkconfig >/dev/null 2>&1; then chkconfig --add fi service restart ||: else # rhel/centos7 cannot use ExecStartPre=+ to specify the pre start should be run as root # even if you want your service to run as non root. if [ "${systemd_version}" -lt 231 ]; then printf "\033[31m systemd version %s is less then 231, fixing the service file \033[0m\n" "${systemd_version}" sed -i "s/=+/=/g" /path/to/.service fi printf "\033[32m Reload the service unit from disk\033[0m\n" systemctl daemon-reload ||: printf "\033[32m Unmask the service\033[0m\n" systemctl unmask ||: printf "\033[32m Set the preset flag for the service unit\033[0m\n" systemctl preset ||: printf "\033[32m Set the enabled flag for the service unit\033[0m\n" systemctl enable ||: systemctl restart ||: fi } upgrade() { printf "\033[32m Post Install of an upgrade\033[0m\n" # Step 3(upgrade), do what you need ... } # Step 2, check if this is a clean install or an upgrade action="$1" if [ "$1" = "configure" ] && [ -z "$2" ]; then # Alpine linux does not pass args, and deb passes $1=configure action="install" elif [ "$1" = "configure" ] && [ -n "$2" ]; then # deb passes $1=configure $2= action="upgrade" fi case "$action" in "1" | "install") cleanInstall ;; "2" | "upgrade") printf "\033[32m Post Install of an upgrade\033[0m\n" upgrade ;; *) # $1 == version being installed printf "\033[32m Alpine\033[0m" cleanInstall ;; esac # Step 4, clean up unused files, yes you get a warning when you remove the package, but that is ok. cleanup ```
Example Multi platform (RPM & Deb) post-remove script ```bash #!/bin/sh remove() { printf "\033[32m Post Remove of a normal remove\033[0m\n" echo "Remove" > /tmp/postremove-proof } purge() { printf "\033[32m Post Remove purge, deb only\033[0m\n" echo "Purge" > /tmp/postremove-proof } upgrade() { printf "\033[32m Post Remove of an upgrade\033[0m\n" echo "Upgrade" > /tmp/postremove-proof } echo "$@" action="$1" case "$action" in "0" | "remove") remove ;; "1" | "upgrade") upgrade ;; "purge") purge ;; *) printf "\033[32m Alpine\033[0m" remove ;; esac ```
### Execution order On upgrade, the scripts are being executed in the following order: 1. `pretrans` of new package (only applies to RPM) 2. `preinstall` of new package 3. `postinstall` of new package 4. `preremove` of old package 5. `postremove` of old package 6. `posttrans` of new package (only applies to RPM) ## SystemD and upstart/init ### upstart / init * try to just say no to supporting this, but if you must make sure you have a single script that works on all platforms you need to support. * as the `post-install` script above does. ### SystemD * The docs you find for SystemD are generally for the latest and greatest version, and it can be hard to find docs for older versions. * In the above `post-install` script you see I am doing a SystemD version check to correct the `ExecStartPre=+...` and `ExecStop=+...` lines * You should always use [automatic directory creation and environment variables](https://www.freedesktop.org/software/systemd/man/systemd.exec.html#id-1.14.4.3.6.2) * With the note that only `RuntimeDirectory` is used in SystemD < 231 * `/bin/bash -c "$(which ...) ...` is a great way to make your single service file work on all platforms since RHEL and Debian-based systems have standard executables in differing locations and complain about `executable path is not absolute` * e.g. `/bin/bash -c '$(which mkdir) -p /var/log/your-service'` ## Debian packages ### The `.lintian-overrides` file It is recommended to run [lintian](https://lintian.debian.org) against your deb packages to see if there are any problems. You can also add a `lintian-overrides` file: ```yaml # nfpm.yaml contents: - src: .lintian-overrides dst: ./usr/share/lintian/overrides/nfpm packager: deb file_info: mode: 0644 ``` You can read more in [lintian's documentation](https://lintian.debian.org/manual/index.html). ### The `copyright` file If you need a `copyright` file, you can add it using the `contents` directive: ```yaml # nfpm.yaml contents: - src: ./path/to/copyright dst: /usr/share/doc//copyright packager: deb file_info: mode: 0644 ```