Packaging explained

Packaging Explained

Pacman is the package manager for archlinux, while APT is the package manager for .deb distros.

Pacman comes with makepkg which is the official tool for package creation on archlinux.

The PKGBUILD defines the package which makepkg is to create. The PKGBUILD is written in bash; this text assumes the reader is familiar with shell scripting or that the illustrated concepts and annotations are understood in their context upon closer inspection.

There is no such official tool with the level of automation that makepkg provides on archlinux for debian.

dpkg is the closest thing (by default included with the OS) which has any similar functionality to makepkg. There are several different packaging tools with their own conventions available for packaging on debian but not included by default. I only ever used dpkg.

There is no single established method for creating .deb packages as there is for creating archlinux packages.

Hence is the challenge; and hence why I don’t blame those who are hesitant to embrace packages. If one was to approach .deb packaging with no previous experience in packaging software, it is almost garaunteed that one would bcome mired in the density and complexity of the official documentation on deb packages, and stuck on trivial, nonessential features of any single packaging tool. Too easy to waste a tremendous amount of time studying the contrived way that debian and .deb based distros do some things, and ultimately conclude that it’s not fesable or worth it and abandon the effort.

synth

But this doesn’t mean it’s a good idea to go around the package manager and just manage what you want to call a ‘software installation’ with scripts. There will always be something that is missed, something that doesn’t work as expected. Scripts which place binaries and other files in a file system a software installation does not make.

If you were going to manage a so-called ‘software installation’ with a script then the script would need to contain essentially the contents of makepkg and a PKGBUILD (adapted to the debian defaults, etc.) At that point, you don’t have a system of any kind that can handle other things similarly; you have a one-off single-purpose script that is incredibly difficult to maintain and troubleshoot and would quickly move out of the scope of the underlying software. Making a system for doing that extends beyond the context of the single piece of software which is attempting to be managed; so it won’t be done. Catch 22.

Honestly, you should not burden developers with figuring out how to make the software update itself when in deployment. Taking the wrong approach will not lead to solutions

After some years of doing archlinux packaging, I devised a scheme for building .deb packages with archlinux packaging tools, which was detailed in this article.

The only thing this fails to accomplish is creating .deb on .deb, so to speak. The solution I developed (and then abandoned and then adopted again) is to use a chroot of archlinux on deb distros to create the .deb package. The aforementioned process is outlined in advanced node management.

So why use debian? Maybe sometimes you can’t get arch to work on your hardware. Any linux is better than no linux. Armbian supports a vast number of boards with already-made images. It is definitely worth it if you can get archlinuxARM to run on your hardware.

This article hopes to familiarize you with a standard packaging system using arch packaging tools; which can create .deb packages. Using the example of the existing skycoin packages which I currently maintain in the AUR; some of which are also provided by the apt repo

We will be referring to packages by their name in the AUR

skycoin-bin

skycoin-bin in the AUR

skycoin-bin AUR repo files

skycoin github

The first example is a binary release, which is the simplest to package.

Let’s examine the PKGBUILD

# Maintainer: Moses Narrow <moe_narrow@use.startmail.com>
# Maintainer: Rudi [KittyCash] <rudi@skycoinmail.com>
#t.me/Skycoin for inquiries
_pkgname=skycoin
pkgname=${_pkgname}-bin
_projectname=${_pkgname}
_githuborg=${_projectname}
pkgdesc="Skycoin Cryptocurrency Wallet; Binary Release"
pkgver='0.27.1'
_pkggopath="github.com/${_githuborg}/${_pkgname}"
pkgrel=2
arch=('x86_64' 'aarch64' 'armv8' 'armv7' 'armv7l' 'armv7h' 'armv6h' 'armhf' 'armel' 'arm')
url="https://${_pkggopath}"
_url="https://downloads.${_projectname}.com/wallet"
license=()
makedepends=()
provides=( 'skycoin' )
conflicts=( 'skycoin' )
#bsdtar -czvf skycoin-scripts.tar.gz skycoin-scripts
source=("${_pkgname}-scripts.tar.gz")
sha256sums=('0738ce23beafc315cad3971afb9b210b0749df05e064db169aea618b5bbd5555')
#https://downloads.skycoin.com/wallet/skycoin-0.27.1-gui-standalone-linux-x64.tar.gz
#https://downloads.skycoin.com/wallet/skycoin-0.27.1-gui-standalone-linux-arm.tar.gz
_release_url=("${_url}/${_pkgname}-${pkgver}-gui-standalone-linux")
source_x86_64=("${_release_url}-x64.tar.gz")
source_aarch64=("${_release_url}-arm.tar.gz")
source_armv8=( ${source_aarch64[@]} )
source_armv7=( ${source_aarch64[@]} )
source_armv7h=( ${source_aarch64[@]} )
source_armv7l=( ${source_aarch64[@]} )
source_armv6h=( ${source_aarch64[@]} )
source_armhf=( ${source_aarch64[@]} )
source_armel=( ${source_aarch64[@]} )
source_arm=( ${source_aarch64[@]} )
sha256sums_x86_64=('ba4c2354b091b3db0ac7418caab1d52988b6fd1d18a9f0d5e0ebcb3f4ef15f94')
sha256sums_aarch64=('e4bbbde43a4971d21aefec55d4fbe3173694567bc372718ce4dd7352ca0bc169')
sha256sums_armv8=( ${sha256sums_aarch64[@]} )
sha256sums_armv7=( ${sha256sums_aarch64[@]} )
sha256sums_armv7h=( ${sha256sums_aarch64[@]} )
sha256sums_armv7l=( ${sha256sums_aarch64[@]} )
sha256sums_armv6h=( ${sha256sums_aarch64[@]} )
sha256sums_armhf=( ${sha256sums_aarch64[@]} )
sha256sums_armel=( ${sha256sums_aarch64[@]} )
sha256sums_arm=( ${sha256sums_aarch64[@]} )

