Merge pull request #10373 from hashicorp/makefile_changes

Modify struct-markdown generator code to work from different projct roots
This commit is contained in:
Megan Marsh 2020-12-11 16:06:13 -08:00 committed by GitHub
commit d8277aa455
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 493 additions and 59 deletions

View File

@ -1,6 +1,7 @@
TEST?=$(shell go list ./...)
COUNT?=1
VET?=$(shell go list ./...)
ACC_TEST_BUILDERS?=all
ACC_TEST_PROVISIONERS?=all
# Get the current full sha from git
@ -56,7 +57,6 @@ install-gen-deps: ## Install dependencies for code generation
# out code dependencies; so a go mod tidy will remove them again. `go
# install` seems to install the last tagged version and we want to install
# master.
@(cd $(TEMPDIR) && GO111MODULE=on go get github.com/mna/pigeon@master)
@(cd $(TEMPDIR) && GO111MODULE=on go get github.com/alvaroloes/enumer@master)
@go install ./cmd/struct-markdown
@go install ./cmd/mapstructure-to-hcl2
@ -120,13 +120,11 @@ fmt-examples:
# generate runs `go generate` to build the dynamically generated
# source files.
generate: install-gen-deps ## Generate dynamically generated code
@echo "==> removing autogenerated markdown..."
@find website/pages/ -type f | xargs grep -l '^<!-- Code generated' | xargs rm -f
@echo "==> removing autogenerated markdown..." # but don't remove partials generated in the SDK and copied over.
@find website/pages -path website/pages/partials/packer-plugin-sdk -prune -o -type f | xargs grep -l '^<!-- Code generated' | xargs rm -f
@echo "==> removing autogenerated code..."
@find post-processor packer-plugin-sdk helper builder provisioner -type f | xargs grep -l '^// Code generated' | xargs rm -f
go generate ./...
go fmt packer-plugin-sdk/bootcommand/boot_command.go
go run ./cmd/generate-fixer-deprecations
@find post-processor helper builder provisioner -type f | xargs grep -l '^// Code generated' | xargs rm -f
PROJECT_ROOT="$(shell pwd)" go generate $(shell go list ./... | grep -v packer-plugin-sdk)
generate-check: generate ## Check go code generation is on par
@echo "==> Checking that auto-generated code is not changed..."

View File

