Merge pull request #73 from Azure/dev

v0.1.5
This commit is contained in:
Martin Strobel 2018-07-09 17:34:51 -07:00 коммит произвёл GitHub
Родитель 578d16f4ec 0d9fee5e94
Коммит 16c74dff1d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
10 изменённых файлов: 603 добавлений и 92 удалений

73
Gopkg.lock сгенерированный
Просмотреть файл

@ -15,8 +15,8 @@
"services/resources/mgmt/2017-05-10/resources",
"version"
]
revision = "cd93ccfe0395e70031704ca68f14606588eec120"
version = "v17.3.0"
revision = "7971189ecf5a584b9211f2527737f94bb979644e"
version = "v17.4.0"
[[projects]]
name = "github.com/Azure/go-autorest"
@ -28,8 +28,8 @@
"autorest/to",
"autorest/validation"
]
revision = "76796dcb80ab6491bf22e344402023c081a7a282"
version = "v10.11.1"
revision = "1f7cd6cfe0adea687ad44a512dfe76140f804318"
version = "v10.12.0"
[[projects]]
branch = "master"
@ -90,8 +90,17 @@
[[projects]]
name = "github.com/gobuffalo/envy"
packages = ["."]
revision = "ef60bfc50c8f92d1ee64674d8ce7a48f1f67625e"
version = "v1.6.2"
revision = "2d0f467653f3d961ce9ada4d32a230bdcb3bfe11"
version = "v1.6.3"
[[projects]]
name = "github.com/gobuffalo/fizz"
packages = [
".",
"translators"
]
revision = "25461ee937655cd1136523f6653d5bd15343cc48"
version = "v1.0.1"
[[projects]]
name = "github.com/gobuffalo/makr"
@ -114,8 +123,8 @@
"parser",
"token"
]
revision = "b0b0a05f963a529b49d835f868fa1e2b92f4b144"
version = "v3.7.4"
revision = "2ec029f415ed9a8a1448a5bb389d79084d606035"
version = "v3.7.7"
[[projects]]
name = "github.com/gobuffalo/pop"
@ -123,12 +132,11 @@
".",
"associations",
"columns",
"fizz",
"fizz/translators",
"fix",
"nulls"
]
revision = "9985012f32f5e36b1a10e9191ee460daac4a9bc7"
version = "v4.5.9"
revision = "66130dbcd030ea900e35e45e03dd1a59577d2e99"
version = "v4.5.12"
[[projects]]
name = "github.com/gobuffalo/tags"
@ -137,8 +145,8 @@
"form",
"form/bootstrap"
]
revision = "82cd7696c84aba829b74e81814ff489b64e7b56a"
version = "v2.0.5"
revision = "96c7cdfcadcb28eb1b42b9080ba7f93936ffc5c5"
version = "v2.0.7"
[[projects]]
name = "github.com/gobuffalo/uuid"
@ -221,7 +229,7 @@
".",
"reflectx"
]
revision = "2aeb6a910c2b94f2d5eb53d9895d80e27264ec41"
revision = "0dae4fefe7c0e190f7b5a78dac28a1c82cc8d849"
[[projects]]
name = "github.com/joho/godotenv"
@ -245,7 +253,6 @@
version = "v1.8.0"
[[projects]]
branch = "master"
name = "github.com/markbates/going"
packages = [
"defaults",
@ -253,18 +260,19 @@
"wait"
]
revision = "0576708c56cea02331f864fe6e157ac7841923e4"
version = "v1.0.0"
[[projects]]
branch = "master"
name = "github.com/markbates/grift"
packages = ["grift"]
revision = "76f93617a788d350124f749acb3790276a436cc0"
version = "v1.0.0"
[[projects]]
branch = "master"
name = "github.com/markbates/inflect"
packages = ["."]
revision = "dd7de90c06bca70f18136e59dec2270c19a401e7"
version = "v1.0.0"
[[projects]]
name = "github.com/markbates/refresh"
@ -293,17 +301,6 @@
packages = ["."]
revision = "48a63b6052f1f9373db9388a658da30c6ab53db1"
[[projects]]
name = "github.com/mattn/anko"
packages = [
"ast",
"core",
"parser",
"vm"
]
revision = "e9c5c0ca86cf129292c56ddbddc4fff027844d65"
version = "v0.0.4"
[[projects]]
name = "github.com/mattn/go-colorable"
packages = ["."]
@ -319,14 +316,14 @@
[[projects]]
name = "github.com/mattn/go-sqlite3"
packages = ["."]
revision = "323a32be5a2421b8c7087225079c6c900ec397cd"
version = "v1.7.0"
revision = "25ecb14adfc7543176f7d85291ec7dba82c6f7e4"
version = "v1.9.0"
[[projects]]
branch = "master"
name = "github.com/microcosm-cc/bluemonday"
packages = ["."]
revision = "995366fdf961d03629cd17361bddd32745718e2c"
revision = "f0761eb8ed07c1cc892ef631b00c33463b9b6868"
[[projects]]
branch = "master"
@ -494,7 +491,7 @@
"blowfish",
"ssh/terminal"
]
revision = "8ac0e0d97ce45cd83d1d7243c060cb8461dda5e9"
revision = "a49355c7e3f8fe157a85be2f77e6e269a0f89602"
[[projects]]
branch = "master"
@ -504,7 +501,7 @@
"html",
"html/atom"
]
revision = "db08ff08e8622530d9ed3a0e8ac279f6d4c02196"
revision = "87b3feba568e144938625fc5d80ec92566c1a8fe"
[[projects]]
branch = "master"
@ -519,7 +516,7 @@
"unix",
"windows"
]
revision = "bff228c7b664c5fce602223a05fb708fd8654986"
revision = "7138fd3d9dc8335c567ca206f4333fb75eb05d56"
[[projects]]
name = "golang.org/x/text"
@ -537,8 +534,8 @@
[[projects]]
name = "google.golang.org/appengine"
packages = ["cloudsql"]
revision = "150dc57a1b433e64154302bdc40b6bb8aefa313a"
version = "v1.0.0"
revision = "b1f26356af11148e710935ed1ac8a7f5702c7612"
version = "v1.1.0"
[[projects]]
name = "gopkg.in/yaml.v2"
@ -549,6 +546,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "b735a8f4099268006777df3205705fac3423a7666a61f92eeba515d365aac5b7"
inputs-digest = "0ca276e99bfba052cf9d07bc5e408c494fce5cc8b82106feec5601f108cd5b4d"
solver-name = "gps-cdcl"
solver-version = 1

