Skip to content

Commit

Permalink
Merge pull request #76 from davidovich/implement-fs
Browse files Browse the repository at this point in the history
Implement fs
davidovich authored Nov 5, 2021

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
2 parents d6a3c34 + c259051 commit f5d6cb0
Showing 38 changed files with 386 additions and 350 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ version: 2
jobs:
build:
docker:
- image: circleci/golang:1.15
- image: circleci/golang:1.17
environment:
GO111MODULE=on
steps:
33 changes: 9 additions & 24 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,43 +1,29 @@
SHELL=/bin/bash

HAS_PACKR2 := $(shell command -v packr2)
HAS_GOBIN := $(shell command -v gobin)
HAS_GOCOVERUTIL := $(shell command -v gocoverutil)

ifndef HAS_GOBIN
$(shell GO111MODULE=off go get -u github.com/myitcv/gobin 2>/dev/null)
endif

export GO111MODULE := on

SCAFFOLD_BIN := bin/scaffold
PACKR_FILE := internal/scaffold/scaffold-packr.go
SCAFFOLD_SRCS := $(shell GO111MODULE=on go list -f '{{ $$dir := .Dir}}{{range .GoFiles}}{{ printf "%s/%s\n" $$dir . }}{{end}}' github.com/davidovich/summon/scaffold/...)
COVERAGE_PERCENT_FILE := $(CURDIR)/build/coverage-percent.txt

DOC_REPO_NAME := davidovich.github.io
DOC_REPO := git@github.com:davidovich/$(DOC_REPO_NAME).git
SUMMON_BADGE_JSON_FILE := $(DOC_REPO_NAME)/shields/summon/summon.json

ASSETS := $(shell find internal/templates/scaffold)
ASSETS := $(shell find internal/scaffold/templates/scaffold)

all: $(PACKR_FILE) test $(SCAFFOLD_BIN)
all: test $(SCAFFOLD_BIN)

.PHONY: bin
bin: $(PACKR_FILE) $(SCAFFOLD_BIN)
bin: $(SCAFFOLD_BIN)

.PHONY: $(SCAFFOLD_BIN)
$(SCAFFOLD_BIN): $(PACKR_FILE)
@mkdir -p bin
$(SCAFFOLD_BIN): $(ASSETS) $(SCAFFOLD_SRCS)
go build -o $@ $(@F)/$(@F).go

$(PACKR_FILE): $(ASSETS)
ifndef HAS_PACKR2
gobin github.com/gobuffalo/packr/v2/packr2
endif
cd internal/scaffold && packr2

GO_TESTS := pkg internal cmd
COVERAGE := $(foreach t,$(GO_TESTS),build/coverage/report/$(t))
COVERAGE := build/coverage/report/summon
MERGED_COVERAGE := build/coverage/report/cover.merged.out
HTML_COVERAGE := build/coverage/html/index.html

@@ -57,7 +43,7 @@ $(COVERAGE_PERCENT_FILE): $(MERGED_COVERAGE)

$(MERGED_COVERAGE): $(COVERAGE)
ifndef HAS_GOCOVERUTIL
gobin github.com/AlekSi/gocoverutil@v0.2.0
go install github.com/AlekSi/gocoverutil@v0.2.0
endif
gocoverutil -coverprofile=$@ merge $^

@@ -67,7 +53,7 @@ $(HTML_COVERAGE): $(MERGED_COVERAGE)

$(COVERAGE):
@mkdir -p $(@D)
go test ./$(@F)/... --cover -coverprofile $@ -v
go test ./... --cover -coverprofile $@ -v

.PHONY: update-coverage-badge
update-coverage-badge: $(COVERAGE_PERCENT_FILE)
@@ -78,12 +64,11 @@ else
rm -rf /tmp/$(DOC_REPO_NAME)
git -C /tmp clone $(DOC_REPO)
cd /tmp/$(DOC_REPO_NAME) && \
gobin -run github.com/davidovich/summon-example-assets/summon shields.io/coverage.json.gotmpl --json "{\"Coverage\": \"$$(cat $(COVERAGE_PERCENT_FILE))\"}" -o- > /tmp/$(SUMMON_BADGE_JSON_FILE)
go run github.com/davidovich/summon-example-assets@3c2e66d7 shields.io/coverage.json.gotmpl --json "{\"Coverage\": \"$$(cat $(COVERAGE_PERCENT_FILE))\"}" -o- > /tmp/$(SUMMON_BADGE_JSON_FILE)
git -C /tmp/$(DOC_REPO_NAME) diff-index --quiet HEAD || git -C /tmp/$(DOC_REPO_NAME) -c user.email=automation@davidovich.com -c user.name=automation commit -am "automated coverage commit of $$(cat $(COVERAGE_PERCENT_FILE)) %" || true
git -C /tmp/$(DOC_REPO_NAME) push
endif