package() {
_msg2 'creating dirs'
#create directory trees
mkdir -p ${pkgdir}/usr/bin
mkdir -p ${pkgdir}/opt/${_pkgname}/bin

_msg2 'installing binaries'
#install binary
if [[ $CARCH == 'x86_64' ]] ; then
install -Dm755 ${_pkgname}-${pkgver}-gui-standalone-linux-x64/${_pkgname} ${pkgdir}/opt/${_pkgname}/bin/${_pkgname}
else
install -Dm755 ${_pkgname}-${pkgver}-gui-standalone-linux-arm/${_pkgname} ${pkgdir}/opt/${_pkgname}/bin/${_pkgname}
fi
ln -rTsf ${pkgdir}/opt/${_pkgname}/bin/${_pkgname} ${pkgdir}/usr/bin/${_pkgname}
chmod 755 ${pkgdir}/usr/bin/${_pkgname}

_msg2 'installing gui sources'
#install the web dir (UI)
cp -r ${srcdir}/${_pkgname}-${pkgver}-*/src ${pkgdir}/opt/${_pkgname}/

_msg2 'installing scripts'
#install the scripts
install -Dm755 ${srcdir}/${_pkgname}-scripts/${_pkgname}-wallet ${pkgdir}/usr/bin/${_pkgname}-wallet
install -Dm755 ${srcdir}/${_pkgname}-scripts/${_pkgname}-wallet-nohup ${pkgdir}/usr/bin/${_pkgname}-wallet-nohup

_msg2 'installing systemd services'
#install the system.d service
install -Dm644 ${srcdir}/${_pkgname}-scripts/${_pkgname}-node.service ${pkgdir}/usr/lib/systemd/system/${_pkgname}-node.service
}

_msg2() {
(( QUIET )) && return
local mesg=$1; shift
printf "${BLUE}  ->${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@"
}

The PKGBUILD tells makepkg what to do to make this package.

The only somewhat complicated thing going on here; this build supports creating packages for arm architectures as well as x86_64 / amd64

an example of building this package on archlinux; Clone skycoin-bin from the AUR to the path where yay would clone it, and change to that dir

mkdir -p~/.cache/yay/
cd ~/.cache/yay
[ d skycoin-bin ] && cd skycoin-bin && git pull origin master
[! d skycoin-bin] && git clone https://aur.archlinux.org/skycoin-bin && cd skycoin-bin

now, run makepkg

makepkg
==> Making package: skycoin-bin 0.27.1-2 (Wed 29 Sep 2021 08:45:03 AM CDT)
==> Checking runtime dependencies...
==> Checking buildtime dependencies...
==> Retrieving sources...
 -> Found skycoin-scripts.tar.gz
 -> Found skycoin-0.27.1-gui-standalone-linux-x64.tar.gz
==> Validating source files with sha256sums...
   skycoin-scripts.tar.gz ... Passed
==> Validating source_x86_64 files with sha256sums...
   skycoin-0.27.1-gui-standalone-linux-x64.tar.gz ... Passed
==> Extracting sources...
 -> Extracting skycoin-scripts.tar.gz with bsdtar
 -> Extracting skycoin-0.27.1-gui-standalone-linux-x64.tar.gz with bsdtar
==> Entering fakeroot environment...
==> Starting package()...
 -> creating dirs
 -> installing binaries
 -> installing gui sources
 -> installing scripts
 -> installing systemd services
==> Tidying install...
 -> Removing libtool files...
 -> Purging unwanted files...
 -> Removing static library files...
 -> Stripping unneeded symbols from binaries and libraries...
 -> Compressing man and info pages...
==> Checking for packaging issues...
==> Creating package "skycoin-bin"...
 -> Generating .PKGINFO file...
 -> Generating .BUILDINFO file...
 -> Generating .MTREE file...
 -> Compressing package...
==> Leaving fakeroot environment.
==> Finished making: skycoin-bin 0.27.1-2 (Wed 29 Sep 2021 08:45:11 AM CDT)

The skycoin-bin package was built. You can install it, now, on archlinux

sudo pacman -U skycoin-bin*.tar.zst

a script is provided by the skycoin-scripts.tar.gz archive which will launch the wallet with the correct defaults.

