Subject: [bug#30806] Packaging Terraform, a Golang package

From: Chris Marusich <[email-masked]>
Date: Thu, 20 Dec 2018 01:31:48 -0800

Hello Chris and Pierre!

Thank you for your tips regarding Golang and Terraform.  I've built it -
both ad-hoc and using a slightly modified version of Chris' original
package definition.  I'm still getting used to Golang's build system and
our own golang-build-system, so please bear with me!

I was able to run the official Terraform build steps on the latest
Terraform release by issuing the following commands - but I'm not sure
if this actually produced the terraform program:

mkdir terraform
cd terraform/
wget https://github.com/hashicorp/terraform/archive/v0.11.11.tar.gz
tar -xf v0.11.11.tar.gz
mkdir -p src/github.com/hashicorp
cp -r terraform-0.11.11 src/github.com/hashicorp/terraform
guix package -i go make git bash grep findutils which coreutils diffutils -p .guix-profile
mkdir gobin
eval "$(guix package --search-paths=exact --profile=$(realpath --no-symlinks .guix-profile))"
export GOPATH="$(pwd)"
export GOBIN="$GOPATH/bin"
export PATH="$PATH:$GOBIN"
cd src/github.com/hashicorp/terraform/
make tools
make

Those last two commands are the ones listed in Terraform's README.md.
It looks like the final command, "make" will execute the "fmtcheck",
"generate", and "test" recipes in that order.  Here are the relevant
parts of the Makefile:

--8<---------------cut here---------------start------------->8---
default: test

[...]

# test runs the unit tests
# we run this one package at a time here because running the entire suite in
# one command creates memory usage issues when running in Travis-CI.
test: fmtcheck generate
	go list $(TEST) | xargs -t -n4 go test $(TESTARGS) -timeout=2m -parallel=4

[...]

# generate runs `go generate` to build the dynamically generated
# source files.
generate:
	@which stringer > /dev/null; if [ $$? -ne 0 ]; then \
	  go get -u golang.org/x/tools/cmd/stringer; \
	fi
	go generate ./...
	@go fmt command/internal_plugin_list.go > /dev/null

[...]

fmtcheck:
	@sh -c "'$(CURDIR)/scripts/gofmtcheck.sh'"
--8<---------------cut here---------------end--------------->8---

So, in essence this runs "go generate", "go fmt", and "go test".  The
script gofmtcheck.sh seems to be a read-only linter to assist the
Terraform maintainers in finding badly formatted Golang files.

This is slightly different from the installation procedure that our
go-build-system runs.  When you build the attached package (which
packages an older version of terraform for now), our go-build-system
runs steps like the following (in order from top to bottom):

* Phase: unpack: Make a "src/github.com/hashicorp/terraform" directory.
* Phase: setup-environment: set GOPATH to (getcwd) and GOBIN to $out/bin.
* Phase: build: go install -v -x '-ldflags=-s -w' github.com/hashicorp/terraform
* Phase: check: go test github.com/hashicorp/terraform

All in all, this has raised some questions in my mind:

1) Is it bad that our package definition isn't running "go generate" or
"go fmt"?  Do you know if "go install" does this for us somehow?  I
don't think "stringer" or "mockgen" are present in the build
environment, but our "go install" invocation seems to build terraform
even without them.  I wonder if the built terraform is broken in some
ways because we didn't run the code generation/formatting steps.

2) After I ran "make" ad-hoc, I couldn't find a built "terraform"
executable anywhere.  Where is it?  Am missing something obvious, or
could it be that the official documentation incomplete and I need to ask
upstream for advice?

3) The official instructions seem to arbitrarily choose to run the build
in parallel, using 4 threads, which means this package won't play nice
with build arguments like --cores.  I suppose I might need to work with
upstream to fix that.

This feels so close, and yet so far.  Hopefully we only have a little
more to do to get Terraform packaged well!  Thank you again for your
help.

-- 
Chris
From 71d654e2738c6ef870441d4234632bd30e93c74a Mon Sep 17 00:00:00 2001
From: Chris Marusich <[email-masked]>
Date: Thu, 20 Dec 2018 01:24:59 -0800
Subject: [PATCH] gnu: Add terraform.

This patch is slightly modified from Christopher Baines' original patch to
accommodate some changes that have taken place recently in the Guix source
tree.  But it's essentially the same.  It is still probably not suitable for
inclusion in Guix just yet.

* gnu/packages/terraform.scm (terraform): New variable.
---
 gnu/packages/terraform.scm | 40 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/gnu/packages/terraform.scm b/gnu/packages/terraform.scm
index f14b152fd..de2288dda 100644
--- a/gnu/packages/terraform.scm
+++ b/gnu/packages/terraform.scm
@@ -47,3 +47,43 @@ the inputs and outputs for modules of the Terraform infrastructure management
 tool.  These can be shown, or written to a file in JSON or Markdown formats.")
     (home-page "https://github.com/segmentio/terraform-docs")
     (license license:expat)))
+
+(define-public terraform
+  (package
+    (name "terraform")
+    (version "0.11.3")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                    (url "https://github.com/hashicorp/terraform")
+                    (commit (string-append "v" version))))
+              (sha256
+               (base32
+                "0637x7jcm62pdnivmh4rggly6dmlvdh3jpsd1z4vba15gbm203nz"))))
+    (build-system go-build-system)
+    (arguments
+     '(#:import-path "github.com/hashicorp/terraform"
+       #:phases
+       (modify-phases %standard-phases
+         ;; I'm not sure what purpose they serve, but they are readonly, so
+         ;; they break the reset-gzip-timestamps phase.
+         (add-after 'install 'delete-test-fixtures
+           (lambda* (#:key outputs #:allow-other-keys)
+             ;; If delete-file-recursively fails, it won't throw an exception.
+             ;; However, if it doesn't do its job, the build will fail, so
+             ;; we'll know one way or another.
+             (delete-file-recursively
+              (string-append
+               (assoc-ref outputs "out")
+               "/src/github.com/hashicorp/terraform/config/module/test-fixtures"))
+             #t)))))
+    (synopsis "Tool for building and changing computing infrastructure")
+    (description
+     "Terraform uses descriptions of infrastructure written in @acronym{HCL,
+Hashicorp Configuration Language} which describe graphs of resources,
+including information about dependencies. From this, Terraform can plan and
+apply changes to the described resources.
+
+Terraform uses plugins that provide intergrations to different providers.")
+    (home-page "https://www.terraform.io/")
+    (license license:mpl2.0)))
-- 
2.20.0