@ -27,8 +27,16 @@ func main() {
if err != nil {
panic(err)
}
paths := strings.SplitAfter(absFilePath, "packer"+string(os.PathSeparator))
packerDir := paths[0]
projectRoot := os.Getenv("PROJECT_ROOT")
var paths []string
if projectRoot == "" {
// fall back to the packer root.
paths = strings.SplitAfter(absFilePath, "packer"+string(os.PathSeparator))
projectRoot = paths[0]
} else {
paths = strings.SplitAfter(absFilePath, projectRoot+string(os.PathSeparator))
}
builderName, _ := filepath.Split(paths[1])
builderName = strings.Trim(builderName, string(os.PathSeparator))
@ -144,7 +152,7 @@ func main() {
}
}
dir := filepath.Join(packerDir, "website", "pages", "partials", builderName)
dir := filepath.Join(projectRoot, "website", "pages", "partials", builderName)
os.MkdirAll(dir, 0755)
for _, str := range []Struct{header, required, notRequired} {

View File

@ -1,7 +1,6 @@
// This is the main package for the `packer` application.
//go:generate go run ./scripts/generate-plugins.go
//go:generate go generate ./packer-plugin-sdk/bootcommand/...
package main
import (

108
packer-plugin-sdk/Makefile Normal file
View File

@ -0,0 +1,108 @@
TEST?=$(shell go list ./...)
COUNT?=1
VET?=$(shell go list ./...)
# Get the current full sha from git
GOPATH=$(shell go env GOPATH)
default: install-build-deps install-gen-deps generate
ci: testrace ## Test in continuous integration
install-gen-deps: ## Install dependencies for code generation
# to avoid having to tidy our go deps, we `go get` our binaries from a temp
# dir. `go get` will change our deps and the following deps are not part of
# out code dependencies; so a go mod tidy will remove them again. `go
# install` seems to install the last tagged version and we want to install
# master.
@(cd $(TEMPDIR) && GO111MODULE=on go get github.com/mna/@master)
@(cd $(TEMPDIR) && GO111MODULE=on go get github.com/alvaroloes/enumer@master)
# grab files from github and install them using go install, then remove files again.
@mkdir cmd
@mkdir cmd/struct-markdown
@curl -sSfL -q https://raw.githubusercontent.com/hashicorp/packer/master/cmd/struct-markdown/main.go -o cmd/struct-markdown/main.go
@curl -sSfL -q https://raw.githubusercontent.com/hashicorp/packer/master/cmd/struct-markdown/template.go -o cmd/struct-markdown/template.go
@go install ./cmd/struct-markdown # in the packer repo
@mkdir cmd/mapstructure-to-hcl2
@curl -sSfL -q https://raw.githubusercontent.com/hashicorp/packer/master/cmd/mapstructure-to-hcl2/mapstructure-to-hcl2.go -o cmd/mapstructure-to-hcl2/mapstructure-to-hcl2.go
@go install ./cmd/mapstructure-to-hcl2 # in the packer repo
@rm -rf cmd
install-lint-deps: ## Install linter dependencies
# Pinning golangci-lint at v1.23.8 as --new-from-rev seems to work properly; the latest 1.24.0 has caused issues with memory consumption
@echo "==> Updating linter dependencies..."
@curl -sSfL -q https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOPATH)/bin v1.23.8
lint: install-lint-deps ## Lint Go code
@if [ ! -z $(PKG_NAME) ]; then \
echo "golangci-lint run ./$(PKG_NAME)/..."; \
golangci-lint run ./$(PKG_NAME)/...; \
else \
echo "golangci-lint run ./..."; \
golangci-lint run ./...; \
fi
ci-lint: install-lint-deps ## On ci only lint newly added Go source files
@echo "==> Running linter on newly added Go source files..."
GO111MODULE=on golangci-lint run --new-from-rev=$(shell git merge-base origin/master HEAD) ./...
fmt: ## Format Go code
@go fmt ./...
fmt-check: fmt ## Check go code formatting
@echo "==> Checking that code complies with go fmt requirements..."
@git diff --exit-code; if [ $$? -eq 1 ]; then \
echo "Found files that are not fmt'ed."; \
echo "You can use the command: \`make fmt\` to reformat code."; \
exit 1; \
fi
fmt-docs:
@find ./website/pages/docs -name "*.md" -exec pandoc --wrap auto --columns 79 --atx-headers -s -f "markdown_github+yaml_metadata_block" -t "markdown_github+yaml_metadata_block" {} -o {} \;
# Install js-beautify with npm install -g js-beautify
fmt-examples:
find examples -name *.json | xargs js-beautify -r -s 2 -n -eol "\n"
# generate runs `go generate` to build the dynamically generated
# source files.
generate: install-gen-deps ## Generate dynamically generated code
@echo "==> removing autogenerated markdown..."
@find website/pages/ -type f | xargs grep -l '^<!-- Code generated' | xargs rm -f
@echo "==> removing autogenerated code..."
@find ./ -type f | xargs grep -l '^// Code generated' | xargs rm -f
PROJECT_ROOT="$(pwd)" go generate ./...
go fmt bootcommand/boot_command.go
# go run ./cmd/generate-fixer-deprecations
generate-check: generate ## Check go code generation is on par
@echo "==> Checking that auto-generated code is not changed..."
@git diff --exit-code; if [ $$? -eq 1 ]; then \
echo "Found diffs in go generated code."; \
echo "You can use the command: \`make generate\` to reformat code."; \
echo "ONCE YOU HAVE REGENERATED CODE, IT SHOULD BE COPIED INTO PACKER CORE"; \
exit 1; \
fi
test: mode-check vet ## Run unit tests
@go test -count $(COUNT) $(TEST) $(TESTARGS) -timeout=3m
testrace: mode-check vet ## Test with race detection enabled
@GO111MODULE=off go test -count $(COUNT) -race $(TEST) $(TESTARGS) -timeout=3m -p=8
# Runs code coverage and open a html page with report
cover:
go test -count $(COUNT) $(TEST) $(TESTARGS) -timeout=3m -coverprofile=coverage.out
go tool cover -html=coverage.out
rm coverage.out
vet: ## Vet Go code
@go vet $(VET) ; if [ $$? -eq 1 ]; then \
echo "ERROR: Vet found problems in the code."; \
exit 1; \
fi
help:
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

View File

@ -0,0 +1,58 @@
# Packer Plugin SDK
This SDK enables building Packer plugins. This allows Packer's users to use both the officially-supported builders, provisioners, and post-processors, and custom in-house solutions.
Packer itself is a tool for building identical machine images for multiple platforms from a single source configuration. You can find more about Packer on its [website](https://www.packer.io) and [its GitHub repository](https://github.com/hashicorp/packer).
## Packer CLI Compatibility
Packer v1.7.0 or later is needed for this SDK. Versions of Packer prior to that release are still compatible with third-party plugins, but the plugins should use the plugin tooling from inside earlier versions of Packer to ensure complete API compatibility.
## Go Compatibility
The Packer Plugin SDK is built in Go, and uses the [support policy](https://golang.org/doc/devel/release.html#policy) of Go as its support policy. The two latest major releases of Go are supported by the SDK.
Currently, that means Go **1.14** or later must be used when building a provider with the SDK.
## Getting Started
See the [Extending Packer](https://www.packer.io/docs/extending) docs for a guided tour of plugin development.
## Documentation
See the [Extending Packer](https://www.packer.io/docs/extending) section on the Packer website.
## Packer Scope (Plugins VS Core)
### Packer Core
- acts as an RPC _client_
- interacts with the user
- parses (HCL/JSON) configuration
- manages build as whole, asks **plugin(s)** to manage the image lifecycle and modify the image being built.
- discovers **plugin(s)** and their versions per configuration
- manages **plugin** lifecycles (i.e. spins up & tears down plugin process)
- passes relevant parts of parsed (valid JSON/HCL) and interpolated configuration to **plugin(s)**
### Packer Provider (via this SDK)
- acts as RPC _server_
- executes any domain-specific logic based on received parsed configuration. For builders this includes managing the vm lifecycle on a give hypervisor or cloud; for provisioners this involves calling the operation on the remote instance.
- tests domain-specific logic via provided acceptance test framework
- provides **Core** with template validation, artifact information, and information about whether the plugin process succeeded or failed.
## Migrating to SDK from built-in SDK
Migrating to the standalone SDK v1 is covered on the [Plugin SDK section](https://www.packer.io/docs/extend/plugin-sdk.html) of the website.
## Versioning
The Packer Plugin SDK is a [Go module](https://github.com/golang/go/wiki/Modules) versioned using [semantic versioning](https://semver.org/).
## Contributing
See [`.github/CONTRIBUTING.md`](https://github.com/hashicorp/packer-plugin-sdk/blob/master/.github/CONTRIBUTING.md)
## License
[Mozilla Public License v2.0](https://github.com/hashicorp/Packer-plugin-sdk/blob/master/LICENSE)

View File

@ -0,0 +1,244 @@
/*
The acctest package provides an acceptance testing framework for testing
builders and provisioners.
Writing Provisioner Acceptance Tests
Packer has implemented a `ProvisionerTestCase` structure to help write
provisioner acceptance tests.
```go
type ProvisionerTestCase struct {
// Check is called after this step is executed in order to test that
// the step executed successfully. If this is not set, then the next
// step will be called
Check func(*exec.Cmd, string) error
// IsCompatible checks whether a provisioner is able to run against a
// given builder type and guest operating system, and returns a boolean.
// if it returns true, the test combination is okay to run. If false, the
// test combination is not okay to run.
IsCompatible func(builderType string, BuilderGuestOS string) bool
// Name is the name of the test case. Be simple but unique and descriptive.
Name string
// Setup, if non-nil, will be called once before the test case
// runs. This can be used for some setup like setting environment
// variables, or for validation prior to the
// test running. For example, you can use this to make sure certain
// binaries are installed, or text fixtures are in place.
Setup func() error
// Teardown will be called before the test case is over regardless
// of if the test succeeded or failed. This should return an error
// in the case that the test can't guarantee all resources were
// properly cleaned up.
Teardown builderT.TestTeardownFunc
// Template is the provisioner template to use.
// The provisioner template fragment must be a json-formatted string
// containing the provisioner definition but no other portions of a packer
// template. For
// example:
//
// ```json
// {
// "type": "shell-local",
// "inline", ["echo hello world"]
// }
//```
//
// is a valid entry for "template" here, but the complete Packer template:
//
// ```json
// {
// "provisioners": [
// {
// "type": "shell-local",
// "inline", ["echo hello world"]
// }
// ]
// }
// ```
//
// is invalid as input.
//
// You may provide multiple provisioners in the same template. For example:
// ```json
// {
// "type": "shell-local",
// "inline", ["echo hello world"]
// },
// {
// "type": "shell-local",
// "inline", ["echo hello world 2"]
// }
// ```
Template string
// Type is the type of provisioner.
Type string
}
```
To start writing a new provisioner acceptance test, you should add a test file
named `provisioner_acc_test.go` in the same folder as your provisioner is
defined. Create a test case by implementing the above struct, and run it
by calling `provisioneracc.TestProvisionersAgainstBuilders(testCase, t)`
The following example has been adapted from a shell-local provisioner test:
```
import (
"github.com/hashicorp/packer/packer-plugin-sdk/acctest/provisioneracc"
"github.com/hashicorp/packer/packer-plugin-sdk/acctest/testutils"
)
// ...
func TestAccShellProvisioner_basic(t *testing.T) {
// Create a json template fragment containing just the provisioners you want
// to run.
templateString := `{
"type": "shell-local",
"script": "test-fixtures/script.sh",
"max_retries" : 5
}`
// instantiate a test case.
testCase := &provisioneracc.ProvisionerTestCase{
IsCompatible: func() bool {return true},
Name: "shell-local-provisioner-basic",
Teardown: func() error {
testutils.CleanupFiles("test-fixtures/file.txt")
return nil
},
Template: templateString,
Type: "shell-local",
Check: func(buildcommand *exec.Cmd, logfile string) error {
if buildcommand.ProcessState != nil {
if buildcommand.ProcessState.ExitCode() != 0 {
return fmt.Errorf("Bad exit code. Logfile: %s", logfile)
}
}
filecontents, err := loadFile("file.txt")
if err != nil {
return err
}
if !strings.Contains(filecontents, "hello") {
return fmt.Errorf("file contents were wrong: %s", filecontents)
}
return nil
},
}
provisioneracc.TestProvisionersAgainstBuilders(testCase, t)
}
```
After writing the struct and implementing the interface, now is time to write the test that will run all
of this code you wrote. Your test should be like:
```go
func TestShellProvisioner(t *testing.T) {
acc.TestProvisionersPreCheck("shell", t)
acc.TestProvisionersAgainstBuilders(new(ShellProvisionerAccTest), t)
}
```
The method `TestProvisionersAgainstBuilders` will run the provisioner against
all available and compatible builders. If there are not builders compatible with
the test you want to run, you can add a builder using the following steps:
Create a subdirectory in provisioneracc/test-fixtures for the type of builder
you are adding. In this subdirectory, add one json file containing a single
builder fragment. For example, one of our amazon-ebs builders is defined in
provisioneracc/test-fixtures/amazon-ebs/amazon-ebs.txt and contains:
```json
{
"type": "amazon-ebs",
"ami_name": "packer-acc-test",
"instance_type": "t2.micro",
"region": "us-east-1",
"ssh_username": "ubuntu",
"source_ami_filter": {
"filters": {
"virtualization-type": "hvm",
"name": "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*",
"root-device-type": "ebs"
},
"owners": ["099720109477"],
"most_recent": true
},
"force_deregister" : true,
"tags": {
"packer-test": "true"
}
}
```
note that this fragment does not contain anything other than a single builder
definition. The testing framework will combine this with the provisioner
fragment to create a working json template.
In order to tell the testing framework how to use this builder fragment, you
need to implement a `BuilderFixture` struct:
```go
type BuilderFixture struct {
// Name is the name of the builder fixture.
// Be simple and descriptive.
Name string
// Setup creates necessary extra test fixtures, and renders their values
// into the BuilderFixture.Template.
Setup func()
// Template is the path to a builder template fragment.
// The builder template fragment must be a json-formatted file containing
// the builder definition but no other portions of a packer template. For
// example:
//
// ```json
// {
// "type": "null",
// "communicator", "none"
// }
//```
//
// is a valid entry for "template" here, but the complete Packer template:
//
// ```json
// {
// "builders": [
// "type": "null",
// "communicator": "none"
// ]
// }
// ```
//
// is invalid as input.
//
// Only provide one builder template fragment per file.
TemplatePath string
// GuestOS says what guest os type the builder template fragment creates.
// Valid values are "windows", "linux" or "darwin" guests.
GuestOS string
// HostOS says what host os type the builder is capable of running on.
// Valid values are "any", windows", or "posix". If you set "posix", then
// this builder can run on a "linux" or "darwin" platform. If you set
// "any", then this builder can be used on any platform.
HostOS string
Teardown builderT.TestTeardownFunc
}
```
Implement this struct to the file "provisioneracc/builders.go", then add
the new implementation to the `BuildersAccTest` map in
`provisioneracc/provisioners.go`
Once you finish these steps, you should be ready to run your new provisioner
acceptance test by setting the name used in the BuildersAccTest map as your
`ACC_TEST_BUILDERS` environment variable.
*/
package acctest

View File

@ -1,9 +1,20 @@
/*
The provisioneracc package creates a framework for provisioner acceptance
testing. For builder acceptance testing, use the top level tooling in the
acctest package.
*/
package provisioneracc
import (
"github.com/hashicorp/packer/packer-plugin-sdk/acctest/testutils"
)
// Variables stored in this file represent implementations of the BuilderFixture
// struct inside of provisioners.go
// AmasonEBSBuilderFixtureLinux points to a build stub of a simple amazon-ebs
// build running on a linux operating system.
var AmasonEBSBuilderFixtureLinux = &BuilderFixture{
Name: "Amazon-ebs Linux builder",
TemplatePath: "amazon-ebs/amazon-ebs.txt",
@ -20,6 +31,8 @@ var AmasonEBSBuilderFixtureLinux = &BuilderFixture{
},
}
// AmasonEBSBuilderFixtureWindows points to a build stub of a simple amazon-ebs
// build running on a Windows operating system.
var AmasonEBSBuilderFixtureWindows = &BuilderFixture{
Name: "Amazon-ebs Windows builder",
TemplatePath: "amazon-ebs/amazon-ebs_windows.txt",
@ -36,7 +49,9 @@ var AmasonEBSBuilderFixtureWindows = &BuilderFixture{
},
}
var VirtualboxBuilderFixtureWindows = &BuilderFixture{
// VirtualboxBuilderFixtureLinux points to a build stub of a simple amazon-ebs
// build running on a linux operating system.
var VirtualboxBuilderFixtureLinux = &BuilderFixture{
Name: "Virtualbox Windows builder",
TemplatePath: "virtualbox/virtualbox-iso.txt",
GuestOS: "linux",

View File

@ -1,43 +0,0 @@
package provisioneracc
import (
"bytes"
"testing"
amazonebsbuilder "github.com/hashicorp/packer/builder/amazon/ebs"
"github.com/hashicorp/packer/command"
"github.com/hashicorp/packer/packer"
packersdk "github.com/hashicorp/packer/packer-plugin-sdk/packer"
fileprovisioner "github.com/hashicorp/packer/provisioner/file"
"github.com/hashicorp/packer/provisioner/shell"
)
// testCoreConfigBuilder creates a packer CoreConfig that has a file builder
// available. This allows us to test a builder that writes files to disk.
func testCoreConfigBuilder(t *testing.T) *packer.CoreConfig {
components := packer.ComponentFinder{
BuilderStore: packersdk.MapOfBuilder{
"amazon-ebs": func() (packersdk.Builder, error) { return &amazonebsbuilder.Builder{}, nil },
},
ProvisionerStore: packersdk.MapOfProvisioner{
"shell": func() (packersdk.Provisioner, error) { return &shell.Provisioner{}, nil },
"file": func() (packersdk.Provisioner, error) { return &fileprovisioner.Provisioner{}, nil },
},
PostProcessorStore: packersdk.MapOfPostProcessor{},
}
return &packer.CoreConfig{
Components: components,
}
}
// TestMetaFile creates a Meta object that includes a file builder
func TestMetaFile(t *testing.T) command.Meta {
var out, err bytes.Buffer
return command.Meta{
CoreConfig: testCoreConfigBuilder(t),
Ui: &packersdk.BasicUi{
Writer: &out,
ErrorWriter: &err,
},
}
}

View File

@ -287,7 +287,7 @@ func writeJsonTemplate(out *bytes.Buffer, filePath string, t *testing.T) {
outputFile.Sync()
}
// BuilderAcceptance is specialized tooling implemented by individual builders
// BuilderAcceptance is specialized tooling implemented by individual builders.
// To add your builder to the provisioner testing framework, create a struct
// that implements this interface, add it to the BuildersAccTest map below.
// TODO add this interface to the plugin server so that Packer can request it
@ -333,6 +333,6 @@ type BuilderAcceptance interface {
// Mapping of all builder fixtures defined for a given builder type.
var BuildersAccTest = map[string][]*BuilderFixture{
"virtualbox-iso": []*BuilderFixture{VirtualboxBuilderFixtureWindows},
"virtualbox-iso": []*BuilderFixture{VirtualboxBuilderFixtureLinux},
"amazon-ebs": []*BuilderFixture{AmasonEBSBuilderFixtureLinux, AmasonEBSBuilderFixtureWindows},
}

View File

@ -2,7 +2,7 @@ package testutils
import "os"
// CleanupFiles removes all files in the given strings.
// CleanupFiles removes all the provided filenames.
func CleanupFiles(moreFiles ...string) {
for _, file := range moreFiles {
os.RemoveAll(file)

View File

@ -1,8 +1,14 @@
/*
Package adapter helps command line tools connect to the guest via a Packer
communicator. A typical use is for custom provisioners that wrap command line
communicator.
A typical use is for custom provisioners that wrap command line
tools. For example, the Ansible provisioner and the Inspec provisioner both
use this package to proxy communicator calls.
You may want to use this adapter if you are writing a provisioner that wraps a
tool which under normal usage would be run locally and form a connection to the
remote instance itself.
*/
package adapter

View File

@ -0,0 +1,41 @@
module github.com/hashicorp/packer-plugin-sdk
require (
github.com/aws/aws-sdk-go v1.36.5
github.com/dylanmei/winrmtest v0.0.0-20190225150635-99b7fe2fddf1
github.com/fatih/camelcase v1.0.0
github.com/fatih/structtag v1.0.0
github.com/gofrs/flock v0.8.0
github.com/google/go-cmp v0.5.2
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/google/uuid v1.1.2
github.com/hashicorp/consul/api v1.8.0
github.com/hashicorp/go-getter/gcs/v2 v2.0.0-20200604122502-a6995fa1edad
github.com/hashicorp/go-getter/s3/v2 v2.0.0-20200604122502-a6995fa1edad
github.com/hashicorp/go-getter/v2 v2.0.0-20200604122502-a6995fa1edad
github.com/hashicorp/go-multierror v1.1.0
github.com/hashicorp/go-version v1.2.0
github.com/hashicorp/hcl/v2 v2.8.0
github.com/hashicorp/packer v1.6.5
github.com/hashicorp/vault/api v1.0.4
github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce
github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869
github.com/masterzen/winrm v0.0.0-20201030141608-56ca5c5f2380
github.com/mitchellh/go-fs v0.0.0-20180402235330-b7b9ca407fff
github.com/mitchellh/iochan v1.0.0
github.com/mitchellh/mapstructure v1.4.0
github.com/mitchellh/reflectwalk v1.0.1
github.com/packer-community/winrmcp v0.0.0-20180921211025-c76d91c1e7db
github.com/pkg/sftp v1.12.0
github.com/ryanuber/go-glob v1.0.0
github.com/stretchr/testify v1.6.1
github.com/ugorji/go v0.0.0-20151218193438-646ae4a518c1
github.com/zclconf/go-cty v1.7.0
golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9
golang.org/x/mobile v0.0.0-20201208152944-da85bec010a2
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
golang.org/x/tools v0.0.0-20200918232735-d647fc253266
)
go 1.14