cat /usr/bin/skycoin-wallet
#!/bin/bash
#launch skycoin wallet
skycoin -gui-dir=/opt/skycoin/src/gui/static/ -launch-browser=true -enable-all-api-sets=true -enable-gui=true -log-level=debug

Launch the wallet like this:

cd ~/
skycoin-wallet

the browser will launch, so you can access the UI, and the blockchain will start syncing.

So what happened in the build? Makepkg downloads the sources and verifies the sha256sums. Signature checking is also possible, however the keys needed for this must be present as well; this is typically done with a keyring package containing the gpg key listed as a dependency. This was previously the case, but the extra dependency of the keying package was somewhat burdensome.

The source archives are automatically extracted, before any of the other functions in the PKGBUILD are executed.

The only function in this build is package(), which is typical for a binary package such as this.

The package function is done in a fakeroot; everything inside the ${pkgdir} is representative of where the software components (such as binary executables, scripts, gui sources, etc) are placed into the filesystem.

to get the permissions correct, the install command is used. The only appropriate use of the install command is when creating a package (as far as I am aware).

install -Dm755 is used to install binary executables install -Dm644 is used to install systemd services and the like into the package

All the skycoin software is installed to /opt/ per Synth’s directive. The binaries and scripts are symlinked to /usr/bin from where they are installed in /opt/skycoin/bin

You may be asking yourself, what about the _msg2() func?

msg2 is an internal function of makepkg which many people use in their PKGBUILDs, but it is against the conventions to use it. So I simply copied the msg2 function from makepkg into my PKGBUILDs as _msg2 for some extra colorful logging that appears the same way the other logging from makepkg.

skycoin-bin .deb package

There is another PKGBUILD maintained in the skycoin-bin AUR repository; cc.deb.PKGBUILD or the crosscompile deb PKGBUILD.

this build will produce .deb packages for all architectures.

# Maintainer: Moses Narrow <moe_narrow@use.startmail.com>
# Maintainer: Rudi [KittyCash] <rudi@skycoinmail.com>
#t.me/Skycoin for inquiries
_pkgname=skycoin
pkgname=skycoin-bin
_projectname=${_pkgname}
_githuborg=${_projectname}
pkgdesc="Skycoin Cryptocurrency Wallet; Binary Release - DEBIAN PACKAGE"
pkgver='0.27.1'
_pkgver=$pkgver
_pkggopath="github.com/${_githuborg}/${_pkgname}"
pkgrel=2
_pkgrel=$pkgrel
#set to native architecture with dpkg
_pkgarch=$(dpkg --print-architecture)
_pkgarches=('armhf' 'arm64' 'amd64')
#leave arch package as any
arch=('any')
url="https://${_pkggopath}"
_url="https://downloads.${_projectname}.com/wallet"
license=()
makedepends=('dpkg')
provides=( 'skycoin' )
conflicts=( 'skycoin' )
#bsdtar -czvf skycoin-scripts.tar.gz skycoin-scripts
source=("${_pkgname}-scripts.tar.gz")
# "PKGBUILD.sig")
sha256sums=('0738ce23beafc315cad3971afb9b210b0749df05e064db169aea618b5bbd5555')
# 'SKIP')
#https://downloads.skycoin.com/wallet/skycoin-0.27.1-gui-standalone-linux-x64.tar.gz
#https://downloads.skycoin.com/wallet/skycoin-0.27.1-gui-standalone-linux-arm.tar.gz
_release_url=("${_url}/${_pkgname}-${pkgver}-gui-standalone-linux")
source_x86_64=("${_release_url}-x64.tar.gz")
# "${_release_url}-x64.tar.gz.asc")
source_aarch64=("${_release_url}-arm.tar.gz")
# "${_release_url}-arm.tar.gz.asc")
source_armv8=( ${source_aarch64[@]} )
source_armv7=( ${source_aarch64[@]} )
source_armv7h=( ${source_aarch64[@]} )
source_armv7l=( ${source_aarch64[@]} )
source_armv6h=( ${source_aarch64[@]} )
source_armhf=( ${source_aarch64[@]} )
source_armel=( ${source_aarch64[@]} )
source_arm=( ${source_aarch64[@]} )
sha256sums_x86_64=('ba4c2354b091b3db0ac7418caab1d52988b6fd1d18a9f0d5e0ebcb3f4ef15f94')
# 'ba4c2354b091b3db0ac7418caab1d52988b6fd1d18a9f0d5e0ebcb3f4ef15f94')
sha256sums_aarch64=('e4bbbde43a4971d21aefec55d4fbe3173694567bc372718ce4dd7352ca0bc169')
# 'e4bbbde43a4971d21aefec55d4fbe3173694567bc372718ce4dd7352ca0bc169'
sha256sums_armv8=( ${sha256sums_aarch64[@]} )
sha256sums_armv7=( ${sha256sums_aarch64[@]} )
sha256sums_armv7h=( ${sha256sums_aarch64[@]} )
sha256sums_armv7l=( ${sha256sums_aarch64[@]} )
sha256sums_armv6h=( ${sha256sums_aarch64[@]} )
sha256sums_armhf=( ${sha256sums_aarch64[@]} )
sha256sums_armel=( ${sha256sums_aarch64[@]} )
sha256sums_arm=( ${sha256sums_aarch64[@]} )