Просмотреть файл

@ -27,11 +27,11 @@
[[constraint]]
name = "github.com/gobuffalo/buffalo"
version = "0.11.0"
version = "~0.11.0"
[[constraint]]
name = "github.com/gobuffalo/uuid"
version = "2.0.0"
version = "^2.0.0"
[[constraint]]
branch = "master"
@ -43,7 +43,11 @@
[[constraint]]
name = "github.com/spf13/viper"
version = "1.0.2"
version = "^1.0.2"
[[constraint]]
name = "github.com/joho/godotenv"
version = "^1.2.0"
[prune]
go-tests = true

Просмотреть файл

@ -42,6 +42,7 @@ import (
"github.com/Azure/go-autorest/autorest/azure"
"github.com/gobuffalo/buffalo/meta"
"github.com/gobuffalo/pop"
"github.com/joho/godotenv"
"github.com/marstr/randname"
"github.com/spf13/cobra"
"github.com/spf13/viper"
@ -108,7 +109,7 @@ const (
const (
DatabaseAdminName = "db-admin"
DatabaseAdminDefault = "buffaloAdmin"
databaseAdminUsage = "The user handle of the administratr account "
databaseAdminUsage = "The user handle of the administrator account."
)
// These constants define a parameter which controls the password of the database provisioned. For marginal security,
@ -119,6 +120,7 @@ const (
DatabasePasswordShorthand = "w"
DatabasePasswordDefault = "<randomly generated>"
databasePasswordUsage = "The administrator password for the database created. It is recommended you read this from a file instead of typing it in from your terminal."
DatabasePasswordEnvVar = "BUFFALO_AZURE_DATABASE_PASSWORD"
)
// These constants define a parameter which allows control over the particular Azure cloud which should be used for
@ -255,8 +257,9 @@ const (
// These constants define a parameter which toggles whether or not to save the template used for deployment to disk.
const (
SkipTemplateCacheName = "skip-template-cache"
skipTemplateCacheUsage = "After downloading the default template, do NOT save it in the working directory."
SkipTemplateCacheName = "skip-template-cache"
SkipTemplateCacheShorthand = "z"
skipTemplateCacheUsage = "After downloading the default template, do NOT save it in the working directory."
)
// These constants define a parameter which toggles whether or not to save the parameters used for deployment to disk.
@ -273,6 +276,41 @@ const (
skipDeploymentUsage = "Do not create an Azure deployment, do just the meta tasks."
)
// These constants define a parameter which controls the Docker registry that will be searched for the image provided.
const (
DockerRegistryURLName = "docker-registry-url"
dockerRegistryURLUsage = "The URL for a private Docker Registry containing the image definition."
)
// These constants define a parameter which allows the username to be set for Docker authentication.
const (
DockerRegistryUsernameName = "docker-registry-username"
dockerRegistryUsernameUsage = "The user handle to allow access to a private docker registry."
)
// These constants define a parameter which allows the password to be set for Docker authentication.
const (
DockerRegistryPasswordName = "docker-registry-password"
dockerRegistryPasswordUsage = "The user password to allow access to a private docker registry."
)
// DockerAccess is an enum that contains either "private" or "public"
type DockerAccess string
// All (currently) possible value of DockerAccess
const (
DockerAccessPublic = "public"
DockerAccessPrivate = "private"
)
// These constants define a parameter which informs buffalo-azure whether the registry is public or
// private.
const (
DockerRegistryAccessName = "docker-registry-access"
DockerRegistryAccessDefault = DockerAccessPublic
dockerRegistryAccessUsage = "Specifies whether the Docker registry targeted is " + DockerAccessPublic + " or " + DockerAccessPrivate
)
var status *log.Logger
var errLog = newFormattedLog(os.Stderr, "error")
var debugLog *log.Logger
@ -304,10 +342,15 @@ var provisionCmd = &cobra.Command{
ctx, cancel := context.WithTimeout(context.Background(), 45*time.Minute)
defer cancel()
auth, err := getAuthorizer(ctx, subscriptionID, clientID, clientSecret, provisionConfig.GetString(TenantIDName))
if err != nil {
errLog.Print("unable to authenticate: ", err)
return
var err error
var auth autorest.Authorizer
if !provisionConfig.GetBool(SkipDeploymentName) {
auth, err = getAuthorizer(ctx, subscriptionID, clientID, clientSecret, provisionConfig.GetString(TenantIDName))
if err != nil {
errLog.Print("unable to authenticate: ", err)
return
}
}
status.Print(TenantIDName+" selected: ", provisionConfig.GetString(TenantIDName))
status.Print(SubscriptionName+" selected: ", subscriptionID)
@ -317,34 +360,26 @@ var provisionCmd = &cobra.Command{
status.Println(DatabaseAdminName+" selected: ", databaseAdmin)
if usingDB, dbPassword := !strings.EqualFold(provisionConfig.GetString(DatabaseTypeName), "none"), provisionConfig.GetString(DatabasePasswordName); usingDB && dbPassword == DatabasePasswordDefault {
provisionConfig.Set(DatabasePasswordName, randname.GenerateWithPrefix("MSFT+Buffalo-", 20))
newPass := randname.GenerateWithPrefix("MSFT+Buffalo-", 20)
provisionConfig.Set(DatabasePasswordName, newPass)
status.Println("generated database password")
var envMap map[string]string
const envFileLoc = "./.env"
if envMap, err = godotenv.Read(envFileLoc); err != nil {
envMap = make(map[string]string, 1)
}
envMap[DatabasePasswordEnvVar] = newPass
if err := godotenv.Write(envMap, envFileLoc); err == nil {
status.Printf("wrote database password to %q", envFileLoc)
} else {
errLog.Printf("unable to write database password to %q", envFileLoc)
}
} else if usingDB {
status.Println("using provided password")
}
status.Println(ImageName+" selected: ", image)
groups := resources.NewGroupsClient(subscriptionID)
groups.Authorizer = auth
groups.AddToUserAgent(userAgent)
// Assert the presence of the specified Resource Group
rgName := provisionConfig.GetString(ResoureGroupName)
created, err := insertResourceGroup(ctx, groups, rgName, provisionConfig.GetString(LocationName))
if err != nil {
errLog.Printf("unable to fetch or create resource group %s: %v\n", rgName, err)
return
}
if created {
status.Println("created resource group: ", rgName)
} else {
status.Println("found resource group: ", rgName)
}
status.Println("site name selected: ", siteName)
pLink := portalLink(subscriptionID, rgName)
// Provision the necessary assets.
deployParams.Parameters["name"] = DeploymentParameter{siteName}
@ -353,6 +388,10 @@ var provisionCmd = &cobra.Command{
deployParams.Parameters["imageName"] = DeploymentParameter{image}
deployParams.Parameters["databaseAdministratorLogin"] = DeploymentParameter{databaseAdmin}
deployParams.Parameters["databaseAdministratorLoginPassword"] = DeploymentParameter{provisionConfig.GetString(DatabasePasswordName)}
deployParams.Parameters["dockerRegistryAccess"] = DeploymentParameter{provisionConfig.GetString(DockerRegistryAccessName)}
deployParams.Parameters["dockerRegistryServerURL"] = DeploymentParameter{provisionConfig.GetString(DockerRegistryURLName)}
deployParams.Parameters["dockerRegistryServerUsername"] = DeploymentParameter{provisionConfig.GetString(DockerRegistryUsernameName)}
deployParams.Parameters["dockerRegistryServerPassword"] = DeploymentParameter{provisionConfig.GetString(DockerRegistryPasswordName)}
template, err := getDeploymentTemplate(ctx, templateLocation)
if err != nil {
@ -369,6 +408,27 @@ var provisionCmd = &cobra.Command{
} else {
go func(errOut chan<- error) {
defer close(errOut)
groups := resources.NewGroupsClient(subscriptionID)
groups.Authorizer = auth
groups.AddToUserAgent(userAgent)
// Assert the presence of the specified Resource Group
rgName := provisionConfig.GetString(ResoureGroupName)
created, err := insertResourceGroup(ctx, groups, rgName, provisionConfig.GetString(LocationName))
if err != nil {
errLog.Printf("unable to fetch or create resource group %s: %v\n", rgName, err)
errOut <- err
return
}
if created {
status.Println("created resource group: ", rgName)
} else {
status.Println("found resource group: ", rgName)
}
status.Println("site name selected: ", siteName)
pLink := portalLink(subscriptionID, rgName)
status.Println("beginning deployment")
if err := doDeployment(ctx, auth, subscriptionID, rgName, template); err == nil {
fmt.Println("Check on your new Resource Group in the Azure Portal: ", pLink)
@ -404,7 +464,7 @@ var provisionCmd = &cobra.Command{
if provisionConfig.GetBool(SkipParameterCacheName) {
close(parameterSaveResults)
} else {
go doCache(ctx, parameterSaveResults, stripDBPassword(deployParams), TemplateParametersDefault, "parameters")
go doCache(ctx, parameterSaveResults, stripPasswords(deployParams), TemplateParametersDefault, "parameters")
}
waitOnResults := func(ctx context.Context, results <-chan error) error {
@ -480,7 +540,7 @@ var provisionCmd = &cobra.Command{
},
}
func stripDBPassword(original *DeploymentParameters) (copy *DeploymentParameters) {
func stripPasswords(original *DeploymentParameters) (copy *DeploymentParameters) {
copy = NewDeploymentParameters()
copy.Parameters = make(map[string]DeploymentParameter, len(original.Parameters))
copy.ContentVersion = original.ContentVersion
@ -490,6 +550,7 @@ func stripDBPassword(original *DeploymentParameters) (copy *DeploymentParameters
copy.Parameters[k] = v
}
delete(copy.Parameters, "databaseAdministratorLoginPassword")
delete(copy.Parameters, "dockerRegistryServerPassword")
return copy
}
@ -498,6 +559,7 @@ func cache(ctx context.Context, contents interface{}, outputName string) error {
defer handle.Close()
enc := json.NewEncoder(handle)
enc.SetIndent("", " ")
err = enc.Encode(contents)
if err != nil {
return err
@ -824,6 +886,22 @@ func setDefaults(conf *viper.Viper, params *DeploymentParameters) {
if dbAdmin, ok := params.Parameters["databaseAdministratorLogin"]; ok {
conf.SetDefault(DatabaseAdminName, dbAdmin.Value)
}
if dockerAccess, ok := params.Parameters["dockerRegistryAccess"]; ok {
conf.SetDefault(DockerRegistryAccessName, dockerAccess)
}
if dockerURL, ok := params.Parameters["dockerRegistryServerURL"]; ok {
conf.SetDefault(DockerRegistryURLName, dockerURL)
}
if dockerUsername, ok := params.Parameters["dockerRegistryServerUsername"]; ok {
conf.SetDefault(DockerRegistryUsernameName, dockerUsername)
}
if dockerPassword, ok := params.Parameters["dockerRegistryServerPassword"]; ok {
conf.SetDefault(DockerRegistryPasswordName, dockerPassword)
}
}
func loadFromParameterFile(paramFile string) (*DeploymentParameters, error) {
@ -844,6 +922,7 @@ func loadFromParameterFile(paramFile string) (*DeploymentParameters, error) {
}
func init() {
const redactedMessage = "[redacted]"
var debugWriter io.Writer
if debug == "" {
debugWriter = ioutil.Discard
@ -854,6 +933,8 @@ func init() {
azureCmd.AddCommand(provisionCmd)
godotenv.Load()
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
@ -870,6 +951,7 @@ func init() {
provisionConfig.BindEnv(TenantIDName, "AZURE_TENANT_ID", "AZ_TENANT_ID")
provisionConfig.BindEnv(EnvironmentName, "AZURE_ENVIRONMENT", "AZ_ENVIRONMENT")
provisionConfig.BindEnv(ProfileName, "GO_ENV")
provisionConfig.BindEnv(DatabasePasswordName, DatabasePasswordEnvVar, "BUFFALO_AZURE_DB_PASSWORD", "BUFFALO_AZ_DATABASE_PASSWORD", "BUFFALO_AZ_DB_PASSWORD")
provisionConfig.SetDefault(ProfileName, "development")
@ -888,6 +970,7 @@ func init() {
provisionConfig.SetDefault(LocationName, LocationDefaultText)
provisionConfig.SetDefault(SiteName, siteDefaultMessage)
provisionConfig.SetDefault(TemplateParametersName, TemplateParametersDefault)
provisionConfig.SetDefault(DockerRegistryAccessName, DockerRegistryAccessDefault)
var sanitizedClientSecret string
if rawSecret := provisionConfig.GetString(ClientSecretName); rawSecret != "" {
@ -895,7 +978,7 @@ func init() {
if len(rawSecret) > safeCharCount {
sanitizedClientSecret = fmt.Sprintf("...%s", rawSecret[len(rawSecret)-safeCharCount:])
} else {
sanitizedClientSecret = "[key hidden]"
sanitizedClientSecret = redactedMessage
}
}
@ -912,6 +995,19 @@ func init() {
deployParams = NewDeploymentParameters()
}
dbPassText := provisionConfig.GetString(DatabasePasswordName)
if dbPassText == "" {
dbPassText = DatabasePasswordDefault
provisionConfig.SetDefault(DatabasePasswordName, DatabasePasswordDefault)
} else {
dbPassText = redactedMessage
}
dockerPassText := provisionConfig.GetString(DockerRegistryPasswordName)
if dockerPassText != "" {
dockerPassText = redactedMessage
}
provisionCmd.Flags().StringP(ImageName, ImageShorthand, provisionConfig.GetString(ImageName), imageUsage)
provisionCmd.Flags().StringP(TemplateName, TemplateShorthand, provisionConfig.GetString(TemplateName), templateUsage)
provisionCmd.Flags().StringP(SubscriptionName, SubscriptionShorthand, provisionConfig.GetString(SubscriptionName), subscriptionUsage)
@ -926,12 +1022,16 @@ func init() {
provisionCmd.Flags().StringP(ResoureGroupName, ResourceGroupShorthand, provisionConfig.GetString(ResoureGroupName), resourceGroupUsage)
provisionCmd.Flags().StringP(SiteName, SiteShorthand, provisionConfig.GetString(SiteName), siteUsage)
provisionCmd.Flags().StringP(LocationName, LocationShorthand, provisionConfig.GetString(LocationName), locationUsage)
provisionCmd.Flags().Bool(SkipTemplateCacheName, false, skipTemplateCacheUsage)
provisionCmd.Flags().BoolP(SkipTemplateCacheName, SkipTemplateCacheShorthand, false, skipTemplateCacheUsage)
provisionCmd.Flags().BoolP(SkipParameterCacheName, SkipParameterCacheShorthand, false, skipParameterCacheUsage)
provisionCmd.Flags().BoolP(SkipDeploymentName, SkipDeploymentShorthand, false, skipDeploymentUsage)
provisionCmd.Flags().StringP(DatabasePasswordName, DatabasePasswordShorthand, DatabasePasswordDefault, databasePasswordUsage)
provisionCmd.Flags().StringP(DatabasePasswordName, DatabasePasswordShorthand, dbPassText, databasePasswordUsage)
provisionCmd.Flags().String(DatabaseAdminName, provisionConfig.GetString(DatabaseAdminName), databaseAdminUsage)
provisionCmd.Flags().StringP(TemplateParametersName, TemplateParametersShorthand, provisionConfig.GetString(TemplateParametersName), templateParametersUsage)
provisionCmd.Flags().String(DockerRegistryAccessName, provisionConfig.GetString(DockerRegistryAccessName), dockerRegistryAccessUsage)
provisionCmd.Flags().String(DockerRegistryURLName, provisionConfig.GetString(DockerRegistryURLName), dockerRegistryURLUsage)
provisionCmd.Flags().String(DockerRegistryUsernameName, provisionConfig.GetString(DockerRegistryUsernameName), dockerRegistryUsernameUsage)
provisionCmd.Flags().String(DockerRegistryPasswordName, dockerPassText, dockerRegistryPasswordUsage)
provisionConfig.BindPFlags(provisionCmd.Flags())

Просмотреть файл

@ -0,0 +1,234 @@
package common
import (
"bytes"
"errors"
"fmt"
"go/ast"
"go/importer"
"go/parser"
"go/token"
"go/types"
"path"
"sort"
"strings"
)
// PackageSpecifier is a string that represents the name that will be used to refer to
// exported functions and variables from a package.
type PackageSpecifier string
// PackagePath is a string that refers to the location of Go package.
type PackagePath string
// ImportBag captures all of the imports in a Go source file, and attempts
// to ease the process of working with them.
type ImportBag struct {
bySpec map[PackageSpecifier]PackagePath
blankIdent map[PackagePath]struct{}
localIdent map[PackagePath]struct{}
}
// NewImportBag instantiates an empty ImportBag.
func NewImportBag() *ImportBag {
return &ImportBag{
bySpec: make(map[PackageSpecifier]PackagePath),
blankIdent: make(map[PackagePath]struct{}),
localIdent: make(map[PackagePath]struct{}),
}
}
// NewImportBagFromFile reads a Go source file, finds all imports,
// and returns them as an instantiated ImportBag.
func NewImportBagFromFile(filepath string) (*ImportBag, error) {
f, err := parser.ParseFile(token.NewFileSet(), filepath, nil, parser.ImportsOnly)
if err != nil {
return nil, err
}
ib := NewImportBag()
for _, spec := range f.Imports {
pkgPath := PackagePath(strings.Trim(spec.Path.Value, `"`))
if spec.Name == nil {
ib.AddImport(pkgPath)
} else {
ib.AddImportWithSpecifier(pkgPath, PackageSpecifier(spec.Name.Name))
}
}
return ib, nil
}
// AddImport includes a package, and returns the name that was selected to
// be the specified for working with this path. It first attempts to use the
// package name as the specifier. Should that cause a conflict, it determines
// a unique name to be used as the specifier.
//
// If the path provided has already been imported, the existing name for it
// is returned, but err is non-nil.
func (ib *ImportBag) AddImport(pkgPath PackagePath) PackageSpecifier {
spec, err := FindSpecifier(pkgPath)
if err != nil {
spec = PackageSpecifier(path.Base(string(pkgPath)))
}
specLen := len(spec)
suffix := uint(1)
for {
err = ib.AddImportWithSpecifier(pkgPath, spec)
if err == nil {
break
} else if err != ErrDuplicateImport {
panic(err)
}
spec = PackageSpecifier(fmt.Sprintf("%s%d", spec[:specLen], suffix))
suffix++
}
return spec
}
// ErrDuplicateImport is the error that will be returned when two packages are both requested
// to be imported using the same specifier.
var ErrDuplicateImport = errors.New("specifier already in use in ImportBag")
// ErrMultipleLocalImport is the error that will be returned when the same package has been imported
// to the specifer "." more than once.
var ErrMultipleLocalImport = errors.New("package already imported into the local namespace")
// AddImportWithSpecifier will add an import with a given name. If it would lead
// to conflicting package specifiers, it returns an error.
func (ib *ImportBag) AddImportWithSpecifier(pkgPath PackagePath, specifier PackageSpecifier) error {
if specifier == "_" {
ib.blankIdent[pkgPath] = struct{}{}
return nil
}
if specifier == "." {
if _, ok := ib.localIdent[pkgPath]; ok {
return ErrMultipleLocalImport
}
ib.localIdent[pkgPath] = struct{}{}
return nil
}
if impPath, ok := ib.bySpec[specifier]; ok && pkgPath != impPath {
return ErrDuplicateImport
}
ib.bySpec[specifier] = pkgPath
return nil
}
// FindSpecifier finds the specifier assocatied with a particular package.
//
// If the package was not imported, the empty string and false are returned.
//
// If multiple specifiers are assigned to the package, one is returned at
// random.
//
// If the same package is imported with a named specifier, and the blank
// identifier, the name is returned.
func (ib ImportBag) FindSpecifier(pkgPath PackagePath) (PackageSpecifier, bool) {
for k, v := range ib.bySpec {
if v == pkgPath {
return k, true
}
}
if _, ok := ib.blankIdent[pkgPath]; ok {
return "_", true
}
if _, ok := ib.localIdent[pkgPath]; ok {
return ".", true
}
return "", false
}
// List returns each import statement as a slice of strings sorted alphabetically by
// their import paths.
func (ib *ImportBag) List() []string {
specs := ib.ListAsImportSpec()
retval := make([]string, len(specs))
builder := bytes.NewBuffer([]byte{})
for i, s := range specs {
if s.Name != nil {
builder.WriteString(s.Name.Name)
builder.WriteRune(' ')
}
builder.WriteString(s.Path.Value)
retval[i] = builder.String()
builder.Reset()
}
return retval
}
// ListAsImportSpec returns the imports from the ImportBag as a slice of ImportSpecs
// sorted alphabetically by their import paths.
func (ib *ImportBag) ListAsImportSpec() []*ast.ImportSpec {
retval := make([]*ast.ImportSpec, 0, len(ib.bySpec)+len(ib.localIdent)+len(ib.blankIdent))
getLit := func(pkgPath PackagePath) *ast.BasicLit {
return &ast.BasicLit{
Kind: token.STRING,
Value: fmt.Sprintf("%q", string(pkgPath)),
}
}
for k, v := range ib.bySpec {
var name *ast.Ident
if path.Base(string(v)) != string(k) {
name = ast.NewIdent(string(k))
}
retval = append(retval, &ast.ImportSpec{
Name: name,
Path: getLit(v),
})
}
for s := range ib.localIdent {
retval = append(retval, &ast.ImportSpec{
Name: ast.NewIdent("."),
Path: getLit(s),
})
}
for s := range ib.blankIdent {
retval = append(retval, &ast.ImportSpec{
Name: ast.NewIdent("_"),
Path: getLit(s),
})
}
sort.Slice(retval, func(i, j int) bool {
return strings.Compare(retval[i].Path.Value, retval[j].Path.Value) < 0
})
return retval
}
var impFinder = importer.Default()
// FindSpecifier finds the name of a package by loading it in from GOPATH
// or a vendor folder.
func FindSpecifier(pkgPath PackagePath) (PackageSpecifier, error) {
var pkg *types.Package
var err error
if cast, ok := impFinder.(types.ImporterFrom); ok {
pkg, err = cast.ImportFrom(string(pkgPath), "", 0)
} else {
pkg, err = impFinder.Import(string(pkgPath))
}
if err != nil {
return "", err
}
return PackageSpecifier(pkg.Name()), nil
}

Просмотреть файл

@ -0,0 +1,144 @@
package common_test
import (
"testing"
. "github.com/Azure/buffalo-azure/generators/common"
)
func TestImportBag_AddImport_Unique(t *testing.T) {
testCases := [][]PackagePath{
{
"github.com/Azure/azure-sdk-for-go/services/eventgrid/2018-01-01/eventgrid",
},
{
"github.com/Azure/buffalo-azure/generators/common",
"github.com/Azure/buffalo-azure/sdk/eventgrid",
},
{
"fmt",
"github.com/Azure/buffalo-azure/generators/common",
},
}
for _, tc := range testCases {
t.Run("", func(t *testing.T) {
seen := map[PackageSpecifier]struct{}{}
subject := NewImportBag()
for _, pkgPath := range tc {
spec := subject.AddImport(pkgPath)
if _, ok := seen[spec]; ok {
t.Logf("duplicate spec returned")
t.Fail()
}
}
})
}
}
func TestImportBag_List(t *testing.T) {
testCases := []struct {
inputs []PackagePath
expected []string
}{
{
inputs: []PackagePath{
"github.com/Azure/buffalo-azure/generators/common",
"github.com/Azure/azure-sdk-for-go/services/eventgrid/2018-01-01/eventgrid",
},
expected: []string{
`"github.com/Azure/azure-sdk-for-go/services/eventgrid/2018-01-01/eventgrid"`,
`"github.com/Azure/buffalo-azure/generators/common"`,
},
},
{
inputs: []PackagePath{
"github.com/Azure/buffalo-azure/sdk/eventgrid",
"github.com/Azure/azure-sdk-for-go/services/eventgrid/2018-01-01/eventgrid",
},
expected: []string{
`eventgrid1 "github.com/Azure/azure-sdk-for-go/services/eventgrid/2018-01-01/eventgrid"`,
`"github.com/Azure/buffalo-azure/sdk/eventgrid"`,
},
},
{
inputs: []PackagePath{
"github.com/Azure/buffalo-azure/sdk/eventgrid",
"github.com/Azure/azure-sdk-for-go/services/eventgrid/2018-01-01/eventgrid",
"github.com/Azure/buffalo-azure/generators/eventgrid",
},
expected: []string{
`eventgrid1 "github.com/Azure/azure-sdk-for-go/services/eventgrid/2018-01-01/eventgrid"`,
`eventgrid2 "github.com/Azure/buffalo-azure/generators/eventgrid"`,
`"github.com/Azure/buffalo-azure/sdk/eventgrid"`,
},
},
{
inputs: []PackagePath{
"github.com/Azure/buffalo-azure/sdk/eventgrid",
"github.com/Azure/buffalo-azure/sdk/eventgrid",
},
expected: []string{
`"github.com/Azure/buffalo-azure/sdk/eventgrid"`,
},
},
}
for _, tc := range testCases {
t.Run("", func(t *testing.T) {
subject := NewImportBag()
for _, i := range tc.inputs {
subject.AddImport(i)
}
got := subject.List()
if len(got) != len(tc.expected) {
t.Logf("got: %d imports want: %d imports", len(got), len(tc.expected))
t.Fail()
}
for i, val := range tc.expected {
if got[i] != val {
t.Logf("at %d\n\tgot: %s\n\twant: %s", i, got[i], val)
t.Fail()
}
}
})
}
}
func TestImportBag_NewImportBagFromFile(t *testing.T) {
testCases := []struct {
inputFile string
expected []string
}{
{"./testdata/main.go", []string{`"fmt"`, `_ "github.com/Azure/azure-sdk-for-go/services/eventgrid/2018-01-01/eventgrid"`}},
}
for _, tc := range testCases {
t.Run("", func(t *testing.T) {
subject, err := NewImportBagFromFile(tc.inputFile)
if err != nil {
t.Error(err)
return
}
got := subject.List()
for i, imp := range tc.expected {
if imp != got[i] {
t.Logf("at: %d\n\tgot: %s\n\twant: %s", i, got[i], imp)
t.Fail()
}
}
if len(got) != len(tc.expected) {
t.Logf("got: %d imports want: %d imports", len(got), len(tc.expected))
t.Fail()
}
})
}
}

11
generators/common/testdata/main.go поставляемый Normal file
Просмотреть файл

@ -0,0 +1,11 @@
package main
import (
"fmt"
_ "github.com/Azure/azure-sdk-for-go/services/eventgrid/2018-01-01/eventgrid"
)
func main() {
fmt.Println("Hello, world!!!")
}

Просмотреть файл

@ -11,6 +11,8 @@ import (
"github.com/gobuffalo/buffalo/meta"
"github.com/gobuffalo/makr"
"github.com/markbates/inflect"
"github.com/Azure/buffalo-azure/generators/common"
)
//go:generate go run ./builder/builder.go -o ./static_templates.go ./templates
@ -26,15 +28,24 @@ func (eg *Generator) Run(app meta.App, name string, types map[string]reflect.Typ
type TypeMapping struct {
Identifier string
inflect.Name
PackageSpecifier string
PkgPath string
PkgSpec common.PackageSpecifier
}
flatTypes := make([]TypeMapping, 0, len(types))
ib := common.NewImportBag()
ib.AddImport("encoding/json")
ib.AddImport("errors")
ib.AddImport("net/http")
ib.AddImportWithSpecifier("github.com/Azure/buffalo-azure/sdk/eventgrid", "eg")
ib.AddImport("github.com/gobuffalo/buffalo")
for i, n := range types {
flatTypes = append(flatTypes, TypeMapping{
Identifier: i,
PackageSpecifier: path.Base(n.PkgPath()),
Name: inflect.Name(n.Name()),
Identifier: i,
PkgPath: n.PkgPath(),
PkgSpec: ib.AddImport(common.PackagePath(n.PkgPath())),
Name: inflect.Name(n.Name()),
})
}
@ -60,6 +71,7 @@ func (eg *Generator) Run(app meta.App, name string, types map[string]reflect.Typ
d := make(makr.Data)
d["name"] = iName
d["types"] = flatTypes
d["imports"] = ib.List()
return g.Run(app.Root, d)
}

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -1,22 +1,18 @@
package actions
import (
"encoding/json"
"errors"
"net/http"
"github.com/Azure/buffalo-azure/sdk/eventgrid"
"github.com/gobuffalo/buffalo"
{{ range $i := .imports }} {{$i}}
{{ end }}
)
// My{{$.name.Camel}}Subscriber gathers responds to all Requests sent to a particular endpoint.
type {{$.name.Camel}}Subscriber struct {
eventgrid.Subscriber
eg.Subscriber
}
// New{{$.name.Camel}}Subscriber instantiates {{$.name.Camel}}Subscriber for use in a `buffalo.App`.
func New{{$.name.Camel}}Subscriber(parent eventgrid.Subscriber) (created *{{$.name.Camel}}Subscriber) {
dispatcher := eventgrid.NewTypeDispatchSubscriber(parent)
func New{{$.name.Camel}}Subscriber(parent eg.Subscriber) (created *{{$.name.Camel}}Subscriber) {
dispatcher := eg.NewTypeDispatchSubscriber(parent)
created = &{{$.name.Camel}}Subscriber{
Subscriber: dispatcher,
@ -25,15 +21,15 @@ func New{{$.name.Camel}}Subscriber(parent eventgrid.Subscriber) (created *{{$.na
{{ range $t := .types}}
dispatcher.Bind("{{$t.Identifier}}", created.Receive{{$t.Name.Camel}})
{{end}}
dispatcher.Bind(eventgrid.EventTypeWildcard, created.ReceiveDefault)
dispatcher.Bind(eg.EventTypeWildcard, created.ReceiveDefault)
return
}
{{ range $t := .types }}
// Receive{{$t.Name.Camel}} will respond to an `eventgrid.Event` carrying a serialized `{{$t.Name.Camel}}` as its payload.
func (s *{{$.name.Camel}}Subscriber) Receive{{$t.Name.Camel}}(c buffalo.Context, e eventgrid.Event) error {
var payload {{$t.PackageSpecifier}}.{{$t.Name.Camel}}
func (s *{{$.name.Camel}}Subscriber) Receive{{$t.Name.Camel}}(c buffalo.Context, e eg.Event) error {
var payload {{$t.PkgSpec}}.{{$t.Name.Camel}}
if err := json.Unmarshal(e.Data, &payload); err != nil {
return c.Error(http.StatusBadRequest, errors.New("unable to unmarshal request data"))
}
@ -44,6 +40,6 @@ func (s *{{$.name.Camel}}Subscriber) Receive{{$t.Name.Camel}}(c buffalo.Context,
{{end}}
// ReceiveDefault will respond to an `eventgrid.Event` carrying any EventType as its payload.
func (s *{{$.name.Camel}}Subscriber) ReceiveDefault(c buffalo.Context, e eventgrid.Event) error {
func (s *{{$.name.Camel}}Subscriber) ReceiveDefault(c buffalo.Context, e eg.Event) error {
return c.Error(http.StatusInternalServerError, errors.New("not implemented"))
}

13
generators/eventgrid/testdata/main.go поставляемый Normal file
Просмотреть файл

@ -0,0 +1,13 @@
package main
import (
"fmt"
egdp "github.com/Azure/azure-sdk-for-go/services/eventgrid/2018-01-01/eventgrid"
"github.com/Azure/buffalo-azure/sdk/eventgrid"
)
func main() {
fmt.Printf("%#v\n", eventgrid.TypeDispatchSubscriber{})
fmt.Printf("%#v\n", egdp.StorageBlobCreatedEventData{})
}