How I Created My First FreeBSD Port
I created my first FreeBSD port recently. I found that FreeBSD didn't have a port for GoCD, which is a continuous integration and continuous deployment (CI/CD) system. This was a great opportunity to learn how to build a FreeBSD port while also contributing back to the community.
Edit: This post was mentioned in BSD Now episode 294.
Initial Setup
I created a FreeBSD build environment in a Digital Ocean droplet. Installed a few things I needed,
$ sudo pkg update $ sudo pkg install -y bash vim-tiny tmux openjdk8 ruby ruby24-gems rubygem-rake
Since GoCD requires Java and Ruby I had to install those with pkg
.
Otherwise, they will be built with the ports system, which is very slow. Others
are for my convenience.
I highly recommend you create a tmux
session for your work, especially when
the build environment is remote.
$ tmux attach -t gocd || tmux new-session -s gocd $ sudo su # become root to make it easier to work with ports $ bash # Many steps assume you're using bash; modify them as needed
Setup Ports
$ cd /usr/ports $ portsnap fetch && portsnap extract && portsnap update
Tweaks
$ echo DEVELOPER=yes | tee -a /etc/make.conf # https://www.freebsd.org/doc/en/books/porters-handbook/quick-porting.html $ export DISTDIR=/usr/ports/distfiles # https://www.freebsd.org/doc/en/books/porters-handbook/quick-porting.html
Port Init
$ mkdir -p /usr/ports/devel/gocd-server/files $ cd /usr/ports/devel/gocd-server $ touch Makefile pkg-descr pkg-plist files/gocd-server.in
pkg-descr
Edit pkg-descr with the following contents.
GoCD is an open source Continuous Integration (CI) and Continuous Delivery (CD) system sponsored by ThoughtWorks Inc. It is built with Java. WWW: https://www.gocd.org/
Makefile (fetch)
Edit Makefile to have the following contents. This is the first round of edits which will allow us to fetch the source tarball. We'll continue to edit this file later in this post, adding more content as we need it for the related step.
At the time of writing, GoCD was at version 19.2.0-8641.
# $FreeBSD$ PORTNAME=gocd-server DISTVERSION=19.2.0-8641 CATEGORIES=devel java MASTER_SITES=https://download.gocd.org/binaries/${DISTVERSION}/generic/ DISTFILES=go-server-${DISTVERSION}.zip MAINTAINER=me@example.com COMMENT=An open-source Continuous Integration and Continuous Delivery system LICENSE=APACHE20 .include <bsd.port.mk>
This Makefile can fetch the source code.
$ make fetch
distinfo
We are also able to create the distinfo file with the Makefile we have.
$ make makesum
Makefile (extract)
Edit Makefile to be able to extract files from the source distribution.
# $FreeBSD$ PORTNAME=gocd-server DISTVERSION=19.2.0-8641 CATEGORIES=devel java MASTER_SITES=https://download.gocd.org/binaries/${DISTVERSION}/generic/ DISTFILES=go-server-${DISTVERSION}.zip MAINTAINER=me@example.com COMMENT=An open-source Continuous Integration and Continuous Delivery system LICENSE=APACHE20 DISTNAME=go-server-19.2.0 EXTRACT_ONLY=go-server-${DISTVERSION}.zip EXTRACT_CMD=${UNZIP_NATIVE_CMD} ${DISTDIR}/${EXTRACT_ONLY} .include <bsd.port.mk>
This Makefile can extract the source code.
$ make extract
GID and UID
Search /usr/ports/GIDs and /usr/ports/UIDs for matching free GID and UID and use them.
$ grep free /usr/ports/GIDs | head $ grep free /usr/ports/UIDs | head
I used GID 237 since it was free. You will not necessarily use these IDs when you submit your port to the project. But it doesn't matter. For now, all we care about is using available IDs.
Edit /usr/ports/GIDs to claim the GID for group gocd.
$ sed -i.bak 's!# free: 237!gocd:*:237:!g' /usr/ports/GIDs
Edit /usr/ports/UIDs to claim the UID for user gocd.
$ sed -i.bak 's!# free: 237!gocd:*:237:237::0:0:GoCD:/usr/local/gocd-server:/bin/sh!g' /usr/ports/UIDs
pkg-plist
Edit pkg-plist with the following contents,
%%JAVAJARDIR%%/go.jar @dir(%%GOCD_SERVER_USER%%,%%GOCD_SERVER_GROUP%%,) gocd-server
files/gocd-server.in
Edit files/gocd-server.in to create an rc script with the following contents,
Makefile (stage, package, install)
Make final edits to Makefile to be able to stage, package, and install.
# $FreeBSD$ PORTNAME=gocd-server DISTVERSION=19.2.0-8641 CATEGORIES=devel java MASTER_SITES=https://download.gocd.org/binaries/${DISTVERSION}/generic/ DISTFILES=go-server-${DISTVERSION}.zip MAINTAINER=me@example.com COMMENT=An open-source Continuous Integration and Continuous Delivery system LICENSE=APACHE20 DISTNAME=go-server-19.2.0 EXTRACT_ONLY=go-server-${DISTVERSION}.zip EXTRACT_CMD=${UNZIP_NATIVE_CMD} ${DISTDIR}/${EXTRACT_ONLY} NO_BUILD=yes USE_JAVA=yes USE_RUBY=yes JAVA_VERSION=1.8+ NO_ARCH= TMPDIR?=/tmp GOCD_SERVER_HOME?=${PREFIX}/gocd-server GOCD_SERVER_CONFIG_DIR?=${LOCALBASE}/etc/gocd-server GOCD_SERVER_LOG_FILE?=/var/log/gocd-server.log GOCD_SERVER_MEM?=512m GOCD_SERVER_MAX_MEM?=1g GOCD_SERVER_MAX_METASPACE?=400m GOCD_SERVER_PORT?=8153 GOCD_SERVER_SSL_PORT?=8154 GOCD_SERVER_USER_LANG?=en GOCD_SERVER_USER_COUNTRY?=US GOCD_SERVER_USER?=gocd GOCD_SERVER_GROUP?=gocd GOCD_SERVER_LISTEN_HOST?= .if ${GOCD_SERVER_USER} == "gocd" USERS=gocd .endif .if ${GOCD_SERVER_GROUP} == "gocd" GROUPS=gocd .endif SUB_LIST+=GOCD_SERVER_CONFIG_DIR=${GOCD_SERVER_CONFIG_DIR} \ GOCD_SERVER_LOG_FILE=${GOCD_SERVER_LOG_FILE} \ GOCD_SERVER_MEM=${GOCD_SERVER_MEM} \ GOCD_SERVER_MAX_MEM=${GOCD_SERVER_MAX_MEM} \ GOCD_SERVER_MAX_METASPACE=${GOCD_SERVER_MAX_METASPACE} \ GOCD_SERVER_PORT=${GOCD_SERVER_PORT} \ GOCD_SERVER_SSL_PORT=${GOCD_SERVER_SSL_PORT} \ GOCD_SERVER_USER_LANG=${GOCD_SERVER_USER_LANG} \ GOCD_SERVER_USER_COUNTRY=${GOCD_SERVER_USER_COUNTRY} \ GOCD_SERVER_USER=${GOCD_SERVER_USER} \ GOCD_SERVER_GROUP=${GOCD_SERVER_GROUP} \ GOCD_SERVER_LISTEN_HOST=${GOCD_SERVER_LISTEN_HOST} \ JAVA_HOME=${JAVA_HOME} \ JAVAJARDIR=${JAVAJARDIR} \ TMPDIR=${TMPDIR} PLIST_SUB+=GOCD_SERVER_USER=${GOCD_SERVER_USER} \ GOCD_SERVER_GROUP=${GOCD_SERVER_GROUP} \ JAVAJARDIR=${JAVAJARDIR} do-install: ${MKDIR} ${STAGEDIR}${JAVAJARDIR} ${STAGEDIR}${GOCD_SERVER_HOME} ${INSTALL_DATA} ${INSTALL_WRKSRC}/go.jar ${STAGEDIR}${JAVAJARDIR} .include <bsd.port.mk>
Test everything is staging ok with,
$ make stage
Test a package can be created with,
$ make package
Finally, install the port,
$ make install
Source Code
The complete source code is available under MIT license from my gocd-server git repo.
TODO
- Log files are not being created in /var/log/ but instead in /usr/local/gocd-server/logs which needs to be fixed
- Submit this port to the FreeBSD project