build() {
  for i in ${_pkgarches[@]}; do
    msg2 "_pkgarch=$i"
    local _pkgarch=$i
    _msg2 'creating the DEBIAN/control files'
    #create control file for the debian package
    echo "Package: skycoin-bin" > ${srcdir}/${_pkgarch}.control
    echo "Version: ${_pkgver}-${_pkgrel}" >> ${srcdir}/${_pkgarch}.control
    echo "Priority: optional" >> ${srcdir}/${_pkgarch}.control
    echo "Section: web" >> ${srcdir}/${_pkgarch}.control
    echo "Architecture: ${_pkgarch}" >> ${srcdir}/${_pkgarch}.control
    #echo "Depends: ${_debdeps}" >> ${srcdir}/${_pkgarch}.control
    echo "Maintainer: the-skycoin-project" >> ${srcdir}/${_pkgarch}.control
    echo "Description: ${pkgdesc}" >> ${srcdir}/${_pkgarch}.control

  done
}

package() {
#loop to make packages for the different architectures
  for i in ${_pkgarches[@]}; do
  msg2 "_pkgarch=${i}"
  local _pkgarch=${i}

_msg2 'creating dirs'
####################### set up to create a .deb package #######################
#_debpkgdir is the full name of the package with version and architecture
_debpkgdir="${_pkgname}-bin-${pkgver}-${_pkgrel}-${_pkgarch}"
#_pkgdir substituites for pkgdir in terms of where the files are installed, so the package operation is the same as for archlinux
_pkgdir="${pkgdir}/${_debpkgdir}"
_skydir="opt/skycoin"
_skybin="${_skydir}/bin"
[[ -d ${_pkgdir} ]] && rm -rf ${_pkgdir}
mkdir -p ${_pkgdir}/usr/bin ${_skybin}

cd $_pkgdir

_msg2 'installing binaries'
#install binary
_msg2 'installing gui sources'
#install the web dir (UI)
if [[ $CARCH == 'x86_64' ]] ; then
  install -Dm755 ${srcdir}/${_pkgname}-${pkgver}-gui-standalone-linux-x64/${_pkgname} ${_pkgdir}/${_skybin}/${_pkgname}
  cp -r ${srcdir}/${_pkgname}-${pkgver}-gui-standalone-linux-x64/src ${_pkgdir}/opt/${_pkgname}/
else
install -Dm755 ${srcdir}/${_pkgname}-${pkgver}-gui-standalone-linux-arm/${_pkgname} ${_pkgdir}/${_skybin}/${_pkgname}
cp -r ${srcdir}/${_pkgname}-${pkgver}-gui-standalone-linux-arm/src ${_pkgdir}/opt/${_pkgname}/
fi
ln -rTsf ${_pkgdir}/${_skybin}/${_pkgname} ${_pkgdir}/usr/bin/${_pkgname}
chmod 755 ${_pkgdir}/usr/bin/${_pkgname}


_msg2 'installing scripts'
#install the scripts
install -Dm755 ${srcdir}/${_pkgname}-scripts/${_pkgname}-wallet ${_pkgdir}/usr/bin/${_pkgname}-wallet
install -Dm755 ${srcdir}/${_pkgname}-scripts/${_pkgname}-wallet-nohup ${_pkgdir}/usr/bin/${_pkgname}-wallet-nohup

_msg2 'installing DEBIAN/control file, postinst & postrm scripts'
install -Dm755 ${srcdir}/${_pkgarch}.control ${_pkgdir}/DEBIAN/control
#install -Dm755 ${srcdir}/${_scripts}/postinst.sh ${_pkgdir}/DEBIAN/postinst
#install -Dm755 ${srcdir}/${_scripts}/postrm.sh ${_pkgdir}/DEBIAN/postrm

_msg2 'creating the debian package'
########################create the debian package!#########################
cd $pkgdir
dpkg-deb --build -z9 ${_debpkgdir}
mv *.deb ../../
done
#exit so the arch package doesn't get built
exit

}

_msg2() {
(( QUIET )) && return
local mesg=$1; shift
printf "${BLUE}  ->${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@"
}

As you can see, this file is very similar to the standard PKGBUILD. The same sources are used.

We have a build() function which creates the DEBIAN/control file, which is a metadata file necessarily included in any debian package.

Now in the package() function, we use a for loop to preform the same basic assembly of the package three times, once with the sources for x86_64 (or amd64 on deb) and another two times with the sources for arm, to create an arm64 and an armhf package. It is critical to use the correct architecture codes in the control file created in the build function.

the .deb package is built at the end of the package() func, and then the build is exited so the archlinux package does not get built.

Note carefully how this is done: first, a folder is created inside ${pkgdir} which is the folder the .deb package will be assembled into. The name of this folder is important as it will be the name of the package archive that is created.

I use the naming convention:

packagename-version-release-architecture

which differs slightly from the standard naming convention for .deb packages in only that it includes the architecture code. This is fine to do and has never caused issues for me.

