Subject: Packaging go projects

From: Konstantin Kulikov <[email-masked]>
Date: Wed, 31 Jul 2019 19:59:26 +0000

Hey everyone.

I'm trying to package a go project which uses modules. This is what I
came up with.

https://github.com/alpinelinux/aports/pull/9800

Notes below:
1. fetch() depends on go command which means that abuild checksum will
fail if go is not installed.
2. $SRCDEST will contain "go" directory with module archives using
layout defined by goproxy protocol (see
https://godoc.org/cmd/go#hdr-Module_proxy_protocol). The good thing is
that directory can be served over http and used as real GOPROXY,
avoiding contacting google or other proxies unnecessarily. Current go
projects in aports run "glide install" or "dep ensure" inside
prepare() or build() and do not cache sources at all.
3. GOPROXY should be defined in abuild.conf and default to
https://proxy.golang.org or any other proxy to avoid depending on
git,svn,bzr and others and allow users to use their own proxies
(googles proxy is unavailable in China for example).
4. sha512sums doesn't record hashes of module files, instead they are
recorded in go.sum file and go tool verifies them itself.
5. chmod line in fetch() is unfortunate, without it cleanup step will
fail. Go devs previously refused to add option to make unpacked module
files writable.
6. fetch() will be the same for every go project and can be defined in
abuild and used with options="gomodule" for example, same goes for
GOPATH var which should be set to the same value for all steps.
7. To build a project we create dummy module which I called "apk" (but
can be any name). It allows to record exact version of every used
dependency, selectively upgrade or replace those dependencies and
record that info in binaries (it can be inspected using
rsc.io/goversion or, since go 1.13, "go version").
8. Patching is undoable in a way it's done in alpine (using .patch
files) because checksums are recorded in binaries and can be verified
against google's sumdb. Instead maintainer will need to fork project,
apply patches, tag release and use their fork in APKBUILD.
9. To create new package contibutor would need to create apk.go and
"blank import" all binaries in it, run "go mod init apk && go mod
tidy", then write APKBUILD as usual.
10. To update a package `go get $(go list -f '{{ join .Imports " "
}}')` can be used. If specific version is wanted instead of @latest,
run manually "go get github.com/9seconds/[email-masked]"

Does this look sane to you? Should we package it like this? Any other ideas?