Skip to content
This repository has been archived by the owner on Nov 1, 2022. It is now read-only.

Commit

Permalink
Break cyclical dependency of generated template fs
Browse files Browse the repository at this point in the history
For `fluxctl install`, we embed a set of templates in the fluxctl
binary by generating a fake filesystem as Go code
(pkg/install/generated_templates.gogen.go).

But the code that generates the fake filesystem also _depends_ on the
fake filesystem, since it does double duty as a program for generating
example manifests from those templates.

This leads to a problem: if anything has upset the generation process,
it's not possible to regenerate the files, since the generation tool
won't build.

A related problem, worked around elsewhere (#2473), is that it's easy
to introduce spurious differences in the generated code -- which,
since it's checked in -- means painful merges.

In general we don't care about the generated Go code, only about what
it produces. This commit removes the generated file from the
"uncommitted change" detection (`make check-generated`); and uses
`fluxctl install` to generate the example files, removing the need for
the code generating program to depend on the code it's generating.

NB It's still necessary to commit the generated code, since other
projects depend on the install package.
  • Loading branch information
squaremo committed Oct 17, 2019
1 parent 64534d4 commit 02644fe
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 87 deletions.
25 changes: 16 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@ BUILD_DATE:=$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')

DOCS_PORT:=8000

GENERATED_TEMPLATES_FILE=pkg/install/generated_templates.gogen.go

all: $(GOBIN)/fluxctl $(GOBIN)/fluxd build/.flux.done

release-bins:
release-bins: $(GENERATED_TEMPLATES_FILE)
for arch in amd64; do \
for os in linux darwin windows; do \
CGO_ENABLED=0 GOOS=$$os GOARCH=$$arch go build -o "build/fluxctl_"$$os"_$$arch" $(LDFLAGS) -ldflags "-X main.version=$(shell ./docker/image-tag)" ./cmd/fluxctl/; \
Expand All @@ -51,7 +53,7 @@ clean:
realclean: clean
rm -rf ./cache

test: test/bin/helm test/bin/kubectl test/bin/kustomize
test: test/bin/helm test/bin/kubectl test/bin/kustomize $(GENERATED_TEMPLATES_FILE)
PATH="${PWD}/bin:${PWD}/test/bin:${PATH}" go test ${TEST_FLAGS} $(shell go list ./... | grep -v "^github.com/fluxcd/flux/vendor" | sort -u)

e2e: test/bin/helm test/bin/kubectl build/.flux.done
Expand Down Expand Up @@ -104,7 +106,7 @@ cache/%/helm-$(HELM_VERSION): docker/helm.version
tar -m -C ./cache -xzf cache/$*/helm-$(HELM_VERSION).tar.gz $*/helm
mv cache/$*/helm $@

$(GOBIN)/fluxctl: $(FLUXCTL_DEPS)
$(GOBIN)/fluxctl: $(FLUXCTL_DEPS) $(GENERATED_TEMPLATES_FILE)
go install ./cmd/fluxctl

$(GOBIN)/fluxd: $(FLUXD_DEPS)
Expand All @@ -113,14 +115,19 @@ $(GOBIN)/fluxd: $(FLUXD_DEPS)
integration-test: all
test/bin/test-flux

generate-deploy: pkg/install/generated_templates.gogen.go
cd deploy && go run ../pkg/install/generate.go deploy
generate-deploy: $(GOBIN)/fluxctl
$(GOBIN)/fluxctl install -o ./deploy \
--git-url git@github.com:fluxcd/flux-get-started \
--git-email flux@example.com \
--git-user 'Flux automation' \
--git-label flux-sync \
--namespace flux

pkg/install/generated_templates.gogen.go: pkg/install/templates/*
cd pkg/install && go run generate.go embedded-templates
$(GENERATED_TEMPLATES_FILE): pkg/install/templates/*.tmpl pkg/install/generate.go
go generate ./pkg/install

check-generated: generate-deploy pkg/install/generated_templates.gogen.go
git diff --exit-code -- integrations/apis integrations/client pkg/install/generated_templates.gogen.go
check-generated: generate-deploy
git diff --exit-code -- deploy/

build-docs:
@cd docs && docker build -t flux-docs .
Expand Down
3 changes: 3 additions & 0 deletions deploy/flux-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ spec:
# Include this if you want to restrict the manifests considered by flux
# to those under the following relative paths in the git repository
# - --git-path=subdir1,subdir2
- --git-label=flux-sync
- --git-user=Flux automation
- --git-email=flux@example.com

# Include these two to enable git commit signing
# - --git-gpg-key-import=/root/gpg-import
Expand Down
80 changes: 8 additions & 72 deletions pkg/install/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,92 +4,28 @@ package main

import (
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"time"

"github.com/shurcooL/vfsgen"

"github.com/fluxcd/flux/pkg/install"
)

func main() {
usage := func() {
fmt.Fprintf(os.Stderr, "usage: %s {embedded-templates,deploy}\n", os.Args[0])
fmt.Fprintf(os.Stderr, "usage: %s\n", os.Args[0])
os.Exit(1)
}
if len(os.Args) != 2 {
if len(os.Args) != 1 {
usage()
}
switch os.Args[1] {
case "embedded-templates":
var fs http.FileSystem = modTimeFS{
fs: http.Dir("templates/"),
}
err := vfsgen.Generate(fs, vfsgen.Options{
Filename: "generated_templates.gogen.go",
PackageName: "install",
VariableName: "templates",
})
if err != nil {
log.Fatalln(err)
}
case "deploy":
params := install.TemplateParameters{
GitURL: "git@github.com:fluxcd/flux-get-started",
GitBranch: "master",
Namespace: "flux",
}
manifests, err := install.FillInTemplates(params)
if err != nil {
fmt.Fprintf(os.Stderr, "error: failed to fill in templates: %s\n", err)
os.Exit(1)
}
for fileName, contents := range manifests {
if err := ioutil.WriteFile(fileName, contents, 0600); err != nil {
fmt.Fprintf(os.Stderr, "error: failed to write deploy file %s: %s\n", fileName, err)
os.Exit(1)
}
}

default:
usage()
}
}

// modTimeFS is a wrapper that rewrites all mod times to Unix epoch.
// This is to ensure `generated_templates.gogen.go` only changes when
// the folder and/or file contents change.
type modTimeFS struct {
fs http.FileSystem
}

func (fs modTimeFS) Open(name string) (http.File, error) {
f, err := fs.fs.Open(name)
err := vfsgen.Generate(http.Dir("templates/"), vfsgen.Options{
Filename: "generated_templates.gogen.go",
PackageName: "install",
VariableName: "templates",
})
if err != nil {
return nil, err
log.Fatalln(err)
}
return modTimeFile{f}, nil
}

type modTimeFile struct {
http.File
}

func (f modTimeFile) Stat() (os.FileInfo, error) {
fi, err := f.File.Stat()
if err != nil {
return nil, err
}
return modTimeFileInfo{fi}, nil
}

type modTimeFileInfo struct {
os.FileInfo
}

func (modTimeFileInfo) ModTime() time.Time {
return time.Unix(0, 0)
}
Loading

0 comments on commit 02644fe

Please sign in to comment.