Updating the PKGBUILD on new versions

Every so often (once in a blue moon) a new version is released. In that event, what is needed to update the PKGBUILD?

On version changes, pkgrel can reset to 1. pkgrel defines a minor release number, which is a change to the PKGBUILD not accompanied by changes to the version. This number must increment to update the package in the AUR unless the version changes.

It’s simple enough to update the version, by changing pkgver= to the current version. After that, the build will fail unless the sha256sums are also updated to their correct value.

updating the sha256sums can be done by hand or with updpkgsums provided by the pacman-contrib package. When multiple architectures are involved, check after running updpkgsums to ensure that the checksums were updated correctly.

After the version is changed and the checksums are updated, simply run makepkg to create the new package.

skycoin

So far, we have only discussed the most basic binary release package. A more advanced example is the skycoin AUR package. This package builds the binaries from source, using the source archive which accompanies the binary releases.

here is the PKGBUILD for skycoin in the AUR

# Maintainer: Moses Narrow <moe_narrow@use.startmail.com>
# Maintainer: Rudi [KittyCash] <rudi@skycoinmail.com>
pkgname=skycoin
_pkgname=${pkgname}
_githuborg=${_pkgname}
pkgdesc="Skycoin Cryptocurrency Wallet. skycoin.com"
pkgver=0.27.1
pkgrel=1
arch=('x86_64' 'aarch64' 'armv8' 'armv7' 'armv7l' 'armv7h' 'armv6h' 'armhf' 'armel' 'arm')
_pkggopath="github.com/${_githuborg}/${_pkgname}"
url="https://${_pkggopath}"
makedepends=('go' 'musl' 'kernel-headers-musl')
source=("${url}/archive/v${pkgver}.tar.gz"
"${_pkgname}-scripts.tar.gz"
)
sha256sums=('4ede6a23e62bf50f097a647519b5b714a5581065bf71c9778e0965a7c84b112b'
            '5e147befaf68e30efa7a15e8b292e52cacb94846de4ac03158275a357c8b7dbc')

#tar -czvf skycoin-scripts.tar.gz skycoin-scripts
#updpkgsums

	prepare() {
		mkdir -p ${srcdir}/go/src/github.com/${_githuborg}/ ${srcdir}/go/bin
		ln -rTsf ${srcdir}/${_pkgname}-${pkgver} ${srcdir}/go/src/${_pkggopath}
	}

build() {
	export GOPATH=${srcdir}/go
	export GOBIN=${GOPATH}/bin
  export CC=musl-gcc
  export CGO_ENABLED=1
	_cmddir=${srcdir}/go/src/${_pkggopath}/cmd

  _buildbins address_gen
  _buildbins cipher-testdata
  _buildbins monitor-peers
  _buildbins newcoin
  _buildbins skycoin
  _buildbins skycoin-cli
	#binary transparency
	cd $GOBIN
	_msg2 'binary sha256sums'
	sha256sum $(ls)
}

_buildbins() {

_binname=$1
_msg2 "building ${_binname} binary"
if [[ ! -f ${GOBIN}/${_binname} ]] ; then
	cd ${_cmddir}/${_binname}
  go build -trimpath --ldflags '-linkmode external -extldflags "-static" -buildid=' -o $GOBIN/ .
fi
}

package() {
	#create directory trees
	_skysrcdir=${srcdir}/${_pkgname}-${pkgver}
	_skypath=${pkgdir}/opt/${_pkgname}
	_skygobin=${_skypath}/bin
	_skyguidir=${_skypath}/src/gui
	mkdir -p ${pkgdir}/usr/bin
	mkdir -p ${_skygobin}
	mkdir -p ${_skyguidir}
	#install binaries & symlink to /usr/bin
	_msg2 'installing binaries'
	_skybin="${srcdir}"/go/bin
	#avoid generic names for binaries
	#collect the binaries & install
	_skybins=$( ls "$_skybin")
	for i in $_skybins; do
		install -Dm755 ${srcdir}/go/bin/${i} ${_skygobin}/${i}
		ln -rTsf ${_skygobin}/$i ${pkgdir}/usr/bin/${i}
		chmod 755 ${pkgdir}/usr/bin/${i}
	done
  _msg2 'installing gui sources'
	#install the web dir (UI)
	cp -r ${_skysrcdir}/src/gui/static ${_skyguidir}
  _msg2 'installing scripts'
	#install the scripts
	_skycoinscripts=$( ls --ignore=*.service ${srcdir}/${_pkgname}-scripts/ )
	for i in $_skycoinscripts; do
		install -Dm755 ${srcdir}/${_pkgname}-scripts/${i} ${_skygobin}/${i}
		ln -rTsf ${_skygobin}/${i} ${pkgdir}/usr/bin/${i}
		chmod 755 ${pkgdir}/usr/bin/${i}
	done
  _msg2 'installing systemd services'
  #install the system.d service
    install -Dm644 ${srcdir}/${_pkgname}-scripts/skycoin-node.service ${pkgdir}/usr/lib/systemd/system/skycoin-node.service
  _msg2 'correcting symlink names'
	#correct symlink names
	cd ${pkgdir}/usr/bin/
	_namechange=$(ls --ignore='skycoin*')
	for i in $_namechange; do
		mv ${pkgdir}/usr/bin/${i} ${pkgdir}/usr/bin/${_pkgname}-${i}
	done
}

