src!: revert bump to go 1.16 and template changes (#340)

* Revert "src: rename boson import 'fn'"

This reverts commit c0a6f561c0.

* Revert "src: all test dirs set to 0700"

This reverts commit 99f01220c2.

* Revert "src: better error when custom template not found"

This reverts commit 6673395834.

* Revert "src: better errors when custom runtime not found"

This reverts commit a31a6f67a1.

* Revert "build: create separate target for templates.tgz"

This reverts commit 11164bf8d9.

* Revert "src: use consistent separators for fs.FS instances"

This reverts commit 4db07b412f.

* Revert "src: update go event template dependencies"

This reverts commit 3bfc13380f.

* Revert "src: tarfs assumes forward slashes internally"

This reverts commit 6cc0e67b1c.

* Revert "feat: support windows paths in embedded templates FS"

This reverts commit c2b216857b.

* Revert "feat: positive error when runtimme or template unrecognized"

This reverts commit acc56b0900.

* Revert "fix: lint issues"

This reverts commit 895872aee7.

* Revert "ci: go 1.16 compatiblity updates"

This reverts commit 1e3959c045.

* Revert "feat: preserve file modes using in-memory tar FS"

This reverts commit 7dc772ec62.

* Revert "feat: create templates archive on go generate"

This reverts commit 63b7f11471.

* Revert "ci: remove pkger from ci"

This reverts commit 876b0dd0f7.

* Revert "src: remove pkger dependency and tidy"

This reverts commit f006ab1e32.

* Revert "src: remove packaging artifact"

This reverts commit 4d9d0a7b4e.

* Revert "src: remove pkger from make targets"

This reverts commit e44c1ad74c.

* Revert "src: replace pkger with embed.FS"

This reverts commit 38874a4afd.

* Revert "src: update references to deprecated ioutil"

This reverts commit 4025460f73.

* Revert "src: require go 1.16"

This reverts commit 512d4c2580.

* chore: update pkged.go

Signed-off-by: Lance Ball <lball@redhat.com>
This commit is contained in:
Lance Ball 2021-05-12 14:37:21 -04:00 committed by GitHub
parent c5d31c5691
commit 2b025df199
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 527 additions and 1220 deletions

View File

@ -10,22 +10,38 @@ jobs:
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
- name: Determine download URL for pkger
id: pkger-download-url
uses: actions/github-script@v2
with:
go-version: '^1.16'
result-encoding: string
script: |
return github.repos.getReleaseByTag({
owner: "markbates",
repo: "pkger",
tag: "v0.17.1"
}).then(result => {
return result.data.assets
.filter(a => a.name.includes('Linux_x86'))
.map(a => a.browser_download_url)[0];
})
- name: Install pkger
run: |
curl -s -L -o pkger.tgz ${{ steps.pkger-download-url.outputs.result }}
tar xvzf pkger.tgz
- name: Test
run: make test
env:
PKGER: "./${{ steps.pkger-binaries.outputs.binary }}"
- name: Lint
run: make check
outputs:
pkger: ${{ steps.pkger-download-url.outputs.result }}
build-and-publish:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
go-version: '^1.16'
# Release
# Create a release, or update the release PR
- uses: GoogleCloudPlatform/release-please-action@v2.24.1
id: release
@ -33,6 +49,8 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
release-type: simple
bump-minor-pre-major: true
# Checkout
- uses: actions/checkout@v2
# Tag
# If a release was created, tag `vX.Y.Z` synchronously which:
# 1. Triggers release-please to create draft release, allowing manual
@ -52,23 +70,28 @@ jobs:
git push origin :v${{steps.release.outputs.major}}.${{steps.release.outputs.minor}}.${{steps.release.outputs.patch}} || true
git tag -a v${{steps.release.outputs.major}}.${{steps.release.outputs.minor}}.${{steps.release.outputs.patch}} -m "Release v${{steps.release.outputs.major}}.${{steps.release.outputs.minor}}.${{steps.release.outputs.patch}}"
git push origin v${{steps.release.outputs.major}}.${{steps.release.outputs.minor}}.${{steps.release.outputs.patch}} || true
# Build
- uses: actions/setup-go@v2
- name: Install pkger
run: |
curl -s -L -o pkger.tgz ${{ needs.test.outputs.pkger }}
tar xvzf pkger.tgz
# Standard build tasks
- name: Build
run: make cross-platform
# NOTE:
# release-please adds the version asynchronously. Without using the
# synchonous tagging step above, the version can be explicitly passed
# to the build using the following environment variable. However this
# has the side-effect of causing inter-relese binaries to not include
# verbose version information, because the special version `tip` is
# overriden with a blank string in those cases.
# env:
# VERS: ${{ steps.release.outputs.tag_name }}
env:
PKGER: "./pkger"
# NOTE:
# release-please adds the version asynchronously. Without using the
# synchonous tagging step above, the version can be explicitly passed
# to the build using the following environment variable. However this
# has the side-effect of causing inter-relese binaries to not include
# verbose version information, because the special version `tip` is
# overriden with a blank string in those cases.
# VERS: ${{ steps.release.outputs.tag_name }}
# Upload
# All build artifacts are uploaded whether release or not
# Non-release binaries have a verbose version `tip-[git hash]-[build timestamp]`
# Upload all build artifacts whether it's a release or not
- uses: actions/upload-artifact@v2
with:
name: OSX Binary

View File

@ -12,12 +12,61 @@ jobs:
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
- name: Determine platform binaries
id: pkger-binaries
uses: actions/github-script@v2
with:
go-version: '^1.16'
result-encoding: string
script: |
let platform, binary;
switch ('${{matrix.os}}') {
case 'ubuntu-latest':
platform = 'Linux_x86'
binary = 'pkger'
break
case 'windows-latest':
platform = 'Windows_x86'
binary = 'pkger.exe'
break
case 'macos-latest':
platform = 'Darwin_x86'
binary = 'pkger'
break
}
core.setOutput('platform', platform)
core.setOutput('binary', binary)
- name: Determine download URL for latest pkger
id: pkger-download-url
uses: actions/github-script@v2
with:
result-encoding: string
script: |
let platform = "${{ steps.pkger-binaries.outputs.platform }}"
let binary = "${{ steps.pkger-binaries.outputs.binary }}"
core.info('PLATFORM: ' + platform)
core.info('BINARY: ' + binary)
return github.repos.getReleaseByTag({
owner: "markbates",
repo: "pkger",
tag: "v0.17.1"
}).then(result => {
return result.data.assets
.filter(a => a.name.includes(platform))
.map(a => a.browser_download_url)[0];
})
- name: Install pkger
run: |
curl -s -L -o pkger.tgz ${{ steps.pkger-download-url.outputs.result }}
tar xvzf pkger.tgz
- name: Test
run: make test
env:
PKGER: "./${{ steps.pkger-binaries.outputs.binary }}"
- name: Build
run: make build
env:
PKGER: "./${{ steps.pkger-binaries.outputs.binary }}"
- name: Lint
run: make check
@ -28,8 +77,6 @@ jobs:
uses: actions/checkout@v2
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: '^1.16'
- name: Provision Cluster
uses: lkingland/kind-action@v1 # use ./hack/allocate.sh locally
with:

3
.gitignore vendored
View File

@ -1,6 +1,7 @@
/func
/func_*
/templates.tgz
/templates/go/events/go.sum
/templates/go/http/go.sum
/coverage.out
/bin

View File

@ -1,9 +1,11 @@
REPO := quay.io/boson/func
BIN := func
BIN := func
DARWIN :=$(BIN)_darwin_amd64
LINUX :=$(BIN)_linux_amd64
WINDOWS :=$(BIN)_windows_amd64.exe
PKGER?=pkger
DARWIN=$(BIN)_darwin_amd64
LINUX=$(BIN)_linux_amd64
WINDOWS=$(BIN)_windows_amd64.exe
CODE := $(shell find . -name '*.go')
DATE := $(shell date -u +"%Y%m%dT%H%M%SZ")
@ -14,21 +16,23 @@ VTAG := $(shell git tag --points-at HEAD)
# unless explicitly, synchronously tagging as is done in ci.yaml
VERS ?= $(shell [ -z $(VTAG) ] && echo 'tip' || echo $(VTAG) )
LDFLAGS := -X main.date=$(DATE) -X main.vers=$(VERS) -X main.hash=$(HASH)
TEMPLATE_DIRS=$(shell find templates -type d)
TEMPLATE_FILES=$(shell find templates -type f -name '*')
TEMPLATE_PACKAGE=pkged.go
build: all
all: $(BIN)
all: $(TEMPLATE_PACKAGE) $(BIN)
templates.tgz:
# ensure no cached dependencies are added to the binary
$(TEMPLATE_PACKAGE): templates $(TEMPLATE_DIRS) $(TEMPLATE_FILES)
# ensure no cached dependencies are added to the binary
rm -rf templates/node/events/node_modules
rm -rf templates/node/http/node_modules
rm -rf templates/python/events/__pycache__
rm -rf templates/python/http/__pycache__
# see generate.go for details
go generate
# to install pkger: go get github.com/markbates/pkger/cmd/pkger
$(PKGER)
cross-platform: $(DARWIN) $(LINUX) $(WINDOWS)
cross-platform: $(TEMPLATE_PACKAGE) $(DARWIN) $(LINUX) $(WINDOWS)
darwin: $(DARWIN) ## Build for Darwin (macOS)
@ -36,21 +40,21 @@ linux: $(LINUX) ## Build for Linux
windows: $(WINDOWS) ## Build for Windows
$(BIN): templates.tgz $(CODE) ## Build using environment defaults
env CGO_ENABLED=0 go build -ldflags "$(LDFLAGS)" ./cmd/$(BIN)
$(BIN): $(CODE) ## Build using environment defaults
env CGO_ENABLED=0 go build -ldflags "-X main.date=$(DATE) -X main.vers=$(VERS) -X main.hash=$(HASH)" ./cmd/$(BIN)
$(DARWIN): templates.tgz
env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o $(DARWIN) -ldflags "$(LDFLAGS)" ./cmd/$(BIN)
$(DARWIN):
env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o $(DARWIN) -ldflags "-X main.date=$(DATE) -X main.vers=$(VERS) -X main.hash=$(HASH)" ./cmd/$(BIN)
$(LINUX): templates.tgz
env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o $(LINUX) -ldflags "$(LDFLAGS)" ./cmd/$(BIN)
$(LINUX):
env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o $(LINUX) -ldflags "-X main.date=$(DATE) -X main.vers=$(VERS) -X main.hash=$(HASH)" ./cmd/$(BIN)
$(WINDOWS): templates.tgz
env CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o $(WINDOWS) -ldflags "$(LDFLAGS)" ./cmd/$(BIN)
$(WINDOWS):
env CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o $(WINDOWS) -ldflags "-X main.date=$(DATE) -X main.vers=$(VERS) -X main.hash=$(HASH)" ./cmd/$(BIN)
test: test-binary test-node test-python test-quarkus test-go
test-binary: templates.tgz
test-binary:
go test -race -cover -coverprofile=coverage.out ./...
test-node:
@ -69,7 +73,7 @@ test-go:
cd templates/go/events && go test
cd templates/go/http && go test
test-integration: templates.tgz
test-integration:
go test -tags integration ./...
bin/golangci-lint:
@ -91,5 +95,4 @@ cluster: ## Set up a local cluster for integraiton tests.
clean:
rm -f $(BIN) $(WINDOWS) $(LINUX) $(DARWIN)
rm -f templates.tgz
-rm -f coverage.out

View File

@ -12,7 +12,7 @@ import (
"github.com/buildpacks/pack"
"github.com/buildpacks/pack/logging"
fn "github.com/boson-project/func"
bosonFunc "github.com/boson-project/func"
)
//Builder holds the configuration that will be passed to
@ -37,7 +37,7 @@ var RuntimeToBuildpack = map[string]string{
}
// Build the Function at path.
func (builder *Builder) Build(ctx context.Context, f fn.Function) (err error) {
func (builder *Builder) Build(ctx context.Context, f bosonFunc.Function) (err error) {
// Use the builder found in the Function configuration file
// If one isn't found, use the defaults

View File

@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
@ -339,14 +340,14 @@ func (c *Client) Create(cfg Function) (err error) {
}
// Write out a template.
w := templateWriter{repositories: c.templates, verbose: c.verbose}
w := templateWriter{templates: c.templates, verbose: c.verbose}
if err = w.Write(f.Runtime, f.Trigger, f.Root); err != nil {
return
}
// Check if template specifies a builder image. If so, add to configuration
builderFilePath := filepath.Join(f.Root, ".builders.yaml")
if builderConfig, err := os.ReadFile(builderFilePath); err == nil {
if builderConfig, err := ioutil.ReadFile(builderFilePath); err == nil {
// A .builder file was found. Read the default builder and set in the config file
// TODO: A command line flag could be used to specify non-default builders
builders := make(map[string]string)

View File

@ -6,11 +6,12 @@ import (
"context"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
fn "github.com/boson-project/func"
bosonFunc "github.com/boson-project/func"
"github.com/boson-project/func/mock"
)
@ -31,10 +32,10 @@ func TestNew(t *testing.T) {
defer os.RemoveAll(root)
// New Client
client := fn.New(fn.WithRegistry(TestRegistry))
client := bosonFunc.New(bosonFunc.WithRegistry(TestRegistry))
// New Function using Client
if err := client.New(context.Background(), fn.Function{Root: root}); err != nil {
if err := client.New(context.Background(), bosonFunc.Function{Root: root}); err != nil {
t.Fatal(err)
}
}
@ -42,19 +43,19 @@ func TestNew(t *testing.T) {
// TestTemplateWrites ensures a template is written.
func TestTemplateWrites(t *testing.T) {
root := "testdata/example.com/testCreateWrites"
if err := os.MkdirAll(root, 0700); err != nil {
if err := os.MkdirAll(root, 0744); err != nil {
t.Fatal(err)
}
defer os.RemoveAll(root)
client := fn.New(fn.WithRegistry(TestRegistry))
if err := client.Create(fn.Function{Root: root}); err != nil {
client := bosonFunc.New(bosonFunc.WithRegistry(TestRegistry))
if err := client.Create(bosonFunc.Function{Root: root}); err != nil {
t.Fatal(err)
}
// Assert file was written
if _, err := os.Stat(filepath.Join(root, fn.ConfigFile)); os.IsNotExist(err) {
t.Fatalf("Initialize did not result in '%v' being written to '%v'", fn.ConfigFile, root)
if _, err := os.Stat(filepath.Join(root, bosonFunc.ConfigFile)); os.IsNotExist(err) {
t.Fatalf("Initialize did not result in '%v' being written to '%v'", bosonFunc.ConfigFile, root)
}
}
@ -62,19 +63,19 @@ func TestTemplateWrites(t *testing.T) {
// Function does not reinitialize
func TestExtantAborts(t *testing.T) {
root := "testdata/example.com/testCreateInitializedAborts"
if err := os.MkdirAll(root, 0700); err != nil {
if err := os.MkdirAll(root, 0744); err != nil {
t.Fatal(err)
}
defer os.RemoveAll(root)
// New once
client := fn.New(fn.WithRegistry(TestRegistry))
if err := client.New(context.Background(), fn.Function{Root: root}); err != nil {
client := bosonFunc.New(bosonFunc.WithRegistry(TestRegistry))
if err := client.New(context.Background(), bosonFunc.Function{Root: root}); err != nil {
t.Fatal(err)
}
// New again should fail as already initialized
if err := client.New(context.Background(), fn.Function{Root: root}); err == nil {
if err := client.New(context.Background(), bosonFunc.Function{Root: root}); err == nil {
t.Fatal("error expected initilizing a path already containing an initialized Function")
}
}
@ -83,7 +84,7 @@ func TestExtantAborts(t *testing.T) {
// visible files aborts.
func TestNonemptyDirectoryAborts(t *testing.T) {
root := "testdata/example.com/testCreateNonemptyDirectoryAborts" // contains only a single visible file.
if err := os.MkdirAll(root, 0700); err != nil {
if err := os.MkdirAll(root, 0744); err != nil {
t.Fatal(err)
}
defer os.RemoveAll(root)
@ -94,8 +95,8 @@ func TestNonemptyDirectoryAborts(t *testing.T) {
t.Fatal(err)
}
client := fn.New(fn.WithRegistry(TestRegistry))
if err := client.New(context.Background(), fn.Function{Root: root}); err == nil {
client := bosonFunc.New(bosonFunc.WithRegistry(TestRegistry))
if err := client.New(context.Background(), bosonFunc.Function{Root: root}); err == nil {
t.Fatal("error expected initilizing a Function in a nonempty directory")
}
}
@ -108,19 +109,19 @@ func TestNonemptyDirectoryAborts(t *testing.T) {
func TestHiddenFilesIgnored(t *testing.T) {
// Create a directory for the Function
root := "testdata/example.com/testCreateHiddenFilesIgnored"
if err := os.MkdirAll(root, 0700); err != nil {
if err := os.MkdirAll(root, 0744); err != nil {
t.Fatal(err)
}
defer os.RemoveAll(root)
// Create a hidden file that should be ignored.
hiddenFile := filepath.Join(root, ".envrc")
if err := os.WriteFile(hiddenFile, []byte{}, 0644); err != nil {
if err := ioutil.WriteFile(hiddenFile, []byte{}, 0644); err != nil {
t.Fatal(err)
}
client := fn.New(fn.WithRegistry(TestRegistry))
if err := client.New(context.Background(), fn.Function{Root: root}); err != nil {
client := bosonFunc.New(bosonFunc.WithRegistry(TestRegistry))
if err := client.New(context.Background(), bosonFunc.Function{Root: root}); err != nil {
t.Fatal(err)
}
}
@ -130,25 +131,25 @@ func TestHiddenFilesIgnored(t *testing.T) {
func TestDefaultRuntime(t *testing.T) {
// Create a root for the new Function
root := "testdata/example.com/testCreateDefaultRuntime"
if err := os.MkdirAll(root, 0700); err != nil {
if err := os.MkdirAll(root, 0744); err != nil {
t.Fatal(err)
}
defer os.RemoveAll(root)
// Create a new function at root with all defaults.
client := fn.New(fn.WithRegistry(TestRegistry))
if err := client.New(context.Background(), fn.Function{Root: root}); err != nil {
client := bosonFunc.New(bosonFunc.WithRegistry(TestRegistry))
if err := client.New(context.Background(), bosonFunc.Function{Root: root}); err != nil {
t.Fatal(err)
}
// Load the function
f, err := fn.NewFunction(root)
f, err := bosonFunc.NewFunction(root)
if err != nil {
t.Fatal(err)
}
// Ensure it has defaulted runtime
if f.Runtime != fn.DefaultRuntime {
if f.Runtime != bosonFunc.DefaultRuntime {
t.Fatal("The default runtime was not applied or persisted.")
}
}
@ -172,18 +173,18 @@ func TestDefaultTrigger(t *testing.T) {
func TestExtensibleTemplates(t *testing.T) {
// Create a directory for the new Function
root := "testdata/example.com/testExtensibleTemplates"
if err := os.MkdirAll(root, 0700); err != nil {
if err := os.MkdirAll(root, 0744); err != nil {
t.Fatal(err)
}
defer os.RemoveAll(root)
// Create a new client with a path to the extensible templates
client := fn.New(
fn.WithTemplates("testdata/repositories"),
fn.WithRegistry(TestRegistry))
client := bosonFunc.New(
bosonFunc.WithTemplates("testdata/templates"),
bosonFunc.WithRegistry(TestRegistry))
// Create a Function specifying a template, 'json' that only exists in the extensible set
if err := client.New(context.Background(), fn.Function{Root: root, Trigger: "customProvider/json"}); err != nil {
if err := client.New(context.Background(), bosonFunc.Function{Root: root, Trigger: "boson-experimental/json"}); err != nil {
t.Fatal(err)
}
@ -195,91 +196,21 @@ func TestExtensibleTemplates(t *testing.T) {
}
}
// TestRuntimeNotFound generates an error (embedded default repository).
func TestRuntimeNotFound(t *testing.T) {
// TestUnsupportedRuntime generates an error.
func TestUnsupportedRuntime(t *testing.T) {
// Create a directory for the Function
root := "testdata/example.com/testRuntimeNotFound"
root := "testdata/example.com/testUnsupportedRuntime"
if err := os.MkdirAll(root, 0700); err != nil {
t.Fatal(err)
}
defer os.RemoveAll(root)
client := fn.New(fn.WithRegistry(TestRegistry))
client := bosonFunc.New(bosonFunc.WithRegistry(TestRegistry))
// creating a Function with an unsupported runtime should bubble
// the error generated by the underlying template initializer.
f := fn.Function{Root: root, Runtime: "invalid"}
err := client.New(context.Background(), f)
if !errors.Is(err, fn.ErrRuntimeNotFound) {
t.Fatalf("Expected ErrRuntimeNotFound, got %T", err)
}
}
// TestRuntimeNotFoundCustom ensures that the correct error is returned
// when the requested runtime is not found in a given custom repository
func TestRuntimeNotFoundCustom(t *testing.T) {
root := "testdata/example.com/testRuntimeNotFoundCustom"
if err := os.MkdirAll(root, 0700); err != nil {
t.Fatal(err)
}
defer os.RemoveAll(root)
// Create a new client with path to extensible templates
client := fn.New(
fn.WithTemplates("testdata/repositories"),
fn.WithRegistry(TestRegistry))
// Create a Function specifying a runtime, 'python' that does not exist
// in the custom (testdata) repository but does in the embedded.
f := fn.Function{Root: root, Runtime: "python", Trigger: "customProvider/event"}
// creating should error as runtime not found
err := client.New(context.Background(), f)
if !errors.Is(err, fn.ErrRuntimeNotFound) {
t.Fatalf("Expected ErrRuntimeNotFound, got %v", err)
}
}
// TestTemplateNotFound generates an error (embedded default repository).
func TestTemplateNotFound(t *testing.T) {
root := "testdata/example.com/testTemplateNotFound"
if err := os.MkdirAll(root, 0700); err != nil {
t.Fatal(err)
}
defer os.RemoveAll(root)
client := fn.New(fn.WithRegistry(TestRegistry))
// Creating a function with an invalid template shulid generate the
// appropriate error.
f := fn.Function{Root: root, Runtime: "go", Trigger: "invalid"}
err := client.New(context.Background(), f)
if !errors.Is(err, fn.ErrTemplateNotFound) {
t.Fatalf("Expected ErrTemplateNotFound, got %v", err)
}
}
// TestTemplateNotFoundCustom ensures that the correct error is returned
// when the requested template is not found in the given custom repository.
func TestTemplateNotFoundCustom(t *testing.T) {
root := "testdata/example.com/testTemplateNotFoundCustom"
if err := os.MkdirAll(root, 0700); err != nil {
t.Fatal(err)
}
defer os.RemoveAll(root)
// Create a new client with path to extensible templates
client := fn.New(
fn.WithTemplates("testdata/repositories"),
fn.WithRegistry(TestRegistry))
// An invalid template, but a valid custom provider
f := fn.Function{Root: root, Runtime: "test", Trigger: "customProvider/invalid"}
// Creation should generate the correct error of template not being found.
err := client.New(context.Background(), f)
if !errors.Is(err, fn.ErrTemplateNotFound) {
t.Fatalf("Expected ErrTemplateNotFound, got %v", err)
// create a Function call witn an unsupported runtime should bubble
// the error generated by the underlying initializer.
if err := client.New(context.Background(), bosonFunc.Function{Root: root, Runtime: "invalid"}); err == nil {
t.Fatal("unsupported runtime did not generate error")
}
}
@ -299,13 +230,13 @@ func TestNamed(t *testing.T) {
}
defer os.RemoveAll(root)
client := fn.New(fn.WithRegistry(TestRegistry))
client := bosonFunc.New(bosonFunc.WithRegistry(TestRegistry))
if err := client.New(context.Background(), fn.Function{Root: root, Name: name}); err != nil {
if err := client.New(context.Background(), bosonFunc.Function{Root: root, Name: name}); err != nil {
t.Fatal(err)
}
f, err := fn.NewFunction(root)
f, err := bosonFunc.NewFunction(root)
if err != nil {
t.Fatal(err)
}
@ -333,9 +264,9 @@ func TestRegistryRequired(t *testing.T) {
}
defer os.RemoveAll(root)
client := fn.New()
client := bosonFunc.New()
var err error
if err = client.New(context.Background(), fn.Function{Root: root}); err == nil {
if err = client.New(context.Background(), bosonFunc.Function{Root: root}); err == nil {
t.Fatal("did not receive expected error creating a Function without specifying Registry")
}
fmt.Println(err)
@ -353,13 +284,13 @@ func TestDeriveImage(t *testing.T) {
defer os.RemoveAll(root)
// Create the function which calculates fields such as name and image.
client := fn.New(fn.WithRegistry(TestRegistry))
if err := client.New(context.Background(), fn.Function{Root: root}); err != nil {
client := bosonFunc.New(bosonFunc.WithRegistry(TestRegistry))
if err := client.New(context.Background(), bosonFunc.Function{Root: root}); err != nil {
t.Fatal(err)
}
// Load the function with the now-populated fields.
f, err := fn.NewFunction(root)
f, err := bosonFunc.NewFunction(root)
if err != nil {
t.Fatal(err)
}
@ -385,18 +316,18 @@ func TestDeriveImageDefaultRegistry(t *testing.T) {
// Create the function which calculates fields such as name and image.
// Rather than use TestRegistry, use a single-token name and expect
// the DefaultRegistry to be prepended.
client := fn.New(fn.WithRegistry("alice"))
if err := client.New(context.Background(), fn.Function{Root: root}); err != nil {
client := bosonFunc.New(bosonFunc.WithRegistry("alice"))
if err := client.New(context.Background(), bosonFunc.Function{Root: root}); err != nil {
t.Fatal(err)
}
// Load the function with the now-populated fields.
f, err := fn.NewFunction(root)
f, err := bosonFunc.NewFunction(root)
if err != nil {
t.Fatal(err)
}
// Expected image is [DefaultRegistry]/[namespace]/[servicename]:latest
expected := fn.DefaultRegistry + "/alice/" + f.Name + ":latest"
expected := bosonFunc.DefaultRegistry + "/alice/" + f.Name + ":latest"
if f.Image != expected {
t.Fatalf("expected image '%v' got '%v'", expected, f.Image)
}
@ -422,11 +353,11 @@ func TestNewDelegates(t *testing.T) {
defer os.RemoveAll(root)
// Create a client with mocks for each of the subcomponents.
client := fn.New(
fn.WithRegistry(TestRegistry),
fn.WithBuilder(builder), // builds an image
fn.WithPusher(pusher), // pushes images to a registry
fn.WithDeployer(deployer), // deploys images as a running service
client := bosonFunc.New(
bosonFunc.WithRegistry(TestRegistry),
bosonFunc.WithBuilder(builder), // builds an image
bosonFunc.WithPusher(pusher), // pushes images to a registry
bosonFunc.WithDeployer(deployer), // deploys images as a running service
)
// Register Function delegates on the mocks which validate assertions
@ -434,7 +365,7 @@ func TestNewDelegates(t *testing.T) {
// The builder should be invoked with a path to a Function project's source
// An example image name is returned.
builder.BuildFn = func(f fn.Function) error {
builder.BuildFn = func(f bosonFunc.Function) error {
expectedPath, err := filepath.Abs(root)
if err != nil {
t.Fatal(err)
@ -445,14 +376,14 @@ func TestNewDelegates(t *testing.T) {
return nil
}
pusher.PushFn = func(f fn.Function) (string, error) {
pusher.PushFn = func(f bosonFunc.Function) (string, error) {
if f.Image != expectedImage {
t.Fatalf("pusher expected image '%v', got '%v'", expectedImage, f.Image)
}
return "", nil
}
deployer.DeployFn = func(f fn.Function) error {
deployer.DeployFn = func(f bosonFunc.Function) error {
if f.Name != expectedName {
t.Fatalf("deployer expected name '%v', got '%v'", expectedName, f.Name)
}
@ -467,7 +398,7 @@ func TestNewDelegates(t *testing.T) {
// Invoke the creation, triggering the Function delegates, and
// perform follow-up assertions that the Functions were indeed invoked.
if err := client.New(context.Background(), fn.Function{Root: root}); err != nil {
if err := client.New(context.Background(), bosonFunc.Function{Root: root}); err != nil {
t.Fatal(err)
}
@ -494,8 +425,8 @@ func TestRun(t *testing.T) {
// Create a client with the mock runner and the new test Function
runner := mock.NewRunner()
client := fn.New(fn.WithRegistry(TestRegistry), fn.WithRunner(runner))
if err := client.New(context.Background(), fn.Function{Root: root}); err != nil {
client := bosonFunc.New(bosonFunc.WithRegistry(TestRegistry), bosonFunc.WithRunner(runner))
if err := client.New(context.Background(), bosonFunc.Function{Root: root}); err != nil {
t.Fatal(err)
}
@ -536,19 +467,19 @@ func TestUpdate(t *testing.T) {
defer os.RemoveAll(root)
// A client with mocks whose implementaton will validate input.
client := fn.New(
fn.WithRegistry(TestRegistry),
fn.WithBuilder(builder),
fn.WithPusher(pusher),
fn.WithDeployer(deployer))
client := bosonFunc.New(
bosonFunc.WithRegistry(TestRegistry),
bosonFunc.WithBuilder(builder),
bosonFunc.WithPusher(pusher),
bosonFunc.WithDeployer(deployer))
// create the new Function which will be updated
if err := client.New(context.Background(), fn.Function{Root: root}); err != nil {
if err := client.New(context.Background(), bosonFunc.Function{Root: root}); err != nil {
t.Fatal(err)
}
// Builder whose implementation verifies the expected root
builder.BuildFn = func(f fn.Function) error {
builder.BuildFn = func(f bosonFunc.Function) error {
rootPath, err := filepath.Abs(root)
if err != nil {
t.Fatal(err)
@ -560,7 +491,7 @@ func TestUpdate(t *testing.T) {
}
// Pusher whose implementaiton verifies the expected image
pusher.PushFn = func(f fn.Function) (string, error) {
pusher.PushFn = func(f bosonFunc.Function) (string, error) {
if f.Image != expectedImage {
t.Fatalf("pusher expected image '%v', got '%v'", expectedImage, f.Image)
}
@ -569,7 +500,7 @@ func TestUpdate(t *testing.T) {
}
// Update whose implementaiton verifed the expected name and image
deployer.DeployFn = func(f fn.Function) error {
deployer.DeployFn = func(f bosonFunc.Function) error {
if f.Name != expectedName {
t.Fatalf("updater expected name '%v', got '%v'", expectedName, f.Name)
}
@ -610,11 +541,11 @@ func TestRemoveByPath(t *testing.T) {
}
defer os.RemoveAll(root)
client := fn.New(
fn.WithRegistry(TestRegistry),
fn.WithRemover(remover))
client := bosonFunc.New(
bosonFunc.WithRegistry(TestRegistry),
bosonFunc.WithRemover(remover))
if err := client.New(context.Background(), fn.Function{Root: root}); err != nil {
if err := client.New(context.Background(), bosonFunc.Function{Root: root}); err != nil {
t.Fatal(err)
}
@ -625,7 +556,7 @@ func TestRemoveByPath(t *testing.T) {
return nil
}
if err := client.Remove(context.Background(), fn.Function{Root: root}); err != nil {
if err := client.Remove(context.Background(), bosonFunc.Function{Root: root}); err != nil {
t.Fatal(err)
}
@ -649,11 +580,11 @@ func TestRemoveByName(t *testing.T) {
}
defer os.RemoveAll(root)
client := fn.New(
fn.WithRegistry(TestRegistry),
fn.WithRemover(remover))
client := bosonFunc.New(
bosonFunc.WithRegistry(TestRegistry),
bosonFunc.WithRemover(remover))
if err := client.Create(fn.Function{Root: root}); err != nil {
if err := client.Create(bosonFunc.Function{Root: root}); err != nil {
t.Fatal(err)
}
@ -665,12 +596,12 @@ func TestRemoveByName(t *testing.T) {
}
// Run remove with only a name
if err := client.Remove(context.Background(), fn.Function{Name: expectedName}); err != nil {
if err := client.Remove(context.Background(), bosonFunc.Function{Name: expectedName}); err != nil {
t.Fatal(err)
}
// Run remove with a name and a root, which should be ignored in favor of the name.
if err := client.Remove(context.Background(), fn.Function{Name: expectedName, Root: root}); err != nil {
if err := client.Remove(context.Background(), bosonFunc.Function{Name: expectedName, Root: root}); err != nil {
t.Fatal(err)
}
@ -700,12 +631,12 @@ func TestRemoveUninitializedFails(t *testing.T) {
}
// Instantiate the client with the failing remover.
client := fn.New(
fn.WithRegistry(TestRegistry),
fn.WithRemover(remover))
client := bosonFunc.New(
bosonFunc.WithRegistry(TestRegistry),
bosonFunc.WithRemover(remover))
// Attempt to remove by path (uninitialized), expecting an error.
if err := client.Remove(context.Background(), fn.Function{Root: root}); err == nil {
if err := client.Remove(context.Background(), bosonFunc.Function{Root: root}); err == nil {
t.Fatalf("did not received expeced error removing an uninitialized func")
}
}
@ -714,7 +645,7 @@ func TestRemoveUninitializedFails(t *testing.T) {
func TestList(t *testing.T) {
lister := mock.NewLister()
client := fn.New(fn.WithLister(lister)) // lists deployed Functions.
client := bosonFunc.New(bosonFunc.WithLister(lister)) // lists deployed Functions.
if _, err := client.List(context.Background()); err != nil {
t.Fatal(err)
@ -733,7 +664,7 @@ func TestListOutsideRoot(t *testing.T) {
lister := mock.NewLister()
// Instantiate in the current working directory, with no name.
client := fn.New(fn.WithLister(lister))
client := bosonFunc.New(bosonFunc.WithLister(lister))
if _, err := client.List(context.Background()); err != nil {
t.Fatal(err)
@ -755,10 +686,10 @@ func TestDeployUnbuilt(t *testing.T) {
defer os.RemoveAll(root)
// New Client
client := fn.New(fn.WithRegistry(TestRegistry))
client := bosonFunc.New(bosonFunc.WithRegistry(TestRegistry))
// Initialize (half-create) a new Function at root
if err := client.Create(fn.Function{Root: root}); err != nil {
if err := client.Create(bosonFunc.Function{Root: root}); err != nil {
t.Fatal(err)
}
@ -768,7 +699,7 @@ func TestDeployUnbuilt(t *testing.T) {
t.Fatal("did not receive an error attempting to deploy an unbuilt Function")
}
if !errors.Is(err, fn.ErrNotBuilt) {
if !errors.Is(err, bosonFunc.ErrNotBuilt) {
t.Fatalf("did not receive expected error type. Expected ErrNotBuilt, got %T", err)
}
}

View File

@ -6,7 +6,7 @@ import (
"github.com/ory/viper"
"github.com/spf13/cobra"
fn "github.com/boson-project/func"
bosonFunc "github.com/boson-project/func"
"github.com/boson-project/func/buildpacks"
"github.com/boson-project/func/progress"
"github.com/boson-project/func/prompt"
@ -106,11 +106,11 @@ func runBuild(cmd *cobra.Command, _ []string) (err error) {
listener.Done()
}()
client := fn.New(
fn.WithVerbose(config.Verbose),
fn.WithRegistry(config.Registry), // for deriving image name when --image not provided explicitly.
fn.WithBuilder(builder),
fn.WithProgressListener(listener))
client := bosonFunc.New(
bosonFunc.WithVerbose(config.Verbose),
bosonFunc.WithRegistry(config.Registry), // for deriving image name when --image not provided explicitly.
bosonFunc.WithBuilder(builder),
bosonFunc.WithProgressListener(listener))
return client.Build(context, config.Path)
}

View File

@ -8,7 +8,7 @@ import (
"github.com/spf13/cobra"
fn "github.com/boson-project/func"
bosonFunc "github.com/boson-project/func"
"github.com/boson-project/func/buildpacks"
"github.com/boson-project/func/knative"
)
@ -79,7 +79,7 @@ func CompleteBuilderList(cmd *cobra.Command, args []string, complete string) (st
var (
err error
path string
f fn.Function
f bosonFunc.Function
)
path, err = cmd.Flags().GetString("path")
@ -87,7 +87,7 @@ func CompleteBuilderList(cmd *cobra.Command, args []string, complete string) (st
return
}
f, err = fn.NewFunction(path)
f, err = bosonFunc.NewFunction(path)
if err != nil {
return
}

View File

@ -7,7 +7,7 @@ import (
"github.com/ory/viper"
"github.com/spf13/cobra"
fn "github.com/boson-project/func"
bosonFunc "github.com/boson-project/func"
"github.com/boson-project/func/prompt"
"github.com/boson-project/func/utils"
)
@ -15,9 +15,9 @@ import (
func init() {
root.AddCommand(createCmd)
createCmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all configuration options (Env: $FUNC_CONFIRM)")
createCmd.Flags().StringP("runtime", "l", fn.DefaultRuntime, "Function runtime language/framework. Available runtimes: "+utils.RuntimeList()+" (Env: $FUNC_RUNTIME)")
createCmd.Flags().StringP("runtime", "l", bosonFunc.DefaultRuntime, "Function runtime language/framework. Available runtimes: "+utils.RuntimeList()+" (Env: $FUNC_RUNTIME)")
createCmd.Flags().StringP("templates", "", filepath.Join(configPath(), "templates"), "Path to additional templates (Env: $FUNC_TEMPLATES)")
createCmd.Flags().StringP("trigger", "t", fn.DefaultTrigger, "Function trigger. Available triggers: 'http' and 'events' (Env: $FUNC_TRIGGER)")
createCmd.Flags().StringP("trigger", "t", bosonFunc.DefaultTrigger, "Function trigger. Available triggers: 'http' and 'events' (Env: $FUNC_TRIGGER)")
if err := createCmd.RegisterFlagCompletionFunc("runtime", CompleteRuntimeList); err != nil {
fmt.Println("internal: error while calling RegisterFlagCompletionFunc: ", err)
@ -60,16 +60,16 @@ func runCreate(cmd *cobra.Command, args []string) error {
config = config.Prompt()
function := fn.Function{
function := bosonFunc.Function{
Name: config.Name,
Root: config.Path,
Runtime: config.Runtime,
Trigger: config.Trigger,
}
client := fn.New(
fn.WithTemplates(config.Templates),
fn.WithVerbose(config.Verbose))
client := bosonFunc.New(
bosonFunc.WithTemplates(config.Templates),
bosonFunc.WithVerbose(config.Verbose))
return client.Create(function)
}

View File

@ -2,6 +2,7 @@ package cmd
import (
"fmt"
"github.com/ory/viper"
"github.com/spf13/cobra"

View File

@ -14,7 +14,7 @@ import (
"github.com/spf13/cobra"
"golang.org/x/term"
fn "github.com/boson-project/func"
bosonFunc "github.com/boson-project/func"
"github.com/boson-project/func/buildpacks"
"github.com/boson-project/func/docker"
"github.com/boson-project/func/knative"
@ -132,13 +132,13 @@ func runDeploy(cmd *cobra.Command, _ []string) (err error) {
listener.Done()
}()
client := fn.New(
fn.WithVerbose(config.Verbose),
fn.WithRegistry(config.Registry), // for deriving image name when --image not provided explicitly.
fn.WithBuilder(builder),
fn.WithPusher(pusher),
fn.WithDeployer(deployer),
fn.WithProgressListener(listener))
client := bosonFunc.New(
bosonFunc.WithVerbose(config.Verbose),
bosonFunc.WithRegistry(config.Registry), // for deriving image name when --image not provided explicitly.
bosonFunc.WithBuilder(builder),
bosonFunc.WithPusher(pusher),
bosonFunc.WithDeployer(deployer),
bosonFunc.WithProgressListener(listener))
if config.Build {
if err := client.Build(context, config.Path); err != nil {

View File

@ -11,7 +11,7 @@ import (
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
fn "github.com/boson-project/func"
bosonFunc "github.com/boson-project/func"
"github.com/boson-project/func/knative"
)
@ -51,7 +51,7 @@ kn func describe --output yaml --path myotherfunc
func runDescribe(cmd *cobra.Command, args []string) (err error) {
config := newDescribeConfig(args)
function, err := fn.NewFunction(config.Path)
function, err := bosonFunc.NewFunction(config.Path)
if err != nil {
return
}
@ -67,9 +67,9 @@ func runDescribe(cmd *cobra.Command, args []string) (err error) {
}
describer.Verbose = config.Verbose
client := fn.New(
fn.WithVerbose(config.Verbose),
fn.WithDescriber(describer))
client := bosonFunc.New(
bosonFunc.WithVerbose(config.Verbose),
bosonFunc.WithDescriber(describer))
d, err := client.Describe(config.Name, config.Path)
if err != nil {
@ -109,7 +109,7 @@ func newDescribeConfig(args []string) describeConfig {
// Output Formatting (serializers)
// -------------------------------
type description fn.Description
type description bosonFunc.Description
func (d description) Human(w io.Writer) error {
fmt.Fprintln(w, "Function name:")

View File

@ -12,7 +12,7 @@ import (
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
fn "github.com/boson-project/func"
bosonFunc "github.com/boson-project/func"
"github.com/boson-project/func/knative"
)
@ -66,9 +66,9 @@ func runList(cmd *cobra.Command, args []string) (err error) {
lister.Namespace = ""
}
client := fn.New(
fn.WithVerbose(config.Verbose),
fn.WithLister(lister))
client := bosonFunc.New(
bosonFunc.WithVerbose(config.Verbose),
bosonFunc.WithLister(lister))
items, err := client.List(cmd.Context())
if err != nil {
@ -105,7 +105,7 @@ func newListConfig() listConfig {
// Output Formatting (serializers)
// -------------------------------
type listItems []fn.ListItem
type listItems []bosonFunc.ListItem
func (items listItems) Human(w io.Writer) error {
return items.Plain(w)

View File

@ -11,7 +11,7 @@ import (
"github.com/ory/viper"
"github.com/spf13/cobra"
fn "github.com/boson-project/func"
bosonFunc "github.com/boson-project/func"
)
// The root of the command tree defines the command name, descriotion, globally
@ -150,8 +150,8 @@ type functionOverrides struct {
// Function project at root, if provided, and returns the Function
// configuration values.
// Please note that When this function is called, the overrides are not persisted.
func functionWithOverrides(root string, overrides functionOverrides) (f fn.Function, err error) {
f, err = fn.NewFunction(root)
func functionWithOverrides(root string, overrides functionOverrides) (f bosonFunc.Function, err error) {
f, err = bosonFunc.NewFunction(root)
if err != nil {
return
}
@ -184,7 +184,7 @@ func deriveName(explicitName string, path string) string {
}
// If the directory at path contains an initialized Function, use the name therein
f, err := fn.NewFunction(path)
f, err := bosonFunc.NewFunction(path)
if err == nil && f.Name != "" {
return f.Name
}
@ -240,14 +240,14 @@ func deriveImage(explicitImage, defaultRegistry, path string) string {
if explicitImage != "" {
return explicitImage // use the explicit value provided.
}
f, err := fn.NewFunction(path)
f, err := bosonFunc.NewFunction(path)
if err != nil {
return "" // unable to derive due to load error (uninitialized?)
}
if f.Image != "" {
return f.Image // use value previously provided or derived.
}
derivedValue, _ := fn.DerivedImage(path, defaultRegistry)
derivedValue, _ := bosonFunc.DerivedImage(path, defaultRegistry)
return derivedValue // Use the func system's derivation logic.
}

View File

@ -6,7 +6,7 @@ import (
"github.com/ory/viper"
"github.com/spf13/cobra"
fn "github.com/boson-project/func"
bosonFunc "github.com/boson-project/func"
"github.com/boson-project/func/docker"
)
@ -40,7 +40,7 @@ kn func run
func runRun(cmd *cobra.Command, args []string) (err error) {
config := newRunConfig(cmd)
function, err := fn.NewFunction(config.Path)
function, err := bosonFunc.NewFunction(config.Path)
if err != nil {
return
}
@ -60,9 +60,9 @@ func runRun(cmd *cobra.Command, args []string) (err error) {
runner := docker.NewRunner()
runner.Verbose = config.Verbose
client := fn.New(
fn.WithRunner(runner),
fn.WithVerbose(config.Verbose))
client := bosonFunc.New(
bosonFunc.WithRunner(runner),
bosonFunc.WithVerbose(config.Verbose))
err = client.Run(cmd.Context(), config.Path)
return

View File

@ -1,6 +1,7 @@
package function
import (
"io/ioutil"
"os"
"path/filepath"
@ -40,7 +41,7 @@ func newConfig(root string) (c config, err error) {
}
return
}
bb, err := os.ReadFile(filename)
bb, err := ioutil.ReadFile(filename)
if err != nil {
return
}
@ -89,5 +90,5 @@ func writeConfig(f Function) (err error) {
if bb, err = yaml.Marshal(&c); err != nil {
return
}
return os.WriteFile(path, bb, 0644)
return ioutil.WriteFile(path, bb, 0644)
}

View File

@ -15,7 +15,7 @@ import (
"github.com/docker/docker/client"
"github.com/pkg/errors"
fn "github.com/boson-project/func"
bosonFunc "github.com/boson-project/func"
)
type Opt func(*Pusher) error
@ -30,7 +30,7 @@ type CredentialsProvider func(ctx context.Context, registry string) (Credentials
// Pusher of images from local to remote registry.
type Pusher struct {
// Verbose logging.
Verbose bool
Verbose bool
credentialsProvider CredentialsProvider
}
@ -48,7 +48,7 @@ func EmptyCredentialsProvider(ctx context.Context, registry string) (Credentials
// NewPusher creates an instance of a docker-based image pusher.
func NewPusher(opts ...Opt) (*Pusher, error) {
result := &Pusher{
Verbose: false,
Verbose: false,
credentialsProvider: EmptyCredentialsProvider,
}
for _, opt := range opts {
@ -61,7 +61,7 @@ func NewPusher(opts ...Opt) (*Pusher, error) {
}
// Push the image of the Function.
func (n *Pusher) Push(ctx context.Context, f fn.Function) (digest string, err error) {
func (n *Pusher) Push(ctx context.Context, f bosonFunc.Function) (digest string, err error) {
if f.Image == "" {
return "", errors.New("Function has no associated image. Has it been built?")
@ -71,7 +71,7 @@ func (n *Pusher) Push(ctx context.Context, f fn.Function) (digest string, err er
parts := strings.Split(f.Image, "/")
switch len(parts) {
case 2:
registry = fn.DefaultRegistry
registry = bosonFunc.DefaultRegistry
case 3:
registry = parts[0]
default:

View File

@ -15,7 +15,7 @@ import (
"github.com/docker/docker/client"
fn "github.com/boson-project/func"
bosonFunc "github.com/boson-project/func"
)
// Runner of functions using the docker command.
@ -30,7 +30,7 @@ func NewRunner() *Runner {
}
// Run the function at path
func (n *Runner) Run(ctx context.Context, f fn.Function) error {
func (n *Runner) Run(ctx context.Context, f bosonFunc.Function) error {
ctx, cancel := context.WithCancel(ctx)
defer cancel()

View File

@ -9,7 +9,7 @@ import (
"os"
"testing"
fn "github.com/boson-project/func"
bosonFunc "github.com/boson-project/func"
"github.com/boson-project/func/docker"
)
@ -27,7 +27,7 @@ func TestDockerRun(t *testing.T) {
t.Skip()
}
f, err := fn.NewFunction("testdata/example.com/runnable")
f, err := bosonFunc.NewFunction("testdata/example.com/runnable")
if err != nil {
t.Fatal(err)
}

View File

@ -9,7 +9,7 @@ To create a Client which uses the included buildpacks-based function builder, pu
package main
import (
fn "github.com/boson-project/func"
bosonFunc "github.com/boson-project/func"
"github.com/boson-project/func/buildpacks"
"github.com/boson-project/func/docker"
"github.com/boson-project/func/knative"
@ -28,16 +28,16 @@ func main() {
// A client which uses embedded function templates,
// Quay.io/alice for interstitial build artifacts.
// Docker to build and push, and a Knative client for deployment.
client := fn.New(
fn.WithBuilder(buildpacks.NewBuilder()),
fn.WithPusher(pusher),
fn.WithDeployer(deployer),
fn.WithRegistry("quay.io/alice"))
client := bosonFunc.New(
bosonFunc.WithBuilder(buildpacks.NewBuilder()),
bosonFunc.WithPusher(pusher),
bosonFunc.WithDeployer(deployer),
bosonFunc.WithRegistry("quay.io/alice"))
// Create a Go function which listens for CloudEvents.
// Publicly routable as https://www.example.com.
// Local implementation is written to the current working directory.
funcTest := fn.Function{
funcTest := bosonFunc.Function{
Runtime: "go",
Trigger: "events",
Name: "my-function",

View File

@ -3,6 +3,7 @@ package function
import (
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
@ -222,7 +223,7 @@ var contentiousFiles = []string{
// contentiousFilesIn the given directoy
func contentiousFilesIn(dir string) (contentious []string, err error) {
files, err := os.ReadDir(dir)
files, err := ioutil.ReadDir(dir)
for _, file := range files {
for _, name := range contentiousFiles {
if file.Name() == name {
@ -236,7 +237,7 @@ func contentiousFilesIn(dir string) (contentious []string, err error) {
// effectivelyEmpty directories are those which have no visible files
func isEffectivelyEmpty(dir string) (bool, error) {
// Check for any non-hidden files
files, err := os.ReadDir(dir)
files, err := ioutil.ReadDir(dir)
if err != nil {
return false, err
}

View File

@ -1,77 +0,0 @@
// +build generate
package main
import (
"archive/tar"
"compress/gzip"
"fmt"
"io"
"io/fs"
"os"
"path/filepath"
)
const (
archive = "templates.tgz"
files = "templates"
)
// on 'go generate' create templates archive (tar -czf templates.tgz templates)
func main() {
if err := create(archive, files); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func create(name, source string) (err error) {
// Create file on disk
tarball, err := os.Create(name)
if err != nil {
return
}
defer tarball.Close()
// A gzip compressor which writes to the file
compressor := gzip.NewWriter(tarball)
defer compressor.Close()
// A tar writer which writes to gzip compressor
w := tar.NewWriter(compressor)
defer w.Close()
// File walking function which writes tar entries for each file.
return filepath.WalkDir(source, func(path string, d fs.DirEntry, e error) (err error) {
if e != nil {
return e // abort on any failed ReadDir calls.
}
// Header
fi, err := d.Info()
if err != nil {
return
}
h, err := tar.FileInfoHeader(fi, d.Name())
if err != nil {
return
}
h.Name = filepath.ToSlash(path)
if err = w.WriteHeader(h); err != nil {
return
}
// Done if directory
if d.IsDir() {
return
}
// Data
data, err := os.Open(path)
if err != nil {
return
}
_, err = io.Copy(w, data)
return
})
}

3
go.mod
View File

@ -1,12 +1,13 @@
module github.com/boson-project/func
go 1.16
go 1.14
require (
github.com/buildpacks/pack v0.18.0
github.com/containers/image/v5 v5.10.5
github.com/docker/docker v20.10.2+incompatible
github.com/docker/go-connections v0.4.0
github.com/markbates/pkger v0.17.1
github.com/mitchellh/go-homedir v1.1.0
github.com/ory/viper v1.7.4
github.com/pkg/errors v0.9.1

6
go.sum
View File

@ -302,6 +302,7 @@ github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLi
github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
@ -377,6 +378,8 @@ github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobuffalo/flect v0.2.2/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc=
github.com/gobuffalo/here v0.6.0 h1:hYrd0a6gDmWxBM4TnrGw8mQg24iSVoIkHEk7FodQcBI=
github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@ -625,6 +628,8 @@ github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7
github.com/mailru/easyjson v0.7.1-0.20191009090205-6c0755d89d1e h1:jcoUdG1TzY/M/eM5BLFLP8DJeMximx5NQYSlLL9YeWc=
github.com/mailru/easyjson v0.7.1-0.20191009090205-6c0755d89d1e/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/manifoldco/promptui v0.8.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ=
github.com/markbates/pkger v0.17.1 h1:/MKEtWqtc0mZvu9OinB9UzVN9iYCwLWuyUv4Bw+PCno=
github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@ -1465,6 +1470,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=

View File

@ -5,7 +5,7 @@ import (
v1 "knative.dev/client/pkg/serving/v1"
"knative.dev/eventing/pkg/apis/eventing/v1beta1"
fn "github.com/boson-project/func"
bosonFunc "github.com/boson-project/func"
)
type Describer struct {
@ -28,7 +28,7 @@ func NewDescriber(namespaceOverride string) (describer *Describer, err error) {
// restricts to label-syntax, which is thus escaped. Therefore as a knative (kube) implementation
// detal proper full names have to be escaped on the way in and unescaped on the way out. ex:
// www.example-site.com -> www-example--site-com
func (d *Describer) Describe(name string) (description fn.Description, err error) {
func (d *Describer) Describe(name string) (description bosonFunc.Description, err error) {
servingClient, err := NewServingClient(d.namespace)
if err != nil {
@ -68,11 +68,11 @@ func (d *Describer) Describe(name string) (description fn.Description, err error
}
subscriptions := make([]fn.Subscription, 0, len(triggers.Items))
subscriptions := make([]bosonFunc.Subscription, 0, len(triggers.Items))
for _, trigger := range triggers.Items {
if triggerMatches(&trigger) {
filterAttrs := trigger.Spec.Filter.Attributes
subscription := fn.Subscription{
subscription := bosonFunc.Subscription{
Source: filterAttrs["source"],
Type: filterAttrs["type"],
Broker: trigger.Spec.Broker,

View File

@ -6,7 +6,7 @@ import (
clientservingv1 "knative.dev/client/pkg/serving/v1"
"knative.dev/pkg/apis"
fn "github.com/boson-project/func"
bosonFunc "github.com/boson-project/func"
)
const (
@ -31,7 +31,7 @@ func NewLister(namespaceOverride string) (l *Lister, err error) {
return
}
func (l *Lister) List(context.Context) (items []fn.ListItem, err error) {
func (l *Lister) List(context.Context) (items []bosonFunc.ListItem, err error) {
client, err := NewServingClient(l.Namespace)
if err != nil {
@ -54,7 +54,7 @@ func (l *Lister) List(context.Context) (items []fn.ListItem, err error) {
}
}
listItem := fn.ListItem{
listItem := bosonFunc.ListItem{
Name: service.Name,
Namespace: service.Namespace,
Runtime: service.Labels["boson.dev/runtime"],

View File

@ -2,21 +2,21 @@ package mock
import (
"context"
fn "github.com/boson-project/func"
bosonFunc "github.com/boson-project/func"
)
type Builder struct {
BuildInvoked bool
BuildFn func(fn.Function) error
BuildFn func(bosonFunc.Function) error
}
func NewBuilder() *Builder {
return &Builder{
BuildFn: func(fn.Function) error { return nil },
BuildFn: func(bosonFunc.Function) error { return nil },
}
}
func (i *Builder) Build(ctx context.Context, f fn.Function) error {
func (i *Builder) Build(ctx context.Context, f bosonFunc.Function) error {
i.BuildInvoked = true
return i.BuildFn(f)
}

View File

@ -3,21 +3,21 @@ package mock
import (
"context"
fn "github.com/boson-project/func"
bosonFunc "github.com/boson-project/func"
)
type Deployer struct {
DeployInvoked bool
DeployFn func(fn.Function) error
DeployFn func(bosonFunc.Function) error
}
func NewDeployer() *Deployer {
return &Deployer{
DeployFn: func(fn.Function) error { return nil },
DeployFn: func(bosonFunc.Function) error { return nil },
}
}
func (i *Deployer) Deploy(ctx context.Context, f fn.Function) (fn.DeploymentResult, error) {
func (i *Deployer) Deploy(ctx context.Context, f bosonFunc.Function) (bosonFunc.DeploymentResult, error) {
i.DeployInvoked = true
return fn.DeploymentResult{}, i.DeployFn(f)
return bosonFunc.DeploymentResult{}, i.DeployFn(f)
}

View File

@ -2,21 +2,21 @@ package mock
import (
"context"
fn "github.com/boson-project/func"
bosonFunc "github.com/boson-project/func"
)
type Lister struct {
ListInvoked bool
ListFn func() ([]fn.ListItem, error)
ListFn func() ([]bosonFunc.ListItem, error)
}
func NewLister() *Lister {
return &Lister{
ListFn: func() ([]fn.ListItem, error) { return []fn.ListItem{}, nil },
ListFn: func() ([]bosonFunc.ListItem, error) { return []bosonFunc.ListItem{}, nil },
}
}
func (l *Lister) List(context.Context) ([]fn.ListItem, error) {
func (l *Lister) List(context.Context) ([]bosonFunc.ListItem, error) {
l.ListInvoked = true
return l.ListFn()
}

View File

@ -3,21 +3,21 @@ package mock
import (
"context"
fn "github.com/boson-project/func"
bosonFunc "github.com/boson-project/func"
)
type Pusher struct {
PushInvoked bool
PushFn func(fn.Function) (string, error)
PushFn func(bosonFunc.Function) (string, error)
}
func NewPusher() *Pusher {
return &Pusher{
PushFn: func(fn.Function) (string, error) { return "", nil },
PushFn: func(bosonFunc.Function) (string, error) { return "", nil },
}
}
func (i *Pusher) Push(ctx context.Context, f fn.Function) (string, error) {
func (i *Pusher) Push(ctx context.Context, f bosonFunc.Function) (string, error) {
i.PushInvoked = true
return i.PushFn(f)
}

View File

@ -2,7 +2,7 @@ package mock
import (
"context"
fn "github.com/boson-project/func"
bosonFunc "github.com/boson-project/func"
)
type Runner struct {
@ -14,7 +14,7 @@ func NewRunner() *Runner {
return &Runner{}
}
func (r *Runner) Run(ctx context.Context, f fn.Function) error {
func (r *Runner) Run(ctx context.Context, f bosonFunc.Function) error {
r.RunInvoked = true
r.RootRequested = f.Root
return nil

12
pkged.go Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,224 +0,0 @@
package tarfs
import (
"archive/tar"
"bytes"
"io"
"io/fs"
"path"
"sort"
"strings"
"sync"
"time"
)
// FS is a tar-backed fs.FS
// adapted from testing/fstest.MapFS
type FS map[string]*file
// file can be any file within the FS
type file struct {
Data []byte
Mode fs.FileMode
ModTime time.Time
Sys interface{}
}
var _ fs.FS = FS(nil)
var _ fs.File = (*openFile)(nil)
// New tar FS from a reader attached to a tarball.
func New(r io.Reader) (FS, error) {
mapfs := make(map[string]*file)
tr := tar.NewReader(r)
for {
header, err := tr.Next()
if err == io.EOF {
return mapfs, nil
}
if err != nil {
return mapfs, err
}
// Create the file entry in the memory FS
mapfs[header.Name] = &file{
Mode: header.FileInfo().Mode(),
ModTime: header.FileInfo().ModTime(),
Sys: header.FileInfo().Sys,
}
// Done if directory
if header.FileInfo().IsDir() {
continue
}
// Copy over the data as well
buf := bytes.Buffer{}
if _, err = buf.ReadFrom(tr); err != nil {
return mapfs, err
}
mapfs[header.Name].Data = buf.Bytes()
}
}
func (fsys FS) Open(name string) (fs.File, error) {
if !fs.ValidPath(name) {
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist}
}
f := fsys[name]
if f != nil && f.Mode&fs.ModeDir == 0 {
// Ordinary file
return &openFile{fileInfo{path.Base(name), f}, name, 0}, nil
}
// Directory, possibly synthesized.
// Note that file can be nil here: the map need not contain explicit parent directories for all its files.
// But file can also be non-nil, in case the user wants to set metadata for the directory explicitly.
// Either way, we need to construct the list of children of this directory.
list := []fileInfo{}
elem := ""
need := make(map[string]bool)
if name == "." {
elem = "."
for fname, f := range fsys {
i := strings.Index(fname, "/")
if i < 0 {
list = append(list, fileInfo{fname, f})
} else {
need[fname[:i]] = true
}
}
} else {
elem = name[strings.LastIndex(name, "/")+1:]
prefix := name + "/"
for fname, f := range fsys {
if strings.HasPrefix(fname, prefix) {
felem := fname[len(prefix):]
i := strings.Index(felem, "/")
if i < 0 {
list = append(list, fileInfo{felem, f})
} else {
need[fname[len(prefix):len(prefix)+i]] = true
}
}
}
// If the directory name is not in the map,
// and there are no children of the name in the map,
// then the directory is treated as not existing.
if f == nil && len(list) == 0 && len(need) == 0 {
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist}
}
}
for _, fi := range list {
delete(need, fi.name)
}
for name := range need {
list = append(list, fileInfo{name, &file{Mode: fs.ModeDir}})
}
sort.Slice(list, func(i, j int) bool {
return list[i].name < list[j].name
})
if f == nil {
f = &file{Mode: fs.ModeDir}
}
return &dir{fileInfo{elem, f}, name, list, 0, sync.Mutex{}}, nil
}
// dir represents a directory in the FS
type dir struct {
fileInfo
path string
entries []fileInfo
offset int
sync.Mutex
}
func (d *dir) Stat() (fs.FileInfo, error) { return &d.fileInfo, nil }
func (d *dir) Close() error { return nil }
func (d *dir) Read(b []byte) (int, error) {
return 0, &fs.PathError{Op: "read", Path: d.path, Err: fs.ErrInvalid}
}
func (d *dir) ReadDir(count int) (entries []fs.DirEntry, err error) {
d.Lock()
defer d.Unlock()
n := len(d.entries) - d.offset
if count > 0 && n > count {
n = count
}
if n == 0 && count > 0 {
return nil, io.EOF
}
list := make([]fs.DirEntry, n)
for i := range list {
list[i] = &d.entries[d.offset+i]
}
d.offset += n
return list, nil
}
// fileInfo wraps files with metadata
type fileInfo struct {
name string
f *file
}
func (i *fileInfo) Name() string { return i.name }
func (i *fileInfo) Size() int64 { return int64(len(i.f.Data)) }
func (i *fileInfo) Mode() fs.FileMode { return i.f.Mode }
func (i *fileInfo) Type() fs.FileMode { return i.f.Mode.Type() }
func (i *fileInfo) ModTime() time.Time { return i.f.ModTime }
func (i *fileInfo) IsDir() bool { return i.f.Mode&fs.ModeDir != 0 }
func (i *fileInfo) Sys() interface{} { return i.f.Sys }
func (i *fileInfo) Info() (fs.FileInfo, error) { return i, nil }
// openFile decorates a fileInfo with accessors to the underlying data for use
// by Open
type openFile struct {
fileInfo
path string
offset int64
}
func (f *openFile) Stat() (fs.FileInfo, error) { return &f.fileInfo, nil }
func (f *openFile) Close() error { return nil }
func (f *openFile) Read(b []byte) (int, error) {
if f.offset >= int64(len(f.f.Data)) {
return 0, io.EOF
}
if f.offset < 0 {
return 0, &fs.PathError{Op: "read", Path: f.path, Err: fs.ErrInvalid}
}
n := copy(b, f.f.Data[f.offset:])
f.offset += int64(n)
return n, nil
}
func (f *openFile) Seek(offset int64, whence int) (int64, error) {
switch whence {
case 0:
// offset += 0
case 1:
offset += f.offset
case 2:
offset += int64(len(f.f.Data))
}
if offset < 0 || offset > int64(len(f.f.Data)) {
return 0, &fs.PathError{Op: "seek", Path: f.path, Err: fs.ErrInvalid}
}
f.offset = offset
return offset, nil
}
func (f *openFile) ReadAt(b []byte, offset int64) (int, error) {
if offset < 0 || offset > int64(len(f.f.Data)) {
return 0, &fs.PathError{Op: "read", Path: f.path, Err: fs.ErrInvalid}
}
n := copy(b, f.f.Data[offset:])
if n < len(b) {
return n, io.EOF
}
return n, nil
}

View File

@ -1,62 +0,0 @@
package tarfs
import (
"os"
"testing"
"testing/fstest"
)
// TestEmpty ensures that an empty TarFS behaves itself.
func TestEmpty(t *testing.T) {
f, err := os.Open("testdata/empty.tar")
if err != nil {
t.Fatal(err)
}
defer f.Close()
tfs, err := New(f)
if err != nil {
t.Fatal(err)
}
if err := fstest.TestFS(tfs); err != nil {
t.Fatal(err)
}
}
// TestFile ensures that a reader of a single file tarball proffers that file.
func TestSingle(t *testing.T) {
f, err := os.Open("testdata/single.tar")
if err != nil {
t.Fatal(err)
}
defer f.Close()
tfs, err := New(f)
if err != nil {
t.Fatal(err)
}
if err := fstest.TestFS(tfs, "single.txt"); err != nil {
t.Fatal(err)
}
}
// TestIsNotExist ensures that a request to read a file or directory which does not
// exist returns the appropriate error.
func TestIsNotExist(t *testing.T) {
f, err := os.Open("testdata/empty.tar")
if err != nil {
t.Fatal(err)
}
defer f.Close()
tfs, err := New(f)
if err != nil {
t.Fatal(err)
}
if err := fstest.TestFS(tfs, "invalid"); err == nil {
t.Fatalf("did not receive expected error testing for a missing file")
}
}

Binary file not shown.

Binary file not shown.

View File

@ -1,231 +1,181 @@
package function
// Updating Templates:
// See documentation in ./templates/README.md
// go get github.com/markbates/pkger
//go:generate pkger
import (
"bytes"
"compress/gzip"
_ "embed"
"errors"
"fmt"
"io"
"io/fs"
"os"
"path/filepath"
"sort"
"strings"
"github.com/boson-project/func/tarfs"
"github.com/markbates/pkger"
)
// Generate templates.tgz
//go:generate go run generate.go
// Embed the templates tarball
//go:embed templates.tgz
var embedded []byte
// DefaultTemplate is the default Function signature / environmental context
// DefautlTemplate is the default Function signature / environmental context
// of the resultant template. All runtimes are expected to have at least
// an HTTP Handler ("http") and Cloud Events ("events")
const DefaultTemplate = "http"
type templateWriter struct {
// Extensible Template Repositories
// templates on disk (extensible templates)
// Stored on disk at path:
// [customTemplatesPath]/[repository]/[runtime]/[template]
// For example
// ~/.config/func/boson/go/http"
// Specified when writing templates as simply:
// Write([runtime], [repository], [path])
// For example
// w := templateWriter{templates:"/home/username/.config/func/templates")
// w.Write("go", "boson/http")
// Ie. "Using the custom templates in the func configuration directory,
// write the Boson HTTP template for the Go runtime."
repositories string
templates fs.FS
verbose bool
// fileAccessor encapsulates methods for accessing template files.
type fileAccessor interface {
Stat(name string) (os.FileInfo, error)
Open(p string) (file, error)
}
var (
ErrRepositoryNotFound = errors.New("repository not found")
ErrRepositoriesNotDefined = errors.New("custom template location not specified")
ErrRuntimeNotFound = errors.New("runtime not found")
ErrTemplateNotFound = errors.New("template not found")
ErrTemplateMissingRepository = errors.New("template name missing repository prefix")
)
type file interface {
Readdir(int) ([]os.FileInfo, error)
Read([]byte) (int, error)
Close() error
}
// Decompress into an in-memory FS which implements fs.ReadDirFS
func (t *templateWriter) load() (err error) {
// When pkger is run, code analysis detects this Include statement,
// triggering the serializaation of the templates directory and all
// its contents into pkged.go, which is then made available via
// a pkger fileAccessor.
// Path is relative to the go module root.
func init() {
_ = pkger.Include("/templates")
}
// Templates are stored as an embedded byte slice gzip encoded.
zr, err := gzip.NewReader(bytes.NewReader(embedded))
type templateWriter struct {
verbose bool
templates string
}
func (n templateWriter) Write(runtime, template string, dest string) error {
if template == "" {
template = DefaultTemplate
}
// TODO: Confirm the dest path is empty? This is currently in an earlier
// step of the create process but future calls directly to initialize would
// be better off being made safe.
if isEmbedded(runtime, template) {
return copyEmbedded(runtime, template, dest)
}
if n.templates != "" {
return copyFilesystem(n.templates, runtime, template, dest)
}
return fmt.Errorf("A template for runtime '%v' template '%v' was not found internally and no custom template path was defined.", runtime, template)
}
func copyEmbedded(runtime, template, dest string) error {
// Copy files to the destination
// Example embedded path:
// /templates/go/http
src := filepath.Join("/templates", runtime, template)
return copy(src, dest, embeddedAccessor{})
}
func copyFilesystem(templatesPath, runtime, templateFullName, dest string) error {
// ensure that the templateFullName is of the format "repoName/templateName"
cc := strings.Split(templateFullName, "/")
if len(cc) != 2 {
return errors.New("Template name must be in the format 'REPO/NAME'")
}
repo := cc[0]
template := cc[1]
// Example FileSystem path:
// /home/alice/.config/func/templates/boson-experimental/go/json
src := filepath.Join(templatesPath, repo, runtime, template)
return copy(src, dest, filesystemAccessor{})
}
func isEmbedded(runtime, template string) bool {
_, err := pkger.Stat(filepath.Join("/templates", runtime, template))
return err == nil
}
type embeddedAccessor struct{}
func (a embeddedAccessor) Stat(path string) (os.FileInfo, error) {
return pkger.Stat(path)
}
func (a embeddedAccessor) Open(path string) (file, error) {
return pkger.Open(path)
}
type filesystemAccessor struct{}
func (a filesystemAccessor) Stat(path string) (os.FileInfo, error) {
return os.Stat(path)
}
func (a filesystemAccessor) Open(path string) (file, error) {
return os.Open(path)
}
func copy(src, dest string, accessor fileAccessor) (err error) {
node, err := accessor.Stat(src)
if err != nil {
return
}
if node.IsDir() {
return copyNode(src, dest, accessor)
} else {
return copyLeaf(src, dest, accessor)
}
}
func copyNode(src, dest string, accessor fileAccessor) (err error) {
node, err := accessor.Stat(src)
if err != nil {
return
}
t.templates, err = tarfs.New(zr)
return
}
err = os.MkdirAll(dest, node.Mode())
if err != nil {
return
}
// Write the template for the given runtime to the destination specified.
// Template may be prefixed with a custom repo name.
func (t *templateWriter) Write(runtime, template, dest string) (err error) {
if t.templates == nil {
// load static embedded templates into t.templates as an fs.FS
if err = t.load(); err != nil {
children, err := readDir(src, accessor)
if err != nil {
return
}
for _, child := range children {
if err = copy(filepath.Join(src, child.Name()), filepath.Join(dest, child.Name()), accessor); err != nil {
return
}
}
if template == "" {
template = DefaultTemplate
}
if isCustom(template) {
return t.writeCustom(t.repositories, runtime, template, dest)
}
return t.writeEmbedded(runtime, template, dest)
return
}
func isCustom(template string) bool {
return len(strings.Split(template, "/")) > 1
}
func (t *templateWriter) writeCustom(repositoriesPath, runtime, template, dest string) (err error) {
if repositoriesPath == "" {
return ErrRepositoriesNotDefined
}
if !repositoryExists(repositoriesPath, template) {
return ErrRepositoryNotFound
}
cc := strings.Split(template, "/")
if len(cc) < 2 {
return ErrTemplateMissingRepository
}
repositoriesFS := os.DirFS(repositoriesPath)
runtimePath := cc[0] + "/" + runtime
_, err = fs.Stat(repositoriesFS, runtimePath)
if errors.Is(err, fs.ErrNotExist) {
return ErrRuntimeNotFound
}
templatePath := runtimePath + "/" + cc[1]
_, err = fs.Stat(repositoriesFS, templatePath)
if errors.Is(err, fs.ErrNotExist) {
return ErrTemplateNotFound
}
// ex: /home/alice/.config/func/repositories/boson/go/http
// Note that the FS instance returned by os.DirFS uses forward slashes
// internally, so source paths do not use the os path separator due to
// that breaking Windows.
src := cc[0] + "/" + runtime + "/" + cc[1]
return t.cp(src, dest, repositoriesFS)
}
func (t *templateWriter) writeEmbedded(runtime, template, dest string) error {
runtimePath := "templates/" + runtime // embedded FS alwas uses '/'
_, err := fs.Stat(t.templates, runtimePath)
if errors.Is(err, fs.ErrNotExist) {
return ErrRuntimeNotFound
}
templatePath := "templates/" + runtime + "/" + template // always '/' in embedded fs
_, err = fs.Stat(t.templates, templatePath)
if errors.Is(err, fs.ErrNotExist) {
return ErrTemplateNotFound
}
return t.cp(templatePath, dest, t.templates)
}
func repositoryExists(repositories, template string) bool {
cc := strings.Split(template, "/")
_, err := fs.Stat(os.DirFS(repositories), cc[0])
return err == nil
}
func (t *templateWriter) cp(src, dest string, files fs.FS) error {
node, err := fs.Stat(files, src)
if err != nil {
return err
}
if node.IsDir() {
return t.copyNode(src, dest, files)
} else {
return t.copyLeaf(src, dest, files)
}
}
func (t *templateWriter) copyNode(src, dest string, files fs.FS) error {
node, err := fs.Stat(files, src)
if err != nil {
return err
}
mode := node.Mode()
err = os.MkdirAll(dest, mode)
if err != nil {
return err
}
children, err := readDir(src, files)
if err != nil {
return err
}
for _, child := range children {
// NOTE: instances of fs.FS use forward slashes,
// even on Windows.
childSrc := src + "/" + child.Name()
childDest := filepath.Join(dest, child.Name())
if err = t.cp(childSrc, childDest, files); err != nil {
return err
}
}
return nil
}
func readDir(src string, files fs.FS) ([]fs.DirEntry, error) {
f, err := files.Open(src)
func readDir(src string, accessor fileAccessor) ([]os.FileInfo, error) {
f, err := accessor.Open(src)
if err != nil {
return nil, err
}
defer f.Close()
fi, err := f.Stat()
list, err := f.Readdir(-1)
f.Close()
if err != nil {
return nil, err
}
if !fi.IsDir() {
return nil, fmt.Errorf("%v must be a directory", fi.Name())
}
list, err := f.(fs.ReadDirFile).ReadDir(-1)
if err != nil {
return nil, err
}
sort.Slice(list, func(i, j int) bool { return list[i].Name() < list[j].Name() })
return list, nil
}
func (t *templateWriter) copyLeaf(src, dest string, files fs.FS) (err error) {
srcFile, err := files.Open(src)
func copyLeaf(src, dest string, accessor fileAccessor) (err error) {
srcFile, err := accessor.Open(src)
if err != nil {
return
}
defer srcFile.Close()
srcFileInfo, err := fs.Stat(files, src)
srcFileInfo, err := accessor.Stat(src)
if err != nil {
return
}
// Use the original's mode unless a nonzero mode was explicitly provided.
mode := srcFileInfo.Mode()
destFile, err := os.OpenFile(dest, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode)
destFile, err := os.OpenFile(dest, os.O_RDWR|os.O_CREATE|os.O_TRUNC, srcFileInfo.Mode())
if err != nil {
return
}

View File

@ -1,4 +1,24 @@
# Templates
This templates directory is embedded entirely into any resultant binaries
using the go:embed directive introduced in Go 1.16
## Packaging
When updates are made to these templates, they must be packaged (serialized as
a Go struture) by running `make`, and checking in the resultant `pkged.go` file.
## How it works
running `make` in turn installs the `pkger` binary, which can be installed via:
`go get github.com/markbates/pkger/cmd/pkger`
Make then invokes `pkger` before `go build`.
The resulting `pkged.go` file includes the contents of the templates directory,
encoded as a Go strucutres which is then makde available in code using an API
similar to the standard library's `os` package.
## Rationale
Until such time as embedding static assets in binaries is included in the
base `go build` functionality (see https://github.com/golang/go/issues/35950)
a third-party tool is required and pkger provides an API very similar
to the `os` package.

View File

@ -1,118 +0,0 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudevents/sdk-go/v2 v2.3.1 h1:QRTu0yRA4FbznjRSds0/4Hy6cVYpWV2wInlNJSHWAtw=
github.com/cloudevents/sdk-go/v2 v2.3.1/go.mod h1:4fO2UjPMYYR1/7KPJQCwTPb0lFA8zYuitkUpAZFSY1Q=
github.com/cloudevents/sdk-go/v2 v2.4.0 h1:IkzAOizTvn+M13KWDLFOiTb44YBuwAvbenzSg43bWM4=
github.com/cloudevents/sdk-go/v2 v2.4.0/go.mod h1:MZiMwmAh5tGj+fPFvtHv9hKurKqXtdB9haJYMJ/7GJY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk=
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac h1:+2b6iGRJe3hvV/yVXrd41yVEjxuFHxasJqDhkIjS4gk=
github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac/go.mod h1:Frd2bnT3w5FB5q49ENTfVlztJES+1k/7lyWX2+9gq/M=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.2 h1:uqH7bpe+ERSiDa34FDOF7RikN6RzXgduUF8yarlZp94=
github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -1,86 +0,0 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudevents/sdk-go/v2 v2.3.1/go.mod h1:4fO2UjPMYYR1/7KPJQCwTPb0lFA8zYuitkUpAZFSY1Q=
github.com/cloudevents/sdk-go/v2 v2.4.0 h1:IkzAOizTvn+M13KWDLFOiTb44YBuwAvbenzSg43bWM4=
github.com/cloudevents/sdk-go/v2 v2.4.0/go.mod h1:MZiMwmAh5tGj+fPFvtHv9hKurKqXtdB9haJYMJ/7GJY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac/go.mod h1:Frd2bnT3w5FB5q49ENTfVlztJES+1k/7lyWX2+9gq/M=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -1,2 +0,0 @@
Runtime A
Template HTTP (Default)

View File

@ -1,2 +0,0 @@
Runtime A
Template A

View File

@ -1,2 +0,0 @@
#!/usr/bin/env bash
echo "example executable script provided by a template"

View File

@ -1,2 +0,0 @@
Runtime A
Template B

View File

@ -3,186 +3,75 @@
package function
import (
"errors"
"os"
"path/filepath"
"runtime"
"testing"
)
// TestRuntime consists of a specially designed templates directory
// used exclusively for embedded template write tests.
const TestRuntime = "test"
// TestWriteEmbedded ensures that embedded templates are copied.
func TestWriteEmbedded(t *testing.T) {
// create test directory
root := "testdata/testWriteEmbedded"
defer using(t, root)()
// write out a template
w := templateWriter{}
err := w.Write(TestRuntime, "tpla", root)
// TestTemplatesEmbeddedFileMode ensures that files from the embedded templates are
// written with the same mode from whence they came
func TestTemplatesEmbeddedFileMode(t *testing.T) {
var path = "testdata/example.com/www"
err := os.MkdirAll(path, 0744)
if err != nil {
panic(err)
}
defer os.RemoveAll(path)
client := New()
function := Function{Root: path, Runtime: "quarkus", Trigger: "events"}
if err := client.Create(function); err != nil {
t.Fatal(err)
}
// Assert file exists as expected
_, err = os.Stat(filepath.Join(root, "rtAtplA.txt"))
// The file mode of the embedded mvnw should be -rwxr-xr-x
// See source file at: templates/quarkus/events/mvnw
// Assert mode is preserved
sourceMode := os.FileMode(0755)
dest, err := os.Stat(filepath.Join(path, "mvnw"))
if err != nil {
t.Fatal(err)
}
if runtime.GOOS != "windows" {
if dest.Mode() != sourceMode {
t.Fatalf("The dest mode should be %v but was %v", sourceMode, dest.Mode())
}
}
}
// TestWriteCustom ensures that a template from a filesystem source (ie. custom
// provider on disk) can be specified as the source for a template.
func TestWriteCustom(t *testing.T) {
// Create test directory
root := "testdata/testWriteFilesystem"
defer using(t, root)()
// TestTemplatesExtensibleFileMode ensures that files from a file-system
// derived template is written with mode retained.
func TestTemplatesExtensibleFileMode(t *testing.T) {
var (
path = "testdata/example.com/www"
template = "boson-experimental/http"
templates = "testdata/templates"
)
err := os.MkdirAll(path, 0744)
if err != nil {
panic(err)
}
defer os.RemoveAll(path)
// Writer which includes reference to custom repositories location
w := templateWriter{repositories: "testdata/repositories"}
// template, in form [provider]/[template], on disk the template is
// located at testdata/repositories/[provider]/[runtime]/[template]
tpl := "customProvider/tpla"
err := w.Write(TestRuntime, tpl, root)
client := New(WithTemplates(templates))
function := Function{Root: path, Runtime: "quarkus", Trigger: template}
if err := client.Create(function); err != nil {
t.Fatal(err)
}
// Assert mode is preserved
source, err := os.Stat(filepath.Join("testdata/templates/boson-experimental/quarkus/http/mvnw"))
if err != nil {
t.Fatal(err)
}
// Assert file exists as expected
_, err = os.Stat(filepath.Join(root, "customtpl.txt"))
dest, err := os.Stat(filepath.Join(path, "mvnw"))
if err != nil {
t.Fatal(err)
}
}
// TestWriteDefault ensures that the default template is used when not specified.
func TestWriteDefault(t *testing.T) {
// create test directory
root := "testdata/testWriteDefault"
defer using(t, root)()
// write out a template
w := templateWriter{}
err := w.Write(TestRuntime, "", root)
if err != nil {
t.Fatal(err)
}
// Assert file exists as expected
_, err = os.Stat(filepath.Join(root, "rtAtplDefault.txt"))
if err != nil {
t.Fatal(err)
}
}
// TestWriteInvalid ensures that specifying unrecgognized runtime/template errors
func TestWriteInvalid(t *testing.T) {
// create test directory
root := "testdata/testWriteInvalid"
defer using(t, root)()
w := templateWriter{}
var err error // should be populated with the correct error type
// Test for error writing an invalid runtime
// (the http template
err = w.Write("invalid", DefaultTemplate, root)
if !errors.Is(err, ErrRuntimeNotFound) {
t.Fatalf("Expected ErrRuntimeNotFound, got %T", err)
}
// Test for error writing an invalid template
err = w.Write(TestRuntime, "invalid", root)
if !errors.Is(err, ErrTemplateNotFound) {
t.Fatalf("Expected ErrTemplateNotFound, got %T", err)
}
}
// TestWriteModeEmbedded ensures that templates written from the embedded
// templates retain their mode.
func TestWriteModeEmbedded(t *testing.T) {
if runtime.GOOS == "windows" {
return
// not applicable
}
// set up test directory
var err error
root := "testdata/testWriteModeEmbedded"
defer using(t, root)()
// Write the embedded template that contains an executable script
w := templateWriter{}
err = w.Write(TestRuntime, "tplb", root)
if err != nil {
t.Fatal(err)
}
// Verify file mode was preserved
file, err := os.Stat(filepath.Join(root, "executable.sh"))
if err != nil {
t.Fatal(err)
}
if file.Mode() != os.FileMode(0755) {
t.Fatalf("The embedded executable's mode should be 0755 but was %v", file.Mode())
}
}
// TestWriteModeCustom ensures that templates written from custom templates
// retain their mode.
func TestWriteModeCustom(t *testing.T) {
if runtime.GOOS == "windows" {
return // not applicable
}
// test directories
var err error
root := "testdata/testWriteModeCustom"
defer using(t, root)()
// Write executable from custom repo
w := templateWriter{repositories: "testdata/repositories"}
err = w.Write(TestRuntime, "customProvider/tplb", root)
if err != nil {
t.Fatal(err)
}
// Verify custom file mode was preserved.
file, err := os.Stat(filepath.Join(root, "executable.sh"))
if err != nil {
t.Fatal(err)
}
if file.Mode() != os.FileMode(0755) {
t.Fatalf("The custom executable file's mode should be 0755 but was %v", file.Mode())
}
}
// Helpers
// -------
// using the given directory (creating it) returns a closure which removes the
// directory, intended to be run in a defer statement.
func using(t *testing.T, root string) func() {
t.Helper()
mkdir(t, root)
return func() {
rm(t, root)
}
}
func mkdir(t *testing.T, dir string) {
t.Helper()
if err := os.MkdirAll(dir, 0700); err != nil {
t.Fatal(err)
}
}
func rm(t *testing.T, dir string) {
t.Helper()
if err := os.RemoveAll(dir); err != nil {
t.Fatal(err)
if runtime.GOOS != "windows" {
if dest.Mode() != source.Mode() {
t.Fatalf("The dest mode should be %v but was %v", source.Mode(), dest.Mode())
}
}
}

View File

@ -1,3 +0,0 @@
Custom Provider
Runtime A
Template A

View File

@ -1,2 +0,0 @@
#!/usr/bin/env bash
echo "example executable script provided by a template"