.PHONY: clean
clean:
packr2 clean
rm -rf bin build
109 changes: 62 additions & 47 deletions README.md
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@
- [How it Works](#how-it-works)
- [Configuration](#configuration)
- [Data repository](#data-repository)
- [Migration from versions prior to v0.13.0](#migration-from-versions-prior-to-v0130)
- [Summon config File](#summon-config-file)
- [Build](#build)
- [Install](#install)
@@ -45,27 +46,40 @@ state (packed scripts or pinned versions of binaries).

> NOTE: This project is still a WIP and experimental.
To install, you first need to create something to install by populating a [data repository](#Configuration). Then, this data repo is installed by using [gobin](https://github.com/myitcv/gobin) (or go install):
To install, you first need to create something to install by populating a
[data repository](#Configuration). Then, this data repo is installed by using
the `go install` command:

```bash
gobin [your-summon-data-repo]/summon
go install [your-summon-data-repo]/summon@latest
```

Assuming there is a my-team-utility.sh script hosted in the data repo, (see how to [configure](#Configuration) below) you can do things like:
Assuming there is a my-team-utility.sh script hosted in the data repo, (see how
to [configure](#Configuration) below) you can do things like:

```bash
bash $(summon my-team-utility.sh)
```

## How it Works

Summon is a library which is consumed by an asset repository (which, by default, has also the `summon` name). This asset repository, managed by your team, provides the summon executable command (it's main() function is in summon/summon.go).
The library provides the command-line interface, so no coding is necessary in the assert repo.
Summon is a library which is consumed by an asset repository (which, by default,
has also the `summon` name). This asset repository, managed by your team,
provides the summon executable command (it's main() function is in
summon/summon.go). The library provides the command-line interface, so no
coding is necessary in the assert repo.

Summon also provides a boostrapping feature in the scaffold command.

Summon builds upon [packr2](https://github.com/gobuffalo/packr/tree/master/v2) to convert an arbitrary tree of files in go compilable source
which you then bootstrap at destination using standard go get or [gobin](https://github.com/myitcv/gobin). The invoked files are then placed locally and the summoned file path is returned so it can be consumed by other shell operations.
> New in v0.13.0
Summon builds upon the new go 1.16 [embed.FS](https://pkg.go.dev/embed) feature
used to pack assets in a go binary. You then install this at destination using
standard `go install`.

When you invoke this binary with a contained asset path, the invoked files are
placed locally and the summoned file path is returned so it can be consumed by
other shell operations.

## Configuration

@@ -76,38 +90,49 @@ Use summon's scaffold feature to create a data repository, which will become you
> Scaffolding is new in v0.1.0
```bash
gobin -run github.com/davidovich/summon/scaffold init [module name]
# go run package at a version requires go 1.17 and up
go run github.com/davidovich/summon/scaffold@latest init [module name]
```

> Be sure to change the [module name] part (usually you will use a module path compatible with where you will host the data repo on a code hosting site).
> Be sure to change the [module name] part (usually you will use a module path
> compatible with where you will host the data repo on a code hosting site).
You will then have something resembling this structure:

```bash
.
├── Makefile
├── README.md
├── assets
│ └── summon.config.yaml
├── go.mod
├── go.sum
└── summon
├── assets
│ └── summon.config.yaml
└── summon.go
```

There is an example setup at https://github.com/davidovich/summon-example-assets.

You just need to populate the `assets` directory with your own data.
You just need to populate the `summon/assets` directory with your own data.

The `summon/summon.go` file of the main module is the entry point to the summon
library, and creates the main command executable.

The `summon/` directory is the entry point to the summon library, and creates the main command executable. This directory will also host
[packr2](https://github.com/gobuffalo/packr/tree/master/v2) generated data files which encode asset data into go files.
#### Migration from versions prior to v0.13.0

The v0.13.0 version uses the embed.FS and the `//go:embed assets/*` directive.
Prior versions used to reference the `assets/` dir at the root of the repo.
This means that the data being embeded must now be a sibling of the source
file containing `package main`.

### Summon config File

The `assets/summon.config.yaml` is an (optional) configuration file to customize summon. You can define:
The `summon/assets/summon.config.yaml` is an (optional) configuration file to
customize summon. You can define:

* aliases
* default output-dir
* executables
- aliases
- default output-dir
- executables

> Breaking in v0.11.0: Handles now take an array of params
@@ -138,9 +163,8 @@ exec:
# ^ handle to script (must be unique). This is what you use
# to invoke the script: `summon run hello`.

gobin -run: # go gettable executables
gobin: [github.com/myitcv/gobin@v0.0.8]
gohack: [github.com/rogppepe/gohack]
go run: # go gettable executables
gohack: [github.com/rogppepe/gohack@latest]

python -c:
hello-python: [print("hello from python!")]
@@ -161,7 +185,8 @@ You can invoke executables like so:
summon run gohack ...
```

This will install gohack using `gobin -run` and forward the arguments that you provide.
This will call and run gohack using `go run` and forward the arguments that you
provide.

> New in v0.10.0, summon now allows templating in the invocable section. See
> [Templating](#/templating).
@@ -170,35 +195,22 @@ This will install gohack using `gobin -run` and forward the arguments that you p

In an empty asset data repository directory:

* First (and once) invoke `go run github.com/davidovich/summon/scaffold init [repo host (module name)]`
- First (and once) invoke `go run github.com/davidovich/summon/scaffold@latest init [repo host (module name)]`
This will create code template similar as above

1. Add assets that need to be shared amongst consumers
2. Use the provided Makefile to invoke the packr2 process: `make`
3. Commit the resulting -packr files so clients can go get the data repo
2. Use the provided Makefile to create the asset executable: `make`
3. Commit the all the files so clients can go get the data repo
4. Tag the repo with semantic version (with the `v`) prefix.
5. Push to remote.
6. Install.
6. On a consumer machine, install.

## Install

Install (using gobin) the asset repo which will become the summon executable.
You have these alternatives:

* change to a directory that does not contain a go.mod. This installs globally:

```bash
cd /tmp
GO111MODULE=on go get [your-go-repo-import]/summon[@wanted-version-or-branch]
cd -
```

* use gobin to install summon in the consuming site:
Install (using `go install`) the asset repo which will become the summon executable.

```bash
GO111MODULE=off go get -u github.com/myitcv/gobin
# install the data repository as summon executable at the site
GOBIN=./ gobin [your-go-repo-import]/summon[@wanted-version-or-branch]
go install [your-go-repo-module]/summon@latest
```

## Use-cases
@@ -212,12 +224,13 @@ summon returns the path ot where the resource was instantiated:
include $(shell summon version.mk)
```

By default, summon will put summoned scripts at the `.summoned/` directory at root of the current directory.
By default, summon will put summoned scripts at the `.summoned/` directory at
the root of the current directory. This can be changed with the `-o` flag.

### Templating

Files in the asset directory can contain go templates. This allows applying
customization using json data.
customization using json data, just before rendering the file (and its contents).

> New in v0.3.0, summon now uses the [Sprig templating library](https://github.com/Masterminds/sprig), which provides many useful templating functions.
@@ -230,21 +243,23 @@ For example, consider this file in a summon asset provider:

With this content:

```bash
```txt
Hello {{ .Name }}!
```

`summon template.file --json '{ "Name": "David" }'`

You will get a summoned `template.file` file with this result:

```bash
```shell
Hello David!
```

> New in v0.2.0, you can summon a whole asset hierarchy by using a directory reference when summoning.
> New in v0.2.0, you can summon a whole asset hierarchy by using a directory
> reference when summoning.
Templates can also be used in the filenames given in the data hierarchy. This can be useful to scaffold simple projects.
Templates can also be used in the filenames given in the data hierarchy. This
can be useful to scaffold simple projects.

```bash
/assets
64 changes: 64 additions & 0 deletions assets/summon.config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# this is a sample summon config file
# see https://github.com/davidovich/summon#configuration
version: 1
aliases: {"git-version": "bin/version.sh"}
# outputdir: "overridden_dir"
exec:
bash:
hello-bash: ['{{ summon "hello.sh" }}']

docker run -v {{ env "PWD" }}:/mounted-app alpine ls:
list: [/mounted-app]

go run:
gohack: [github.com/rogpeppe/gohack@v1.0.2]

docker {{ lower "INFO" }}: # naive example of templating
docker-info:

? docker run -ti --rm -w /{{ env "PWD" | base }}
-v {{ env "PWD" }}:/{{ env "PWD" | base }}
hairyhenderson/figlet
:
figlet: ['hello {{ env "USER" }}']

# echo: # future implementation idea
# - handle: echo
# args: ['echoing: {{ .Message }}']
# env: []

python3 -c:
hello:
- |
import sys
print('pyhon version:'); print(sys.version)
if True:
print()
print(f"hello from python! args: {sys.argv}")
python -c:
hellopy2: [print('hello from python!')]

bash -c:
# small function to setup a temporary GOPATH compatible godoc server inside docker
# see https://github.com/golang/go/issues/26827. This allows serving documentation
# for a go modules enabled project.
godoc:
- |
function _godoc() {
[ ! -f "$(pwd)/go.mod" ] && echo "error: go.mod not found" ||
module=$(awk 'NR==1{print $2}' go.mod) &&
docker run --rm -ti -e "GOPATH=/tmp/go" -p 6060:6060 -v $(pwd):/tmp/go/src/$module golang:1.15 /bin/bash -c "GO111MODULE=on go get golang.org/x/tools/cmd/godoc && echo -e \"\nhttp://localhost:6060/pkg/$module\" && \$(go env GOPATH)/bin/godoc -http=:6060"
unset -f _godoc;
}
_godoc
# kmerge merges a the default kubeconfig with a kubeconfig file passed as argement
# https://github.com/kubernetes/kubernetes/issues/46381#issuecomment-461404505
kmerge:
- |
function kmerge() {
KUBECONFIG=~/.kube/config:$1 kubectl config view --flatten > ~/.kube/mergedkub && mv ~/.kube/mergedkub ~/.kube/config
}
kmerge
5 changes: 1 addition & 4 deletions cmd/completion_test.go
Original file line number Diff line number Diff line change
@@ -5,14 +5,11 @@ import (
"testing"

"github.com/davidovich/summon/pkg/summon"
"github.com/gobuffalo/packr/v2"
"github.com/stretchr/testify/assert"
)

func TestCompletionCommand(t *testing.T) {
box := packr.New("testCompletion", "testdata/plain")

s, _ := summon.New(box)
s, _ := summon.New(runCmdTestFS)

cmd := newCompletionCmd(s)

10 changes: 5 additions & 5 deletions cmd/list_test.go
Original file line number Diff line number Diff line change
@@ -6,13 +6,11 @@ import (
"testing"

"github.com/davidovich/summon/pkg/summon"
"github.com/gobuffalo/packr/v2"
"github.com/stretchr/testify/assert"
)

func TestListCmd(t *testing.T) {

box := packr.New("test box", "testdata/plain")
tests := []struct {
name string
args []string
@@ -21,20 +19,22 @@ func TestListCmd(t *testing.T) {
}{
{
name: "no-args",
expected: "json-for-template.json\nsummon.config.yaml",
expected: "a.txt\nb.txt\njson-for-template.json\nsummon.config.yaml",
},
{
name: "--tree",
args: []string{"--tree"},
expected: `plain
expected: `testdata
├── a.txt
├── b.txt
├── json-for-template.json
└── summon.config.yaml`,
},
}

for i, tt := range tests {
t.Run(strconv.Itoa(i)+"_"+tt.name, func(t *testing.T) {
s, _ := summon.New(box)
s, _ := summon.New(runCmdTestFS)

cmd := newListCmd(false, nil, s)
cmd.cmd.SetArgs(tt.args)
28 changes: 9 additions & 19 deletions cmd/root_test.go
Original file line number Diff line number Diff line change
@@ -12,11 +12,10 @@ import (

"github.com/davidovich/summon/internal/testutil"
"github.com/davidovich/summon/pkg/summon"
"github.com/gobuffalo/packr/v2"
)

func makeRootCmd(box *packr.Box, withoutRun bool, args ...string) (*summon.Driver, *cobra.Command) {
s, _ := summon.New(box)
func makeRootCmd(withoutRun bool, args ...string) (*summon.Driver, *cobra.Command) {
s, _ := summon.New(runCmdTestFS)
rootCmd := CreateRootCmd(s, []string{"summon"}, summon.MainOptions{WithoutRunSubcmd: withoutRun})
rootCmd.SetArgs(args)
return s, rootCmd
@@ -25,10 +24,6 @@ func makeRootCmd(box *packr.Box, withoutRun bool, args ...string) (*summon.Drive
func Test_createRootCmd(t *testing.T) {
defer testutil.ReplaceFs()()

box := packr.New("test box", "testdata/plain")
box.AddString("a.txt", "a content")
box.AddString("b.txt", "b content")

mockBuildInfo := func() func() {
oldBi := buildInfo
buildInfo = func() (*debug.BuildInfo, bool) {
@@ -52,7 +47,7 @@ func Test_createRootCmd(t *testing.T) {
}

makeRootCmd := func(args ...string) *cobra.Command {
_, c := makeRootCmd(box, false, args...)
_, c := makeRootCmd(false, args...)
return c
}

@@ -102,7 +97,7 @@ func Test_createRootCmd(t *testing.T) {
},
{
name: "--json-file",
rootCmd: makeRootCmd("--json-file", "testdata/plain/json-for-template.json", "summon.config.yaml"),
rootCmd: makeRootCmd("--json-file", "testdata/json-for-template.json", "summon.config.yaml"),
wantErr: false,
},
{
@@ -139,7 +134,6 @@ func Test_createRootCmd(t *testing.T) {
}

func Test_RootCmdWithRunnables(t *testing.T) {
box := packr.New("test box runnables", "testdata/plain")

tests := []struct {
name string
@@ -162,7 +156,7 @@ func Test_RootCmdWithRunnables(t *testing.T) {
}
for i, tt := range tests {
t.Run(strconv.Itoa(i)+"_"+tt.name, func(t *testing.T) {
s, rootCmd := makeRootCmd(box, true, tt.args...)
s, rootCmd := makeRootCmd(true, tt.args...)

stdout := &bytes.Buffer{}
stderr := &bytes.Buffer{}
@@ -184,10 +178,6 @@ func Test_RootCmdWithRunnables(t *testing.T) {
func Test_mainCmd_run(t *testing.T) {
defer testutil.ReplaceFs()()

box := packr.New("test box Test_mainCmd_run", t.TempDir())
box.AddString("a.txt", "a content")
box.AddString("b.txt", "b content")

type fields struct {
copyAll bool
dest string
@@ -206,24 +196,24 @@ func Test_mainCmd_run(t *testing.T) {
fields: fields{
dest: ".s",
filename: "a.txt",
driver: func() *summon.Driver { s, _ := summon.New(box); return s }(),
driver: func() *summon.Driver { s, _ := summon.New(runCmdTestFS); return s }(),
},
out: ".s/a.txt\n",
},
{
name: "ls-option",
lsAsOption: true,
fields: fields{
driver: func() *summon.Driver { s, _ := summon.New(box); return s }(),
driver: func() *summon.Driver { s, _ := summon.New(runCmdTestFS); return s }(),
},
out: "a.txt\nb.txt\n",
out: "a.txt\nb.txt\njson-for-template.json\nsummon.config.yaml\n",
},
{
name: "copyAll",
fields: fields{
copyAll: true,
dest: ".s",
driver: func() *summon.Driver { s, _ := summon.New(box); return s }(),
driver: func() *summon.Driver { s, _ := summon.New(runCmdTestFS); return s }(),
},
out: ".s\n", // note dest dir
},
8 changes: 5 additions & 3 deletions cmd/run_test.go
Original file line number Diff line number Diff line change
@@ -2,17 +2,19 @@ package cmd

import (
"bytes"
"embed"
"testing"

"github.com/davidovich/summon/internal/testutil"
"github.com/davidovich/summon/pkg/summon"
"github.com/gobuffalo/packr/v2"
"github.com/spf13/pflag"
"github.com/stretchr/testify/assert"
)

//go:embed testdata/*
var runCmdTestFS embed.FS

func TestRunCmd(t *testing.T) {
box := packr.New("test box", "testdata/plain")

testCases := []struct {
desc string
@@ -57,7 +59,7 @@ func TestRunCmd(t *testing.T) {

for _, tC := range testCases {
t.Run(tC.desc, func(t *testing.T) {
s, _ := summon.New(box)
s, _ := summon.New(runCmdTestFS)
stdout := &bytes.Buffer{}
stderr := &bytes.Buffer{}
execCommand := testutil.FakeExecCommand("TestSummonRunHelper", stdout, stderr)
1 change: 1 addition & 0 deletions cmd/testdata/a.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
a content
1 change: 1 addition & 0 deletions cmd/testdata/b.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
b content
1 change: 1 addition & 0 deletions cmd/testdata/json-for-template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 0 additions & 1 deletion cmd/testdata/plain/json-for-template.json

This file was deleted.

File renamed without changes.
20 changes: 17 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,17 +1,31 @@
module github.com/davidovich/summon

go 1.17

require (
github.com/DiSiqueira/GoTree v1.0.1-0.20190529205929-3e23dcd4532b
github.com/Masterminds/sprig/v3 v3.1.0
github.com/gobuffalo/packr/v2 v2.5.1
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/lithammer/dedent v1.1.0
github.com/spf13/afero v1.2.1
github.com/spf13/cobra v1.0.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.5.1
golang.org/x/sys v0.0.0-20200819091447-39769834ee22 // indirect
gopkg.in/yaml.v2 v2.2.2
)

go 1.15
require (
github.com/Masterminds/goutils v1.1.0 // indirect
github.com/Masterminds/semver/v3 v3.1.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/uuid v1.1.1 // indirect
github.com/huandu/xstrings v1.3.1 // indirect
github.com/imdario/mergo v0.3.8 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/mitchellh/copystructure v1.0.0 // indirect
github.com/mitchellh/reflectwalk v1.0.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/cast v1.3.1 // indirect
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904 // indirect
golang.org/x/text v0.3.0 // indirect
)
45 changes: 0 additions & 45 deletions go.sum
Original file line number Diff line number Diff line change
@@ -18,11 +18,9 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
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=
@@ -35,14 +33,6 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobuffalo/envy v1.7.0 h1:GlXgaiBkmrYMHco6t4j7SacKO4XUjvh5pwXh0f4uxXU=
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/logger v1.0.0 h1:xw9Ko9EcC5iAFprrjJ6oZco9UpzS5MQ4jAwghsLHdy4=
github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4=
github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q=
github.com/gobuffalo/packr/v2 v2.5.1 h1:TFOeY2VoGamPjQLiNDT3mn//ytzk236VMO2j7iHxJR4=
github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -67,18 +57,11 @@ github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/karrick/godirwalk v1.10.12 h1:BqUm+LuJcXjGv1d2mj3gBiQyrQ57a0rYoAmhvJQ7RDU=
github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -111,16 +94,9 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.1.0 h1:g0fH8RicVgNl+zVZDCDfbdWxAWoAEJyI7I3TZYXFiig=
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
@@ -129,39 +105,28 @@ github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
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/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
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-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4 h1:ydJNl0ENAG67pFbB+9tfhiL2pYqLhfoaZFw/cjLhY4A=
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904 h1:bXoxMPcSLOq08zI3/c5dEBT6lE4eh+jOh886GHrn6V8=
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -176,27 +141,18 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG
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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/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-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200819091447-39769834ee22 h1:YUxhQGxYV280Da2a0XZiHblyJZN6NuXS1f4dahsm0SM=
golang.org/x/sys v0.0.0-20200819091447-39769834ee22/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/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-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@@ -205,7 +161,6 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
12 changes: 7 additions & 5 deletions internal/scaffold/create.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
package scaffold

import (
"embed"
"fmt"
"io"
"os"

"github.com/davidovich/summon/pkg/summon"
"github.com/gobuffalo/packr/v2"
)

//go:embed templates/scaffold/*
var scaffoldFS embed.FS

const scaffoldParams = `{
"ModName": "%s",
"SummonerName": "%s",
"go": ".go"
"go": "go"
}`

// Create will create a folder structure at destination with templates resolved
func Create(destDir, modName, summonerName string, force bool) error {
box := packr.New("Summon scaffold template", "../templates/scaffold")

s, err := summon.New(box)
s, err := summon.New(scaffoldFS)
if err != nil {
return err
}
@@ -33,6 +34,7 @@ func Create(destDir, modName, summonerName string, force bool) error {

_, err = s.Summon(
summon.All(true),
summon.Filename("templates/scaffold"),
summon.JSON(fmt.Sprintf(scaffoldParams, modName, summonerName)),
summon.Dest(destDir),
)
10 changes: 6 additions & 4 deletions internal/scaffold/create_test.go
Original file line number Diff line number Diff line change
@@ -12,6 +12,8 @@ import (
func TestCreateScaffold(t *testing.T) {
assert := assert.New(t)

content := "module example.com/my/assets\n\nrequire github.com/davidovich/summon latest\n"

testCases := []struct {
desc string
args []string
@@ -26,13 +28,13 @@ func TestCreateScaffold(t *testing.T) {
desc: "happy path",
args: []string{".", "example.com/my/assets", "summon"},
file: "go.mod",
content: "module example.com/my/assets",
content: content,
},
{
desc: "output dir",
args: []string{"subdir", "example.com/my/assets", "summon"},
file: "subdir/go.mod",
content: "module example.com/my/assets",
content: content,
},
{
desc: "non empty dir error",
@@ -51,13 +53,13 @@ func TestCreateScaffold(t *testing.T) {
f.Close()
},
file: "summon/go.mod",
content: "module example.com/my/assets",
content: content,
},
{
desc: "named exe",
args: []string{".", "example.com/my/assets", "my-assets"},
file: "go.mod",
content: "module example.com/my/assets",
content: content,
},
{
desc: "README rendered contents",
38 changes: 0 additions & 38 deletions internal/scaffold/packrd/packed-packr.go

This file was deleted.

8 changes: 0 additions & 8 deletions internal/scaffold/scaffold-packr.go

This file was deleted.

12 changes: 12 additions & 0 deletions internal/scaffold/templates/scaffold/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
SUMMONER_NAME := {{ .SummonerName }}

ASSETS := $(shell find $(SUMMONER_NAME)/assets)

all: bin/$(SUMMONER_NAME)

bin/$(SUMMONER_NAME): $(SUMMONER_NAME)/$(SUMMONER_NAME).go $(ASSETS)
go build -o $@ $<

.PHONY: clean
clean:
rm -rf bin
Original file line number Diff line number Diff line change
@@ -1,31 +1,32 @@
Summon Data Provider Repo
=========================

This repository hosts a [{{ .SummonerName }}](https://github.com/davidovich/summon) data
provider.
This repository hosts a [{{ .SummonerName }}](https://github.com/davidovich/summon) data provider.

You install this provider as `{{ .SummonerName }}`:
You install the latest version of this provider as `{{ .SummonerName }}`:

```
go install {{ .ModName }}/{{.SummonerName}}
```shell
go install {{ .ModName }}/{{.SummonerName}}@latest
```

And then use the `{{ .SummonerName }}` executable to summon assets.

Summon `some-asset` like so:

```
```shell
{{ .SummonerName }} some-asset
```

By default, summon will instantiate the asset in the `.summoned/` directory and return its path. This can be overriden in the `asssets/summon.config.yaml` file or by using the `-o` flag.
By default, summon will instantiate the asset in the `.summoned/` directory and
return its path. This can be overriden in the `{{ .SummonerName }}/asssets/summon.config.yaml` file
or by using the `-o` flag.

Get more help with `{{ .SummonerName }} -h`.

Updating assets
---------------

1) Make modifications (additions, removals) in the `assets/` dir
1) Make modifications (additions, removals) in the `{{ .SummonerName }}/assets/` dir
2) Invoke `make`
3) Commit changes
4) Tag with a semantic version (prefix with `v`)
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package main

import (
"os"
"embed"

"github.com/davidovich/summon"
)

// capture the files of the assets tree, assuming the assets directory
// is named "assets".
//go:embed assets/*
var fs embed.FS

func main() {
os.Exit(summon.Main(os.Args, fs))
}
3 changes: 3 additions & 0 deletions internal/scaffold/templates/scaffold/{{.go}}.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module {{ .ModName }}

require github.com/davidovich/summon latest
25 changes: 0 additions & 25 deletions internal/templates/scaffold/Makefile

This file was deleted.

1 change: 0 additions & 1 deletion internal/templates/scaffold/go.mod

This file was deleted.

14 changes: 0 additions & 14 deletions internal/templates/scaffold/{{.SummonerName}}/summon{{.go}}

This file was deleted.

9 changes: 4 additions & 5 deletions main.go
Original file line number Diff line number Diff line change
@@ -15,11 +15,12 @@ This library needs a command entrypoint in a data repository. See https://github
It can be bootstrapped in an empty directory by using:
cd [empty data repo dir]
gobin -run github.com/davidovich/summon/scaffold init [module name]
go run github.com/davidovich/summon/scaffold init [module name]
*/
package summon

import (
"embed"
"fmt"
"os"
"os/exec"
@@ -28,15 +29,13 @@ import (

"github.com/davidovich/summon/cmd"
"github.com/davidovich/summon/pkg/summon"
"github.com/gobuffalo/packr/v2"
)

// Main entrypoint, typically called from a data repository. Calling Main() relinquishes
// control to Summon so it can manage the command line arguments and instantiation of assets
// located in the packr.Box data repository parameter.
// located in the embed.fs data repository parameter.
// Config opts functions are optional.
// See https://github.com/gobuffalo/packr/tree/master/v2 for more information on packr Boxes.
func Main(args []string, box *packr.Box, opts ...option) int {
func Main(args []string, box embed.FS, opts ...option) int {
options := &MainOptions{}

for _, o := range opts {
12 changes: 6 additions & 6 deletions main_test.go
Original file line number Diff line number Diff line change
@@ -4,20 +4,20 @@
package summon_test

import (
"embed"
"os"

"github.com/davidovich/summon"
"github.com/gobuffalo/packr/v2"
)

// fs captures the files of the assets tree
//go:embed assets/*
var fs embed.FS

var exit = os.Exit

// Here is the main() entry-point in summon.go
func Example() {

// box captures the files of the assets tree
box := packr.New("Summon Box", "../assets")

// relinquish control to the summon library
exit(summon.Main(os.Args, box))
exit(summon.Main(os.Args, fs))
}
32 changes: 27 additions & 5 deletions pkg/summon/driver.go
Original file line number Diff line number Diff line change
@@ -2,14 +2,16 @@ package summon

import (
"fmt"
"io"
"io/fs"
"os"
"path"
"text/template"

"github.com/Masterminds/sprig/v3"

"github.com/davidovich/summon/pkg/command"
"github.com/davidovich/summon/pkg/config"
"github.com/gobuffalo/packr/v2"
)

// Summoner is the old name for Driver, use Driver instead.
@@ -22,20 +24,35 @@ var Name = "summon"
type Driver struct {
opts options
Config config.Config
box *packr.Box
box fs.FS
baseDataDir string
templateCtx *template.Template
execCommand command.ExecCommandFn
configRead bool
}

// New creates the Driver.
func New(box *packr.Box, opts ...Option) (*Driver, error) {
func New(box fs.FS, opts ...Option) (*Driver, error) {
d := &Driver{
box: box,
execCommand: command.New,
}

err := d.Configure(opts...)
err := fs.WalkDir(d.box, ".", func(path string, de fs.DirEntry, err error) error {
if path == "." {
return nil
}
if de.IsDir() {
d.baseDataDir = path
return fs.SkipDir
}
return nil
})
if err != nil {
return nil, err
}

err = d.Configure(opts...)
if err != nil {
return nil, err
}
@@ -50,8 +67,13 @@ func (d *Driver) Configure(opts ...Option) error {
}
if !d.configRead {
// try to find a config file in the box
config, err := d.box.Find(config.ConfigFile)
configFile, err := d.box.Open(path.Join(d.baseDataDir, config.ConfigFile))
if err == nil {
defer configFile.Close()
config, err := io.ReadAll(configFile)
if err != nil {
return err
}
err = d.Config.Unmarshal(config)
if err != nil {
return err
29 changes: 25 additions & 4 deletions pkg/summon/list.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package summon

import (
"io/fs"
"path/filepath"
"strings"

@@ -11,16 +12,36 @@ import (
func (d *Driver) List(opts ...Option) ([]string, error) {
d.Configure(opts...)

list := d.box.List()
var list []string
err := fs.WalkDir(d.box, d.baseDataDir, func(path string, de fs.DirEntry, err error) error {
if path == d.baseDataDir {
return nil
}

// old packr.Box List would only produce actual entries, and not intermediate
// entries, simulate that by ignoring dir only entries.
if !de.IsDir() {
rel, err := filepath.Rel(d.baseDataDir, path)
if err != nil {
return err
}
list = append(list, rel)
}
return nil
})

if err != nil {
return nil, err
}

if d.opts.tree {
_, assetDir := filepath.Split(d.box.Path)
assetDir := d.baseDataDir
rootTree := &fileTree{
Tree: gotree.New(assetDir),
children: map[string]*fileTree{},
}
for _, path := range list {
rootTree.addPath(path)
for _, p := range list {
rootTree.addPath(p)
}
return []string{strings.TrimSpace(rootTree.Print())}, nil
}
24 changes: 10 additions & 14 deletions pkg/summon/list_test.go
Original file line number Diff line number Diff line change
@@ -1,35 +1,31 @@
package summon

import (
"io/ioutil"
"os"
"strings"
"testing"
"testing/fstest"

"github.com/gobuffalo/packr/v2"
"github.com/stretchr/testify/assert"
)

func TestSummonerList(t *testing.T) {
dir, _ := ioutil.TempDir("", "")
defer os.RemoveAll(dir)
testFs := fstest.MapFS{}

box := packr.New("test box", dir)
box.AddString("a", "a content")
box.AddString("b", "b content")
testFs["dir/a"] = &fstest.MapFile{Data: []byte("a content")}
testFs["dir/b"] = &fstest.MapFile{Data: []byte("b content")}

s, _ := New(box)
s, _ := New(testFs)
got, _ := s.List()

assert.Equal(t, got, []string{"a", "b"}, "Summoner.List() = %v, want %v", got, []string{"a", "b"})
assert.Equal(t, []string{"a", "b"}, got, "Summoner.List() = %v, want %v", got, []string{"a", "b"})
}

func TestSummonerListTree(t *testing.T) {
box := packr.New("TestSummonerListTree", "nonexisting/../abc")
box.AddString("a/b/c.txt", "")
box.AddString("d", "")
testFs := fstest.MapFS{}
testFs["abc/a/b/c.txt"] = &fstest.MapFile{}
testFs["abc/d"] = &fstest.MapFile{}

s, _ := New(box)
s, _ := New(testFs)

treeList, _ := s.List(ShowTree(true))

5 changes: 1 addition & 4 deletions pkg/summon/options_test.go
Original file line number Diff line number Diff line change
@@ -3,14 +3,11 @@ package summon
import (
"testing"

"github.com/gobuffalo/packr/v2"
"github.com/stretchr/testify/assert"
)

func TestBoxedConfig(t *testing.T) {
box := packr.New("testBoxedConfig", "testdata")

s, _ := New(box)
s, _ := New(summonTestFS)

assert.Equal(t, "overridden_dir", s.opts.destination)
}
8 changes: 2 additions & 6 deletions pkg/summon/run_test.go
Original file line number Diff line number Diff line change
@@ -7,14 +7,12 @@ import (
"path/filepath"
"testing"

"github.com/gobuffalo/packr/v2"
"github.com/stretchr/testify/assert"

"github.com/davidovich/summon/internal/testutil"
)

func TestRun(t *testing.T) {
box := packr.New("test run box", "testdata")

tests := []struct {
name string
@@ -116,7 +114,7 @@ func TestRun(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s, err := New(box, Ref(tt.ref))
s, err := New(summonTestFS, Ref(tt.ref))
assert.Nil(t, err)

stdout := &bytes.Buffer{}
@@ -166,9 +164,7 @@ func TestSubCommandTemplateRunCall(t *testing.T) {
}

func TestListInvocables(t *testing.T) {
box := packr.New("test run box", "testdata")

s, _ := New(box)
s, _ := New(summonTestFS)

inv := s.ListInvocables()
assert.ElementsMatch(t, []string{"hello-bash", "bash-self-ref", "run-example", "docker", "gobin", "gohack", "hello", "args", "one-arg", "all-args", "osArgs", "templateref"}, inv)
76 changes: 51 additions & 25 deletions pkg/summon/summon.go
Original file line number Diff line number Diff line change
@@ -9,15 +9,15 @@ import (
"bytes"
"fmt"
"io"
"io/fs"
"io/ioutil"
"net/http"
"os"
"path"
"path/filepath"
"strings"
"text/template"

"github.com/Masterminds/sprig/v3"
"github.com/gobuffalo/packr/v2/file"
"github.com/spf13/afero"

"github.com/davidovich/summon/internal/testutil"
@@ -47,29 +47,57 @@ func (d *Driver) Summon(opts ...Option) (string, error) {
}

if d.opts.all {
return destination, d.box.Walk(func(path string, info file.File) error {
_, err := d.copyOneFile(info, "")
return err
})
startdir := filepath.Clean(d.opts.filename)
if d.opts.filename == "" {
startdir = d.baseDataDir
}

return destination, fs.WalkDir(d.box, startdir, makeCopyFileFun(startdir, d))
}

filename := filepath.Clean(d.opts.filename)
filename = d.resolveAlias(filename)

// User wants to extract a subdirectory
if d.box.HasDir(filename) {
return destination,
d.box.WalkPrefix(filename, func(path string, info file.File) error {
_, err := d.copyOneFile(info, filename)
return err
})
}
filename = path.Join(d.baseDataDir, filename)

boxedFile, err := d.box.Open(filename)
if err != nil {
return "", err
}
return d.copyOneFile(boxedFile, "")
stat, err := boxedFile.Stat()
if err != nil {
return "", err
}
if stat.IsDir() {
// User wants to extract a subdirectory
startdir := filename
return destination,
fs.WalkDir(d.box, startdir, makeCopyFileFun(startdir, d))
}

return d.copyOneFile(boxedFile, filename, d.baseDataDir)
}

func makeCopyFileFun(startdir string, d *Driver) func(path string, de fs.DirEntry, _ error) error {
return func(path string, de fs.DirEntry, _ error) error {
if de.IsDir() {
return nil
}
file, err := d.box.Open(path)
if err != nil {
return err
}
rel, err := filepath.Rel(d.baseDataDir, path)
if err != nil {
return err
}
subdir, err := filepath.Rel(d.baseDataDir, startdir)
if err != nil {
return err
}

_, err = d.copyOneFile(file, rel, subdir)
return err
}
}

func (d *Driver) renderTemplate(tmpl string, data map[string]interface{}) (string, error) {
@@ -156,23 +184,18 @@ func summonFuncMap(d *Driver) template.FuncMap {
}
}

func (d *Driver) copyOneFile(boxedFile http.File, rootDir string) (string, error) {
func (d *Driver) copyOneFile(boxedFile fs.File, filename, root string) (string, error) {
destination := d.opts.destination
// Write the file and print it'd path
stat, err := boxedFile.Stat()
if err != nil {
return "", err
}
filename := stat.Name()

if !d.opts.raw {
var err error
filename, err = d.renderTemplate(filename, d.opts.data)
if err != nil {
return "", err
}
}

filename, err = filepath.Rel(rootDir, filename)
filename, err := filepath.Rel(root, filename)
if err != nil {
return "", err
}
@@ -183,7 +206,7 @@ func (d *Driver) copyOneFile(boxedFile http.File, rootDir string) (string, error
out = d.opts.out
} else {
summonedFile = filepath.Join(destination, filename)
err = appFs.MkdirAll(filepath.Dir(summonedFile), os.ModePerm)
err := appFs.MkdirAll(filepath.Dir(summonedFile), os.ModePerm)
if err != nil {
return "", err
}
@@ -197,6 +220,9 @@ func (d *Driver) copyOneFile(boxedFile http.File, rootDir string) (string, error
}

boxedContent, err := ioutil.ReadAll(boxedFile)
if err != nil {
return "", err
}

var rendered string
if d.opts.raw {
39 changes: 19 additions & 20 deletions pkg/summon/summon_test.go
Original file line number Diff line number Diff line change
@@ -2,22 +2,23 @@ package summon

import (
"bytes"
"embed"
"path/filepath"
"testing"
"testing/fstest"

"github.com/davidovich/summon/internal/testutil"
"github.com/davidovich/summon/pkg/config"
"github.com/spf13/afero"

"github.com/gobuffalo/packr/v2"
"github.com/stretchr/testify/assert"
)

func TestErrorOnMissingFiles(t *testing.T) {
defer testutil.ReplaceFs()()
//go:embed testdata/*
var summonTestFS embed.FS

box := packr.New("test box", t.TempDir())
s, _ := New(box, Filename("missing"))
func TestErrorOnMissingFiles(t *testing.T) {
s, _ := New(embed.FS{}, Filename("missing"))
path, err := s.Summon()

assert.NotNil(t, err)
@@ -27,12 +28,11 @@ func TestErrorOnMissingFiles(t *testing.T) {
func TestMultifileInstanciation(t *testing.T) {
defer testutil.ReplaceFs()()

box := packr.New("test box multifile", t.TempDir())

box.AddString("text.txt", "this is a text")
box.AddString("another.txt", "another text")
testFs := fstest.MapFS{}
testFs["assets/text.txt"] = &fstest.MapFile{Data: []byte("this is a text")}
testFs["assets/another.txt"] = &fstest.MapFile{Data: []byte("another text")}

s, _ := New(box, All(true))
s, _ := New(testFs, All(true))

path, err := s.Summon()
assert.Nil(t, err)
@@ -50,11 +50,11 @@ func TestOneFileInstanciation(t *testing.T) {

a := assert.New(t)

box := packr.New("t1", t.TempDir())
box.AddString("text.txt", "this is a text")
testFs := fstest.MapFS{}
testFs["text.txt"] = &fstest.MapFile{Data: []byte("this is a text")}

// create a summoner to summon text.txt at
s, err := New(box, Filename("text.txt"), Dest(config.DefaultOutputDir))
s, err := New(testFs, Filename("text.txt"), Dest(config.DefaultOutputDir))
a.NoError(err)

path, err := s.Summon()
@@ -71,10 +71,8 @@ func TestSubfolderHierarchy(t *testing.T) {
defer testutil.ReplaceFs()()
a := assert.New(t)

box := packr.New("hierarchy", "testdata")

// create a summoner to summon a complete hierarchy
s, err := New(box, Filename("subdir/"), Dest("o"), JSON(`{"TemplatedName":"b", "Content":"b content"}`))
s, err := New(summonTestFS, Filename("subdir/"), Dest("o"), JSON(`{"TemplatedName":"b", "Content":"b content"}`))
a.NoError(err)

path, err := s.Summon()
@@ -160,22 +158,23 @@ func TestSummonScenarios(t *testing.T) {
},
}

box := packr.New("TestTemplateRendering", "testdata")

for _, tC := range testCases {
for _, tC := range testCases[len(testCases)-1:] {
t.Run(tC.desc, func(t *testing.T) {
args := []Option{Filename(tC.filename), JSON(tC.json), Dest(tC.dest), Raw(tC.raw)}
output := &bytes.Buffer{}
if tC.dest == "-" {
args = append(args, out(output))
}
s, err := New(box, args...)
s, err := New(summonTestFS, args...)
assert.NotNil(s)

if tC.wantError {
assert.Error(err)
} else {
assert.NoError(err)
}
path, err := s.Summon()
assert.NoError(err)

assert.Equal(tC.expectedFileName, path)
var b []byte
15 changes: 10 additions & 5 deletions scaffold/scaffold.go
Original file line number Diff line number Diff line change
@@ -3,10 +3,9 @@ Command scaffold is used to bootstrap a data provider in an empty directory.
Basics
Invoke the scaffolder by using gobin -run in an empty directory. gobin can be
installed from https://github.com/myitcv/gobin:
Invoke the scaffolder by using go run in an empty directory:
$ gobin -run github.com/davidovich/summon/scaffold init [go module name]
$ go run github.com/davidovich/summon/scaffold@latest init [go module name]
Where [go module name] is replaced by the path to the go module of the data
repo. For example, github.com/davidovich/summon-example-assets was used to
@@ -16,7 +15,7 @@ Help
The scaffold command has a help:
$ gobin -run github.com/davidovich/summon/scaffold -h
$ go run github.com/davidovich/summon/scaffold@latest -h
initialize an asset directory managed by summon
Usage:
@@ -38,6 +37,7 @@ import (

"github.com/davidovich/summon/internal/scaffold"
"github.com/davidovich/summon/pkg/command"
"github.com/davidovich/summon/pkg/summon"
"github.com/spf13/cobra"
)

@@ -82,13 +82,18 @@ func newMainCmd() *cobra.Command {
gitcmd := execCmd(git, "-C", dest, "init")
gitcmd.Stdout = os.Stdout
_ = gitcmd.Run()

gocmd := execCmd("go", "mod", "tidy")
gocmd.Dir = dest
gocmd.Stdout = os.Stdout
_ = gocmd.Run()
}
return err
},
}

initCmd.Flags().StringVarP(&dest, "out", "o", ".", "destination directory")
initCmd.Flags().StringVarP(&summonName, "name", "n", "summon", "summon executable name")
initCmd.Flags().StringVarP(&summonName, "name", "n", summon.Name, "summon executable name")
initCmd.Flags().BoolVarP(&force, "force", "f", false, "force overwrite")

rootCmd.AddCommand(initCmd)
2 changes: 1 addition & 1 deletion scaffold/scaffold_test.go
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@ func TestScaffolder(t *testing.T) {
desc: "happy path",
args: []string{"init", "example.com/my/assets"},
file: "go.mod",
content: "module example.com/my/assets/summon",
content: "module example.com/my/assets\n\nrequire github.com/davidovich/summon latest\n",
},
{
desc: "non empty dir error",

0 comments on commit f5d6cb0

Please sign in to comment.