_msg2() {
(( QUIET )) && return
local mesg=$1; shift
printf "${BLUE}  ->${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@"
}

This is only slightly more complex, but to anyone with familiarity building golang binaries, this should look familiar.

So the source archive is extracted, and in the prepare() function this is symlinked to a GOPATH which is created in the ${srcdir}.

The binaries are manually compiled using go build and musl-gcc is used to eliminate the glibc dependency. This was also something that Synth has on numerous occasions expressed interest in; eliminating glibc as a runtime dependency.

The new concept introduced with this build is the dependency management aspect; there are two types of dependencies, broadly speaking. Those needed to compile the software and those needed to run it. Using musl eliminates glibc as a runtime dependency.

The compilation dependencies are the makedepends which include golang, officially, and for the purposes of this build, musl and kernel-headers-musl.

makepkg can have pacman install the needed makedepends, if they are officially provided by a repository configured in /etc/pacman.conf if the -s flag is used when invoking makepkg.

If the dependencies or makedependencies are only available from the AUR, yay is able to automatically install them and will offer to remove the makedependencies after installation as well. But this only works in the typical invocation of yay; i.e. not in the existing setup of these examples.

A note here on dependency management: Makepkg can be made to run on debian natively, but it uses pacman to handle the dependencies. Dependencies often have different names on different linux distributions; such is the case here. go on archlinux is golang on debian. It should go without saying don’t install arch packages on .deb or vice versa. Don’t try to handle dependencies with one package manager on a linux distro which it did not come from, or you will break your system. You have been warned.

The correct way is to use a chroot.

skywire-bin

The skywire-bin and skywire packages share similarity with the above skycoin packages. A new concept introduced here are the install / postinst scripts which create the skywire config .json file. This was instrumental for automation.

the skywire-bin PKGBUILD:

# Maintainer: Moses Narrow <moe_narrow@use.startmail.com>
# Maintainer: Rudi [KittyCash] <rudi@skycoinmail.com>
_pkgname=skywire
pkgname=${_pkgname}-bin
_projectname=skycoin
_githuborg=${_projectname}
pkgdesc="Skywire: Building a New Internet. Skycoin.com"
_pkgver='0.4.2'
_tag_ver="v${_pkgver}"
pkgver=${_pkgver//-/.}
_pkggopath="github.com/${_githuborg}/${_pkgname}"
pkgrel=4
arch=( 'i686' 'x86_64' 'aarch64' 'armv8' 'armv7' 'armv7l' 'armv7h' 'armv6h' 'armhf' 'armel' 'arm' )
url="https://${_pkggopath}"
makedepends=()
depends=()
provides=( 'skywire' )
conflicts=( 'skywire' )
install=skywire.install
_scripts=${_pkgname}-scripts
source=("${_scripts}.tar.gz" )
# "PKGBUILD.sig")
sha256sums=('ca6f604f5d925a8c37b99a709661196a29b1f9db961e3510e357265ce79772ed')
sha256sums_i686=('93d2dec6f6ae3a4d1aad097f3cd79acba491ab617182e88ced8a0f5f4a7fe598')
sha256sums_x86_64=('1d1a24d50c7838ae369a15ff914777c0a54352383b9b2ffd319e6a61f1bc1659')
sha256sums_aarch64=('a0fc5f7b17e6e6e22b0d4fc144bf9ee19ab7d78a3fa785bbfdb5a653de936253')
sha256sums_armv8=('a0fc5f7b17e6e6e22b0d4fc144bf9ee19ab7d78a3fa785bbfdb5a653de936253')
sha256sums_armv7=('89956549bedcc53393895c9d37146e5423da0836acf10824a0d8b95775134737')
sha256sums_armv7l=('89956549bedcc53393895c9d37146e5423da0836acf10824a0d8b95775134737')
sha256sums_armv7h=('89956549bedcc53393895c9d37146e5423da0836acf10824a0d8b95775134737')
sha256sums_arm=('89956549bedcc53393895c9d37146e5423da0836acf10824a0d8b95775134737')
_release_url=("${url}/releases/download/${_tag_ver}/${_pkgname}-${_tag_ver}-linux")
source_x86_64=("${_release_url}-amd64.tar.gz")
source_aarch64=("${_release_url}-arm64.tar.gz")
source_armv8=( ${source_aarch64[@]} )
source_arm=("${_release_url}-arm.tar.gz")
source_armv7=( ${source_arm[@]} )
source_armv7l=( ${source_arm[@]} )
source_armv7h=( ${source_arm[@]} )
source_i686=("${_release_url}-386.tar.gz")

#tar -czvf skywire-scripts.tar.gz skywire-scripts
#updpkgsums

package() {
_msg2 'creating dirs'
#create directory trees or the visor might make them with weird permissions
_skydir="opt/skywire"
_skyapps="${_skydir}/apps"
_skyscripts="${_skydir}/scripts"
_systemddir="etc/systemd/system"
_skybin="${_skydir}/bin"
mkdir -p ${pkgdir}/usr/bin
mkdir -p ${pkgdir}/${_skydir}/bin
mkdir -p ${pkgdir}/${_skydir}/apps
mkdir -p ${pkgdir}/${_skydir}/ssl
mkdir -p ${pkgdir}/${_skydir}/local
mkdir -p ${pkgdir}/${_skydir}/dmsgpty
mkdir -p ${pkgdir}/${_skydir}/${_pkgname}
mkdir -p ${pkgdir}/${_skydir}/transport_logs
mkdir -p ${pkgdir}/${_skydir}/scripts


_msg2 'installing binaries'
_msg3 'skywire-visor'
install -Dm755 ${srcdir}/${_pkgname}-visor ${pkgdir}/${_skybin}/
ln -rTsf ${pkgdir}/${_skybin}/${_pkgname}-visor ${pkgdir}/usr/bin/${_pkgname}-visor
_msg3 'skywire-cli'
install -Dm755 ${srcdir}/${_pkgname}-cli ${pkgdir}/${_skybin}/
ln -rTsf ${pkgdir}/${_skybin}/${_pkgname}-cli ${pkgdir}/usr/bin/${_pkgname}-cli
_msg2 'installing app binaries'
_msg3 'skychat'
install -Dm755 ${srcdir}/skychat ${pkgdir}/${_skyapps}/
_msg3 'skysocks'
install -Dm755 ${srcdir}/skysocks ${pkgdir}/${_skyapps}/
_msg3 'skysocks-client'
install -Dm755 ${srcdir}/skysocks-client ${pkgdir}/${_skyapps}/
_msg3 'vpn-client'
install -Dm755 ${srcdir}/vpn-client ${pkgdir}/${_skyapps}/
_msg3 'vpn-server'
install -Dm755 ${srcdir}/vpn-server ${pkgdir}/${_skyapps}/
_msg2 'installing scripts'
_skywirescripts=$( ls ${srcdir}/${_scripts}/${_pkgname} )
for i in ${_skywirescripts}; do
  _install2 ${srcdir}/${_scripts}/${_pkgname}/${i} ${_skyscripts}
done

#rename visor to skywire
[[ -f ${pkgdir}/usr/bin/${_pkgname}-visor ]] && mv ${pkgdir}/usr/bin/${_pkgname}-visor ${pkgdir}/usr/bin/${_pkgname}

#install the system.d services (from the source)
#install -Dm644 ${srcdir}/go/src/${_pkggopath}/init/${_pkgname}-hypervisor.service ${pkgdir}/usr/lib/systemd/system/${_pkgname}-hypervisor.service
#install -Dm644 ${srcdir}/go/src/${_pkggopath}/init/${_pkgname}-visor.service ${pkgdir}/usr/lib/systemd/system/${_pkgname}-visor.service

#install the patched system.d services
install -Dm644 ${srcdir}/${_scripts}/systemd/${_pkgname}.service ${pkgdir}/${_systemddir}/${_pkgname}.service
install -Dm644 ${srcdir}/${_scripts}/systemd/${_pkgname}-visor.service ${pkgdir}/${_systemddir}/${_pkgname}-visor.service

#tls key and certificate generation
#install -Dm755 ${srcdir}/${_pkgname}/static/skywire-manager-src/ssl/generate-1.sh ${pkgdir}/${_skydir}/ssl/generate.sh
install -Dm755 ${srcdir}/${_scripts}/ssl/generate.sh ${pkgdir}/${_skydir}/ssl/generate.sh
ln -rTsf ${pkgdir}/${_skydir}/ssl/generate.sh ${pkgdir}/usr/bin/${_pkgname}-tls-gen
install -Dm644 ${srcdir}/${_scripts}/ssl/certificate.cnf ${pkgdir}/${_skydir}/ssl/certificate.cnf
}
_install2() {
_binname="${1##*/}"
_binname="${_binname%%.*}"
install -Dm755 ${1} ${pkgdir}/${2}/${_binname}
ln -rTsf ${pkgdir}/${2}/${_binname} ${pkgdir}/usr/bin/${_binname}
chmod +x ${pkgdir}/usr/bin/${_binname}
}

_msg2() {
(( QUIET )) && return
local mesg=$1; shift
printf "${BLUE}  ->${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@"
}

_msg3() {
(( QUIET )) && return
local mesg=$1; shift
printf "${BLUE}  -->${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@"
}

looking at the install script:

post_install() {
/opt/skywire/scripts/skywire-autoconfig
}

post_upgrade() {
post_install
}

pre-remove() {
systemctl disable --now skywire.service
systemctl disable --now skywire-visor.service
}

post_remove() {
#remove possibly dangling configs so as not to interfere with future installs
rm -rf /opt/skywire
}

the config file generation is in the skywire-autoconfig script. If anything gets messed up in terms of the configuration files and the user doesn’t know what they did; skywire-autoconfig can typically achieve a working state. In lieu of that, if something is really messed up; reinstalling will achieve a working state faster than any troubleshooting of the user’s actions.

the skywire-autoconfig script is where the magic happens:

#!/usr/bin/bash
#root portion of the configuration
if [[ $EUID -ne 0 ]]; then
   echo -e "Root permissions required" 1>&2
   exit 100
fi
_nc='\033[0m'
_red='\033[0;31m'
_green='\033[0;32m'
_yellow='\033[0;33m'
_blue='\033[1;34m'
_purple='\033[0;35m'
_cyan='\033[0;36m'
_bold='\033[1m'

_msg2() {
	(( QUIET )) && return
	local mesg=$1; shift
	printf "${_cyan}  ->${_nc}${_bold} ${mesg}${_nc}\n" "$@"
}

_msg3() {
(( QUIET )) && return
local mesg=$1; shift
printf "${BLUE}  -->${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@"
}

_errmsg1() {
	(( QUIET )) && return
	local mesg=$1; shift
	printf "${_red}  >>> Error:${_bold} ${mesg}${_nc}\n" "$@"
}

_warnmsg1() {
	(( QUIET )) && return
	local mesg=$1; shift
	printf "${_red}  >>> Warning:${_bold} ${mesg}${_nc}\n" "$@"
}

_errmsg2() {
	(( QUIET )) && return
	local mesg=$1; shift
	printf "${_red}   >>> FATAL:${_bold} ${mesg}${_nc}\n" "$@"
}

_msg2 "Configuring skywire"

#halt any running instance
systemctl disable --now skywire.service
systemctl disable --now skywire-visor.service
#disable old instances / instances not provided by the package
systemctl disable --now skywire-hypervisor.service

#config generation writes in the current dir;
#so we want to make anything spawned by the process appear in a subdirectory of install dir
cd /opt/skywire/  || _errmsg2 "the path /opt/skywire was not found"

#try to reuse existing configuration
if [[ ! -f /opt/skywire/skywire.json ]]; then
  if [[ -f /etc/skywire-config.json ]]; then
    _warnmsg1 "Importing existing skybian configuration from /etc/skywire-config.json"
    cp -b  /etc/skywire-config.json /opt/skywire/skywire.json
  fi
fi
##generate hypervisor configuration##
_msg3 "Generating skywire config with command:"
echo "cd /opt/skywire && skywire-cli visor gen-config --is-hypervisor -p -r -o /opt/skywire/skywire.json"
#again we take precautions by not generating the config file in-place, but moving it there in the next step
if [[ $(skywire-cli visor gen-config --is-hypervisor -p -r -o /opt/skywire/skywire.json) ]]; then
_msg2 "${_blue}Skywire${_nc} configuration updated!"
else
_errmsg2 "Skywire is not installed or installation not detected! Could not generate configuration file!"
echo "this should never happen."
exit 100
fi

#generate tls keys
skywire-tls-gen

if [[ ! -f /opt/skywire/skywire-visor.json ]] ; then #start hypervisor if visor config does not exist
_msg3 "Enabling skywire systemd service:
systemctl enable --now skywire.service"
systemctl enable --now skywire.service
echo
_msg2 "${_blue}Skywire${_nc} has been configured!"
echo
_msg2 "starting now on:
${_red}https://127.0.0.1:8000${_nc}"
_lanip=$(ifconfig | grep inet | head -n 1)
_lanip=${_lanip##*inet }
_lanip=${_lanip%% *}
echo
_msg2 "Access from local network at:
${_yellow}https://${_lanip}:8000${_nc}"
_pubkey=$(cat /opt/skywire/skywire.json | grep pk\")
_pubkey=${_pubkey#*: }
echo
_msg2 "Visor Public Key:
${_green}${_pubkey}${_nc}"
echo
_msg2 "run the following commands to set a remote hypervisor:

  ${_cyan}cd /opt/skywire

  sudo cp skywire.json skywire-visor.json

  sudo skywire-cli visor gen-config --hypervisor-pks ${_yellow}<hypervisor-public-key>${_cyan} -pro skywire-visor.json

  sudo systemctl disable --now skywire.service && sudo systemctl enable --now skywire-visor.service${_nc}"
#hypervisorkey-autoconfig  #regenerate the visor config
else  #config exists
  _msg3 "Enabling skywire-visor systemd service:
  systemctl enable --now skywire-visor.service"
systemctl enable --now skywire-visor.service
echo
_msg2 "${_blue}Skywire${_nc} starting in visor-only mode"
_pubkey=$(cat /opt/skywire/skywire-visor.json | grep pk\")
_pubkey=${_pubkey#*: }
echo
_msg2 "Visor Public Key: ${_green}${_pubkey}${_nc}"
fi
echo
_msg2 "Visit ${_blue}https://whitelist.skycoin.com/${_nc} to register your public key."
_msg2 "View the uptime tracker: ${_blue}http://ut.skywire.skycoin.com/uptimes${_nc}"
_msg2 "join our community on telegram: ${_blue}https://t.me/skywire https://t.me/Skycoin${_nc}"

more will be written in time

Get Started with Skycoin