diff --git a/Gopkg.lock b/Gopkg.lock index 810d6be4..33548d11 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -58,8 +58,8 @@ [[projects]] branch = "master" name = "github.com/palantir/godel" - packages = ["framework/artifactresolver","framework/builtintasks","framework/builtintasks/checkpath","framework/builtintasks/githooks","framework/builtintasks/githubwiki","framework/builtintasks/idea","framework/builtintasks/installupdate","framework/builtintasks/installupdate/layout","framework/builtintasks/packages","framework/godel","framework/godellauncher","framework/internal/legacyplugins","framework/internal/pathsinternal","framework/pluginapi","framework/pluginapitester","framework/plugins","framework/verifyorder","godelgetter","pkg/osarch","pkg/products","pkg/versionedconfig"] - revision = "9a68fc561092131fdf43a4a15d1ae920acf391e2" + packages = ["framework/artifactresolver","framework/builtintasks","framework/builtintasks/checkpath","framework/builtintasks/githooks","framework/builtintasks/githubwiki","framework/builtintasks/idea","framework/builtintasks/installupdate","framework/builtintasks/installupdate/layout","framework/builtintasks/packages","framework/godel","framework/godel/config","framework/godel/config/internal/legacy","framework/godel/config/internal/v0","framework/godellauncher","framework/internal/pathsinternal","framework/pluginapi","framework/pluginapi/v2/pluginapi","framework/pluginapitester","framework/plugins","framework/verifyorder","godelgetter","pkg/osarch","pkg/products","pkg/versionedconfig"] + revision = "85235ee4112d52cba80bc57a53f62976ce936cc5" [[projects]] branch = "master" @@ -130,6 +130,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "561a5599b08164989c579308c0c4db8b5e601712ea1678a0f181c18a0fcc18e7" + inputs-digest = "dabfa61be7fef8426b56df47341cf4e9ce1ef2498cc1ddb29fa2602224b0fe87" solver-name = "gps-cdcl" solver-version = 1 diff --git a/commoncmd/run.go b/commoncmd/run.go index 499dd4f5..a3810d9b 100644 --- a/commoncmd/run.go +++ b/commoncmd/run.go @@ -6,6 +6,7 @@ package commoncmd import ( "io/ioutil" + "os" "github.com/pkg/errors" "gopkg.in/yaml.v2" @@ -15,6 +16,9 @@ import ( func LoadConfig(cfgFile string) (config.ProjectConfig, error) { cfgYML, err := ioutil.ReadFile(cfgFile) + if os.IsNotExist(err) { + return config.ProjectConfig{}, nil + } if err != nil { return config.ProjectConfig{}, errors.Wrapf(err, "failed to read file %s", cfgFile) } diff --git a/godelplugin/plugininfo.go b/godelplugin/cmd/plugininfo.go similarity index 84% rename from godelplugin/plugininfo.go rename to godelplugin/cmd/plugininfo.go index 2262e259..f23dcbdd 100644 --- a/godelplugin/plugininfo.go +++ b/godelplugin/cmd/plugininfo.go @@ -2,15 +2,15 @@ // Use of this source code is governed by the Apache License, Version 2.0 // that can be found in the LICENSE file. -package main +package cmd import ( - "github.com/palantir/godel/framework/pluginapi" + "github.com/palantir/godel/framework/pluginapi/v2/pluginapi" "github.com/palantir/godel/framework/verifyorder" "github.com/palantir/pkg/cobracli" ) -var pluginInfo = pluginapi.MustNewPluginInfo( +var PluginInfo = pluginapi.MustNewPluginInfo( "com.palantir.go-license", "license-plugin", cobracli.Version, @@ -25,13 +25,14 @@ var pluginInfo = pluginapi.MustNewPluginInfo( "license", "Run license task", pluginapi.TaskInfoCommand("run"), - pluginapi.TaskInfoVerifyOptions(pluginapi.NewVerifyOptions( + pluginapi.TaskInfoVerifyOptions( pluginapi.VerifyOptionsOrdering(intVar(verifyorder.License)), pluginapi.VerifyOptionsApplyFalseArgs("--verify"), - )), + ), ), pluginapi.PluginInfoUpgradeConfigTaskInfo( pluginapi.UpgradeConfigTaskInfoCommand("upgrade-config"), + pluginapi.LegacyConfigFile("license.yml"), ), ) diff --git a/godelplugin/cmd/run.go b/godelplugin/cmd/run.go index 60b730e4..110baa52 100644 --- a/godelplugin/cmd/run.go +++ b/godelplugin/cmd/run.go @@ -5,8 +5,7 @@ package cmd import ( - "path" - + godelconfig "github.com/palantir/godel/framework/godel/config" "github.com/palantir/godel/framework/godellauncher" "github.com/palantir/pkg/matcher" "github.com/spf13/cobra" @@ -24,7 +23,7 @@ var ( return err } if godelConfigFileFlagVal != "" { - cfgVal, err := godellauncher.ReadGodelConfig(path.Dir(godelConfigFileFlagVal)) + cfgVal, err := godelconfig.ReadGodelConfigFromFile(godelConfigFileFlagVal) if err != nil { return err } diff --git a/godelplugin/integration_test/integration_test.go b/godelplugin/integration_test/integration_test.go index dd71b714..4b39e524 100644 --- a/godelplugin/integration_test/integration_test.go +++ b/godelplugin/integration_test/integration_test.go @@ -193,16 +193,6 @@ package bar`, } func TestUpgradeConfig(t *testing.T) { - const ( - godelYML = `exclude: - names: - - "\\..+" - - "vendor" - paths: - - "godel" -` - ) - pluginPath, err := products.Bin("license-plugin") require.NoError(t, err) pluginProvider := pluginapitester.NewPluginProvider(pluginPath) @@ -212,7 +202,49 @@ func TestUpgradeConfig(t *testing.T) { nil, []pluginapitester.UpgradeConfigTestCase{ { - Name: "generate configuration is unmodified", + Name: "legacy config is unmodified", + ConfigFiles: map[string]string{ + "godel/config/godel.yml": godelYML, + "godel/config/license-plugin.yml": `legacy-config: true + +header: | + // Copyright 2016 Palantir Technologies, Inc. + // + // License content. + +custom-headers: + # comment in YAML + - name: subproject + header: | + // Copyright 2016 Palantir Technologies, Inc. All rights reserved. + // Subproject license. + + paths: + - subprojectDir +`, + }, + WantOutput: "Upgraded configuration for license-plugin.yml\n", + WantFiles: map[string]string{ + "godel/config/license-plugin.yml": ` +header: | + // Copyright 2016 Palantir Technologies, Inc. + // + // License content. + +custom-headers: + # comment in YAML + - name: subproject + header: | + // Copyright 2016 Palantir Technologies, Inc. All rights reserved. + // Subproject license. + + paths: + - subprojectDir +`, + }, + }, + { + Name: "current config is unmodified", ConfigFiles: map[string]string{ "godel/config/godel.yml": godelYML, "godel/config/license-plugin.yml": ` diff --git a/godelplugin/main.go b/godelplugin/main.go index 66278444..1adf79ea 100644 --- a/godelplugin/main.go +++ b/godelplugin/main.go @@ -7,7 +7,7 @@ package main import ( "os" - "github.com/palantir/godel/framework/pluginapi" + "github.com/palantir/godel/framework/pluginapi/v2/pluginapi" "github.com/palantir/pkg/cobracli" "github.com/palantir/go-license/godelplugin/cmd" @@ -18,7 +18,7 @@ var ( ) func main() { - if ok := pluginapi.InfoCmd(os.Args, os.Stdout, pluginInfo); ok { + if ok := pluginapi.InfoCmd(os.Args, os.Stdout, cmd.PluginInfo); ok { return } os.Exit(cobracli.ExecuteWithDefaultParamsWithVersion(cmd.RootCmd, &debugFlagVal, "")) diff --git a/golicense/config/internal/legacy/config.go b/golicense/config/internal/legacy/config.go index 6d55daf0..35cf86df 100644 --- a/golicense/config/internal/legacy/config.go +++ b/golicense/config/internal/legacy/config.go @@ -11,9 +11,12 @@ import ( "gopkg.in/yaml.v2" ) -type GoLicense struct { +type GoLicenseWithLegacy struct { versionedconfig.ConfigWithLegacy `yaml:",inline"` + GoLicense `yaml:",inline"` +} +type GoLicense struct { // Header is the expected license header. All applicable files are expected to start with this header followed // by a newline. Header string `yaml:"header"` @@ -42,10 +45,18 @@ type License struct { } func UpgradeConfig(cfgBytes []byte) ([]byte, error) { - var legacyCfg GoLicense + var legacyCfg GoLicenseWithLegacy if err := yaml.UnmarshalStrict(cfgBytes, &legacyCfg); err != nil { return nil, errors.Wrapf(err, "failed to unmarshal license-plugin legacy configuration") } - // legacy configuration is completely compatible with v0 configuration - return cfgBytes, nil + // optimization: if input bytes start with the legacy configuration key, trim it to get a valid v0 configuration + if trimmed, ok := versionedconfig.TrimLegacyPrefix(cfgBytes); ok { + return trimmed, nil + } + // otherwise, marshal just the GoLicense portion of the configuration, which is fully compatible with v0 + upgradedBytes, err := yaml.Marshal(legacyCfg.GoLicense) + if err != nil { + return nil, errors.Wrapf(err, "failed to marshal dist-sls-asset legacy configuration") + } + return upgradedBytes, nil } diff --git a/vendor/github.com/palantir/godel/framework/artifactresolver/param.go b/vendor/github.com/palantir/godel/framework/artifactresolver/param.go new file mode 100644 index 00000000..0747f7ec --- /dev/null +++ b/vendor/github.com/palantir/godel/framework/artifactresolver/param.go @@ -0,0 +1,41 @@ +// Copyright 2016 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package artifactresolver + +import ( + "fmt" + + "github.com/palantir/godel/pkg/osarch" +) + +type LocatorWithResolverParam struct { + LocatorWithChecksums LocatorParam + Resolver Resolver +} + +type LocatorParam struct { + Locator + Checksums map[osarch.OSArch]string +} + +type Locator struct { + Group string + Product string + Version string +} + +func (l Locator) String() string { + return fmt.Sprintf("%s:%s:%s", l.Group, l.Product, l.Version) +} diff --git a/vendor/github.com/palantir/godel/framework/builtintasks/info.go b/vendor/github.com/palantir/godel/framework/builtintasks/info.go index bb989604..15942994 100644 --- a/vendor/github.com/palantir/godel/framework/builtintasks/info.go +++ b/vendor/github.com/palantir/godel/framework/builtintasks/info.go @@ -19,6 +19,7 @@ import ( "github.com/spf13/cobra" "gopkg.in/yaml.v2" + "github.com/palantir/godel/framework/godel/config" "github.com/palantir/godel/framework/godellauncher" ) @@ -36,13 +37,13 @@ func InfoTask() godellauncher.Task { if err != nil { return err } - godelCfg, err := godellauncher.ReadGodelConfigFromProjectDir(projectDir) + godelCfg, err := config.ReadGodelConfigFromProjectDir(projectDir) if err != nil { return err } - bytes, err := yaml.Marshal(godellauncher.DefaultTasksPluginsConfig(godelCfg.DefaultTasks)) + bytes, err := yaml.Marshal(godelCfg.DefaultTasks) if err != nil { - return errors.Wrapf(err, "failed to marshal default task config to JSON") + return errors.Wrapf(err, "failed to marshal default task configuration") } cmd.Print(string(bytes)) return nil diff --git a/vendor/github.com/palantir/godel/framework/builtintasks/installupdate/godelwcmds.go b/vendor/github.com/palantir/godel/framework/builtintasks/installupdate/godelwcmds.go new file mode 100644 index 00000000..81d77daf --- /dev/null +++ b/vendor/github.com/palantir/godel/framework/builtintasks/installupdate/godelwcmds.go @@ -0,0 +1,63 @@ +// Copyright 2016 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package installupdate + +import ( + "io" + "os/exec" + "path" + "strings" + + "github.com/pkg/errors" +) + +// RunUpgradeConfig runs the "upgrade-config" task by invoking "{{projectDir}}/godelw upgrade-config". +func RunUpgradeConfig(projectDir string, stdout, stderr io.Writer) error { + return runUpgradeConfig(projectDir, nil, stdout, stderr) +} + +// RunUpgradeLegacyConfig runs the "upgrade-config" task in legacy mode by invoking +// "{{projectDir}}/godelw upgrade-config --legacy". +func RunUpgradeLegacyConfig(projectDir string, stdout, stderr io.Writer) error { + return runUpgradeConfig(projectDir, []string{"--legacy"}, stdout, stderr) +} + +func runUpgradeConfig(projectDir string, args []string, stdout, stderr io.Writer) error { + godelw := path.Join(projectDir, "godelw") + cmd := exec.Command(godelw, append([]string{"upgrade-config"}, args...)...) + cmd.Stdout = stdout + cmd.Stderr = stderr + return cmd.Run() +} + +// GodelVersion returns the Version returned by "{{projectDir}}/godelw version". +func GodelVersion(projectDir string) (Version, error) { + godelw := path.Join(projectDir, "godelw") + cmd := exec.Command(godelw, "version") + output, err := cmd.Output() + if err != nil { + return Version{}, errors.Wrapf(err, "failed to execute command %v: %s", cmd.Args, string(output)) + } + outputString := strings.TrimSpace(string(output)) + parts := strings.Split(outputString, " ") + if len(parts) != 3 { + return Version{}, errors.Errorf(`expected output %s to have 3 parts when split by " ", but was %v`, outputString, parts) + } + v, err := NewVersion(parts[2]) + if err != nil { + return Version{}, errors.Wrapf(err, "failed to create version from output") + } + return v, nil +} diff --git a/vendor/github.com/palantir/godel/framework/builtintasks/installupdate/install.go b/vendor/github.com/palantir/godel/framework/builtintasks/installupdate/install.go index 57158780..d180b89f 100644 --- a/vendor/github.com/palantir/godel/framework/builtintasks/installupdate/install.go +++ b/vendor/github.com/palantir/godel/framework/builtintasks/installupdate/install.go @@ -109,7 +109,7 @@ func install(src godelgetter.PkgSrc, stdout io.Writer) (string, error) { } // getExecutableVersion gets the version of gödel contained in the provided root gödel directory. Invokes the executable -// for the current platform with the "--version" flag and returns the version determined by that output. +// for the current platform with the "version" task and returns the version determined by that output. func getExecutableVersion(gödelApp specdir.SpecDir) (string, error) { executablePath := gödelApp.Path(layout.AppExecutable) cmd := exec.Command(executablePath, "version") @@ -123,6 +123,5 @@ func getExecutableVersion(gödelApp specdir.SpecDir) (string, error) { if len(parts) != 3 { return "", errors.Errorf(`expected output %s to have 3 parts when split by " ", but was %v`, outputString, parts) } - return parts[2], nil } diff --git a/vendor/github.com/palantir/godel/framework/builtintasks/installupdate/versionparser.go b/vendor/github.com/palantir/godel/framework/builtintasks/installupdate/versionparser.go new file mode 100644 index 00000000..e9c5cb17 --- /dev/null +++ b/vendor/github.com/palantir/godel/framework/builtintasks/installupdate/versionparser.go @@ -0,0 +1,212 @@ +// Copyright 2016 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package installupdate + +import ( + "fmt" + "regexp" + "strconv" +) + +type Type int + +var unknown = Type(-1) + +const ( + ReleaseCandidate Type = iota + ReleaseCandidateSnapshot + Release + ReleaseSnapshot + NonOrderable +) + +func (t Type) String() string { + switch t { + case ReleaseCandidate: + return "ReleaseCandidate" + case ReleaseCandidateSnapshot: + return "ReleaseCandidateSnapshot" + case Release: + return "Release" + case ReleaseSnapshot: + return "ReleaseSnapshot" + case NonOrderable: + return "NonOrderable" + } + return strconv.Itoa(int(t)) +} + +var releaseRegexps = []*regexp.Regexp{ + ReleaseCandidate: regexp.MustCompile(`^([0-9]+)\.([0-9]+)\.([0-9])+-rc([0-9]+)$`), + ReleaseCandidateSnapshot: regexp.MustCompile(`^([0-9]+)\.([0-9]+)\.([0-9])+-rc([0-9]+)-([0-9]+)-g[a-f0-9]+$`), + Release: regexp.MustCompile(`^([0-9]+)\.([0-9]+)\.([0-9])+$`), + ReleaseSnapshot: regexp.MustCompile(`^([0-9]+)\.([0-9]+)\.([0-9])+-([0-9]+)-g[a-f0-9]+$`), + NonOrderable: regexp.MustCompile(`^([0-9]+)\.([0-9]+)\.([0-9])+(-[a-z0-9-]+)?(\.dirty)?$`), +} + +type Version struct { + version string + + // computed once on construction and stored + typ Type + majorVersionNum int + minorVersionNum int + patchVersionNum int + firstSequenceVersionNum *int + secondSequenceVersionNum *int +} + +func (v Version) String() string { + return v.version +} + +func (v Version) Type() Type { + return getType(v.version) +} + +func (v Version) Orderable() bool { + typ := v.Type() + return typ >= ReleaseCandidate && typ < NonOrderable +} + +func (v Version) Value() string { + return v.version +} + +func (v Version) MajorVersionNum() int { + return v.majorVersionNum +} + +func (v Version) MinorVersionNum() int { + return v.minorVersionNum +} + +func (v Version) PatchVersionNum() int { + return v.patchVersionNum +} + +func (v Version) FirstSequenceVersionNum() *int { + return v.firstSequenceVersionNum +} + +func (v Version) SecondSequenceVersionNum() *int { + return v.secondSequenceVersionNum +} + +func NewVersion(v string) (Version, error) { + typ := getType(v) + if typ == unknown { + return Version{}, fmt.Errorf("%s is not a valid SLS version", v) + } + + matches := releaseRegexps[typ].FindStringSubmatch(v) + + var firstSequenceVersionNum *int + if typ != NonOrderable && len(matches) > 4 { + n := mustAtoI(matches[4]) + firstSequenceVersionNum = &n + } + var secondSequenceVersionNum *int + if typ != NonOrderable && len(matches) > 5 { + n := mustAtoI(matches[5]) + secondSequenceVersionNum = &n + } + + return Version{ + version: v, + typ: typ, + majorVersionNum: mustAtoI(matches[1]), + minorVersionNum: mustAtoI(matches[2]), + patchVersionNum: mustAtoI(matches[3]), + firstSequenceVersionNum: firstSequenceVersionNum, + secondSequenceVersionNum: secondSequenceVersionNum, + }, nil +} + +func getType(v string) Type { + for i, regExp := range releaseRegexps { + if regExp.MatchString(v) { + return Type(i) + } + } + return unknown +} + +// CompareTo compares the receiver to the provided version. If either version is not orderable (as defined by the spec), +// always returns -1 and false. If both versions are orderable, then returns -1 if the receiver is less than the +// argument, 0 if they are equal and 1 if the receiver is greater than the argument. If both versions are orderable, the +// second return value is always true. +func (v Version) CompareTo(o Version) (int, bool) { + // if either input is not orderable, always return -1 and false + if !v.Orderable() || !o.Orderable() { + return -1, false + } + + switch { + case v.MajorVersionNum() != o.MajorVersionNum(): + return compareInts(v.MajorVersionNum(), o.MajorVersionNum()), true + case v.MinorVersionNum() != o.MinorVersionNum(): + return compareInts(v.MinorVersionNum(), o.MinorVersionNum()), true + case v.PatchVersionNum() != o.PatchVersionNum(): + return compareInts(v.PatchVersionNum(), o.PatchVersionNum()), true + case (v.Type() == ReleaseSnapshot && o.Type() == Release) || (v.Type() == Release && o.Type() == ReleaseSnapshot): + if v.Type() == ReleaseSnapshot { + return 1, true + } + return -1, true + case (v.Type() == Release && o.Type() == ReleaseCandidate) || (v.Type() == ReleaseCandidate && o.Type() == Release): + if v.Type() == Release { + return 1, true + } + return -1, true + case v.Type() == ReleaseSnapshot && o.Type() == ReleaseSnapshot: + return compareInts(*v.FirstSequenceVersionNum(), *o.FirstSequenceVersionNum()), true + case (v.Type() == ReleaseCandidate || v.Type() == ReleaseCandidateSnapshot) && (o.Type() == ReleaseCandidate || o.Type() == ReleaseCandidateSnapshot): + if cmp := compareInts(*v.FirstSequenceVersionNum(), *o.FirstSequenceVersionNum()); cmp != 0 { + return cmp, true + } + + if v.Type() != o.Type() { + if v.Type() == ReleaseCandidateSnapshot { + return 1, true + } + return -1, true + } + + if v.Type() == ReleaseCandidateSnapshot { + return compareInts(*v.SecondSequenceVersionNum(), *o.SecondSequenceVersionNum()), true + } + } + return 0, true +} + +func compareInts(val, other int) int { + switch { + default: + return 0 + case val < other: + return -1 + case val > other: + return 1 + } +} + +func mustAtoI(in string) int { + out, err := strconv.Atoi(in) + if err != nil { + panic(fmt.Sprintf("invalid version string: %s must be parsable as an int", in)) + } + return out +} diff --git a/vendor/github.com/palantir/godel/framework/builtintasks/packages.go b/vendor/github.com/palantir/godel/framework/builtintasks/packages.go index 8d4a0192..18a99049 100644 --- a/vendor/github.com/palantir/godel/framework/builtintasks/packages.go +++ b/vendor/github.com/palantir/godel/framework/builtintasks/packages.go @@ -21,6 +21,7 @@ import ( "github.com/spf13/cobra" "github.com/palantir/godel/framework/builtintasks/packages" + "github.com/palantir/godel/framework/godel/config" "github.com/palantir/godel/framework/godellauncher" ) @@ -35,11 +36,7 @@ func PackagesTask() godellauncher.Task { return err } - cfgDir, err := godellauncher.ConfigDirPath(projectDir) - if err != nil { - return err - } - cfg, err := godellauncher.ReadGodelConfig(cfgDir) + cfg, err := config.ReadGodelConfigFromProjectDir(projectDir) if err != nil { return err } diff --git a/vendor/github.com/palantir/godel/framework/builtintasks/pluginsconfig.go b/vendor/github.com/palantir/godel/framework/builtintasks/pluginsconfig.go index e0f05266..6aecb58d 100644 --- a/vendor/github.com/palantir/godel/framework/builtintasks/pluginsconfig.go +++ b/vendor/github.com/palantir/godel/framework/builtintasks/pluginsconfig.go @@ -23,10 +23,11 @@ import ( "github.com/spf13/cobra" "gopkg.in/yaml.v2" + "github.com/palantir/godel/framework/godel/config" "github.com/palantir/godel/framework/godellauncher" ) -func TasksConfigTask(tasksCfgInfo godellauncher.TasksConfigInfo) godellauncher.Task { +func TasksConfigTask(tasksCfgInfo config.TasksConfigInfo) godellauncher.Task { return godellauncher.CobraCLITask(&cobra.Command{ Use: "tasks-config", Short: "Prints the full YAML configuration used to load tasks and assets", @@ -36,7 +37,7 @@ func TasksConfigTask(tasksCfgInfo godellauncher.TasksConfigInfo) godellauncher.T }, nil) } -func printTasksCfgInfo(tasksCfgInfo godellauncher.TasksConfigInfo, stdout io.Writer) error { +func printTasksCfgInfo(tasksCfgInfo config.TasksConfigInfo, stdout io.Writer) error { if err := printWithHeader("Built-in plugin configuration", tasksCfgInfo.BuiltinPluginsConfig, stdout); err != nil { return err } diff --git a/vendor/github.com/palantir/godel/framework/builtintasks/tasks.go b/vendor/github.com/palantir/godel/framework/builtintasks/tasks.go index f5658195..007c6f5b 100644 --- a/vendor/github.com/palantir/godel/framework/builtintasks/tasks.go +++ b/vendor/github.com/palantir/godel/framework/builtintasks/tasks.go @@ -15,10 +15,11 @@ package builtintasks import ( + "github.com/palantir/godel/framework/godel/config" "github.com/palantir/godel/framework/godellauncher" ) -func Tasks(tasksCfgInfo godellauncher.TasksConfigInfo) []godellauncher.Task { +func Tasks(tasksCfgInfo config.TasksConfigInfo) []godellauncher.Task { return []godellauncher.Task{ VersionTask(), InstallTask(), diff --git a/vendor/github.com/palantir/godel/framework/builtintasks/update.go b/vendor/github.com/palantir/godel/framework/builtintasks/update.go index ecff5044..35f70f82 100644 --- a/vendor/github.com/palantir/godel/framework/builtintasks/update.go +++ b/vendor/github.com/palantir/godel/framework/builtintasks/update.go @@ -17,6 +17,7 @@ package builtintasks import ( "time" + "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/palantir/godel/framework/builtintasks/installupdate" @@ -25,11 +26,12 @@ import ( func UpdateTask() godellauncher.Task { var ( - syncFlag bool - versionFlag string - checksumFlag string - cacheDurationFlag time.Duration - globalCfg godellauncher.GlobalConfig + syncFlag bool + versionFlag string + checksumFlag string + cacheDurationFlag time.Duration + skipUpgradeConfigFlag bool + globalCfg godellauncher.GlobalConfig ) cmd := &cobra.Command{ @@ -40,21 +42,51 @@ func UpdateTask() godellauncher.Task { if err != nil { return err } + + var godelVersionBeforeUpdate installupdate.Version + if !skipUpgradeConfigFlag { + versionBeforeUpdateVar, err := installupdate.GodelVersion(projectDir) + if err != nil { + return errors.Wrapf(err, "failed to determine version before update") + } + godelVersionBeforeUpdate = versionBeforeUpdateVar + } + if syncFlag { // if sync flag is true, update version to what is specified in gödel.yml pkgSrc, err := installupdate.GodelPropsDistPkgInfo(projectDir) if err != nil { return err } - return installupdate.Update(projectDir, pkgSrc, cmd.OutOrStdout()) + if err := installupdate.Update(projectDir, pkgSrc, cmd.OutOrStdout()); err != nil { + return err + } + } else { + if err := installupdate.InstallVersion(projectDir, versionFlag, checksumFlag, cacheDurationFlag, false, cmd.OutOrStdout()); err != nil { + return err + } + } + + // run "upgrade-config" after upgrade if new version is greater than or equal to previous version. + if !skipUpgradeConfigFlag { + godelVersionAfterUpdate, err := installupdate.GodelVersion(projectDir) + if err != nil { + return errors.Wrapf(err, "failed to determine version after update") + } + if cmp, ok := godelVersionAfterUpdate.CompareTo(godelVersionBeforeUpdate); !ok || cmp >= 0 { + if err := installupdate.RunUpgradeConfig(projectDir, cmd.OutOrStdout(), cmd.OutOrStderr()); err != nil { + return err + } + } } - return installupdate.InstallVersion(projectDir, versionFlag, checksumFlag, cacheDurationFlag, false, cmd.OutOrStdout()) + return nil }, } cmd.Flags().BoolVar(&syncFlag, "sync", false, "use version and checksum specified in godel.properties (if true, all other flags are ignored)") cmd.Flags().StringVar(&versionFlag, "version", "", "version to update (if blank, uses latest version)") cmd.Flags().StringVar(&checksumFlag, "checksum", "", "expected checksum for package") cmd.Flags().DurationVar(&cacheDurationFlag, "cache-duration", time.Hour, "duration for which cache entries should be considered valid") + cmd.Flags().BoolVar(&skipUpgradeConfigFlag, "skip-upgrade-config", false, "skips running configuration upgrade tasks after running update") return godellauncher.CobraCLITask(cmd, &globalCfg) } diff --git a/vendor/github.com/palantir/godel/framework/builtintasks/upgradeconfig.go b/vendor/github.com/palantir/godel/framework/builtintasks/upgradeconfig.go index 33ec4fbc..29be4ddb 100644 --- a/vendor/github.com/palantir/godel/framework/builtintasks/upgradeconfig.go +++ b/vendor/github.com/palantir/godel/framework/builtintasks/upgradeconfig.go @@ -22,11 +22,15 @@ import ( "os" "path" "path/filepath" + "sort" "strings" + "github.com/palantir/pkg/matcher" "github.com/pkg/errors" "github.com/spf13/cobra" + "gopkg.in/yaml.v2" + "github.com/palantir/godel/framework/godel/config" "github.com/palantir/godel/framework/godellauncher" ) @@ -35,11 +39,13 @@ func UpgradeConfigTask(upgradeTasks []godellauncher.UpgradeConfigTask) godellaun upgradeConfigCmdName = "upgrade-config" dryRunFlagName = "dry-run" printContentFlagName = "print-content" + legacyFlagName = "legacy" ) var ( dryRunFlagVal bool printContentFlagVal bool + legacyFlagVal bool ) cmd := &cobra.Command{ @@ -49,6 +55,7 @@ func UpgradeConfigTask(upgradeTasks []godellauncher.UpgradeConfigTask) godellaun cmd.Flags().BoolVar(&dryRunFlagVal, dryRunFlagName, false, "print what the upgrade operation would do without writing changes") cmd.Flags().BoolVar(&printContentFlagVal, printContentFlagName, false, "print the content of the changes to stdout in addition to writing them") + cmd.Flags().BoolVar(&legacyFlagVal, legacyFlagName, false, "upgrade pre-2.0 legacy configuration") cmd.SilenceErrors = true cmd.SilenceUsage = true @@ -70,28 +77,10 @@ func UpgradeConfigTask(upgradeTasks []godellauncher.UpgradeConfigTask) godellaun if err != nil { return err } - - var failedUpgrades []string - for _, upgradeTask := range upgradeTasks { - changed, upgradedCfgBytes, err := upgradeConfigFile(upgradeTask, global, configDirPath, dryRunFlagVal, stdout) - if err != nil { - failedUpgrades = append(failedUpgrades, upgradeError(projectDir, path.Join(configDirPath, upgradeTask.ConfigFile), err)) - continue - } - if !changed { - continue - } - printUpgradedConfig(upgradeTask.ConfigFile, upgradedCfgBytes, dryRunFlagVal, printContentFlagVal, stdout) - } - - if len(failedUpgrades) == 0 { - return nil - } - dryRunPrintln(stdout, dryRunFlagVal, "Failed to upgrade configuration:") - for _, upgrade := range failedUpgrades { - dryRunPrintln(stdout, dryRunFlagVal, "\t"+upgrade) + if legacyFlagVal { + return runUpgradeLegacyConfig(upgradeTasks, global, projectDir, configDirPath, dryRunFlagVal, printContentFlagVal, cmd.OutOrStdout()) } - return fmt.Errorf("") + return runUpgradeConfig(upgradeTasks, global, projectDir, configDirPath, dryRunFlagVal, printContentFlagVal, cmd.OutOrStdout()) } rootCmd := godellauncher.CobraCmdToRootCmd(cmd) @@ -101,6 +90,37 @@ func UpgradeConfigTask(upgradeTasks []godellauncher.UpgradeConfigTask) godellaun } } +func runUpgradeConfig( + upgradeTasks []godellauncher.UpgradeConfigTask, + global godellauncher.GlobalConfig, + projectDir, configDirPath string, + dryRun, printContent bool, + stdout io.Writer, +) error { + + var failedUpgrades []string + for _, upgradeTask := range upgradeTasks { + changed, upgradedCfgBytes, err := upgradeConfigFile(upgradeTask, global, configDirPath, dryRun, stdout) + if err != nil { + failedUpgrades = append(failedUpgrades, upgradeError(projectDir, path.Join(configDirPath, upgradeTask.ConfigFile), err)) + continue + } + if !changed { + continue + } + printUpgradedConfig(upgradeTask.ConfigFile, upgradedCfgBytes, dryRun, printContent, stdout) + } + + if len(failedUpgrades) == 0 { + return nil + } + dryRunPrintln(stdout, dryRun, "Failed to upgrade configuration:") + for _, upgrade := range failedUpgrades { + dryRunPrintln(stdout, dryRun, "\t"+upgrade) + } + return fmt.Errorf("") +} + func dryRunPrintln(w io.Writer, dryRun bool, content string) { if !dryRun { fmt.Fprintln(w, content) @@ -187,3 +207,275 @@ func upgradeError(projectDir, configFilePath string, upgradeErr error) string { } return fmt.Sprintf("%s: %v", configFilePath, upgradeErr) } + +func runUpgradeLegacyConfig( + upgradeTasks []godellauncher.UpgradeConfigTask, + global godellauncher.GlobalConfig, + projectDir, configDirPath string, + dryRun, printContent bool, + stdout io.Writer, +) error { + + // record all of the original YML files in the directory + originalYMLFiles, err := dirYMLFiles(configDirPath) + if err != nil { + return err + } + // track all of the upgraded YML files + knownConfigFiles := make(map[string]struct{}) + + upgradeTasksMap := make(map[string]godellauncher.UpgradeConfigTask) + for _, upgradeTask := range upgradeTasks { + upgradeTasksMap[upgradeTask.ID] = upgradeTask + } + + var failedUpgrades []string + // perform hard-coded one-time upgrades + for _, currUpgrader := range hardCodedLegacyUpgraders { + if err := currUpgrader.upgradeConfig(configDirPath, dryRun, printContent, stdout); err != nil { + failedUpgrades = append(failedUpgrades, upgradeError(projectDir, path.Join(configDirPath, currUpgrader.configFileName()), err)) + } + knownConfigFiles[currUpgrader.configFileName()] = struct{}{} + } + + var legacyConfigUpgraderIDs []string + for _, upgradeTask := range upgradeTasks { + // consider current configuration file for the plugin as known (don't warn if these files already + // existed in config directory but were not processed by a legacy config upgrader). + knownConfigFiles[upgradeTask.ConfigFile] = struct{}{} + if upgradeTask.LegacyConfigFile == "" { + continue + } + legacyConfigUpgraderIDs = append(legacyConfigUpgraderIDs, upgradeTask.ID) + } + sort.Strings(legacyConfigUpgraderIDs) + for _, k := range legacyConfigUpgraderIDs { + upgradeTask, ok := upgradeTasksMap[k] + if !ok { + // legacy task does not have an upgrader: continue + continue + } + knownConfigFiles[upgradeTask.LegacyConfigFile] = struct{}{} + if err := upgradeLegacyConfig(upgradeTask, configDirPath, global, dryRun, printContent, stdout); err != nil { + failedUpgrades = append(failedUpgrades, upgradeError(projectDir, path.Join(configDirPath, upgradeTask.ConfigFile), err)) + continue + } + } + + var unhandledYMLFiles []string + for _, k := range originalYMLFiles { + if _, ok := knownConfigFiles[k]; ok { + continue + } + unhandledYMLFiles = append(unhandledYMLFiles, k) + } + if err := processUnhandledYMLFiles(configDirPath, unhandledYMLFiles, dryRun, stdout); err != nil { + return err + } + + if len(failedUpgrades) == 0 { + return nil + } + dryRunPrintln(stdout, dryRun, "Failed to upgrade configuration:") + for _, upgrade := range failedUpgrades { + dryRunPrintln(stdout, dryRun, "\t"+upgrade) + } + return fmt.Errorf("") +} + +var hardCodedLegacyUpgraders = []hardCodedLegacyUpgrader{ + &hardCodedLegacyUpgraderImpl{ + fileName: "exclude.yml", + upgradeConfigFn: func(configDirPath string, dryRun, printContent bool, stdout io.Writer) error { + // godel.yml itself is compatible. Only work to be performed is if "exclude.yml" exists and contains entries that + // differ from godel.yml. + legacyExcludeFilePath := path.Join(configDirPath, "exclude.yml") + if _, err := os.Stat(legacyExcludeFilePath); os.IsNotExist(err) { + // if legacy file does not exist, there is no upgrade to be performed + return nil + } + legacyConfigBytes, err := ioutil.ReadFile(legacyExcludeFilePath) + if err != nil { + return errors.Wrapf(err, "failed to read legacy configuration file") + } + var excludeCfg matcher.NamesPathsCfg + if err := yaml.UnmarshalStrict(legacyConfigBytes, &excludeCfg); err != nil { + return errors.Wrapf(err, "failed to unmarshal legacy exclude configuration") + } + + currentGodelConfig, err := config.ReadGodelConfigFromFile(path.Join(configDirPath, "godel.yml")) + if err != nil { + return errors.Wrapf(err, "failed to read godel configuration") + } + + existingNames := make(map[string]struct{}) + for _, name := range currentGodelConfig.Exclude.Names { + existingNames[name] = struct{}{} + } + existingPaths := make(map[string]struct{}) + for _, path := range currentGodelConfig.Exclude.Paths { + existingPaths[path] = struct{}{} + } + + modified := false + for _, legacyName := range excludeCfg.Names { + if _, ok := existingNames[legacyName]; ok { + continue + } + currentGodelConfig.Exclude.Names = append(currentGodelConfig.Exclude.Names, legacyName) + modified = true + } + for _, legacyPath := range excludeCfg.Paths { + if _, ok := existingPaths[legacyPath]; ok { + continue + } + currentGodelConfig.Exclude.Names = append(currentGodelConfig.Exclude.Paths, legacyPath) + modified = true + } + + // back up old configuration by moving it + if err := backupConfigFile(legacyExcludeFilePath, dryRun, stdout); err != nil { + return errors.Wrapf(err, "failed to back up legacy configuration file") + } + + if !modified { + // exclude.yml did not provide any new excludes: no need to write + return nil + } + + upgradedCfgBytes, err := yaml.Marshal(currentGodelConfig) + if err != nil { + return errors.Wrapf(err, "failed to marshal upgraded godel configuration") + } + + if !dryRun { + // write migrated configuration + if err := ioutil.WriteFile(path.Join(configDirPath, "godel.yml"), upgradedCfgBytes, 0644); err != nil { + return errors.Wrapf(err, "failed to write upgraded configuration") + } + } + printUpgradedConfig("godel.yml", upgradedCfgBytes, dryRun, printContent, stdout) + return nil + }, + }, +} + +func dirYMLFiles(inputDir string) ([]string, error) { + fis, err := ioutil.ReadDir(inputDir) + if err != nil { + return nil, errors.Wrapf(err, "failed to read input directory") + } + var ymlFiles []string + for _, fi := range fis { + if fi.IsDir() { + continue + } + if strings.HasSuffix(fi.Name(), ".yml") { + ymlFiles = append(ymlFiles, fi.Name()) + } + } + return ymlFiles, nil +} + +type hardCodedLegacyUpgrader interface { + configFileName() string + upgradeConfig(configDirPath string, dryRun, printContent bool, stdout io.Writer) error +} + +type hardCodedLegacyUpgraderImpl struct { + fileName string + upgradeConfigFn func(configDirPath string, dryRun, printContent bool, stdout io.Writer) error +} + +func (u *hardCodedLegacyUpgraderImpl) configFileName() string { + return u.fileName +} + +func (u *hardCodedLegacyUpgraderImpl) upgradeConfig(configDirPath string, dryRun, printContent bool, stdout io.Writer) error { + return u.upgradeConfigFn(configDirPath, dryRun, printContent, stdout) +} + +func upgradeLegacyConfig(upgradeTask godellauncher.UpgradeConfigTask, configDirPath string, global godellauncher.GlobalConfig, dryRun, printContent bool, stdout io.Writer) error { + legacyConfigFilePath := path.Join(configDirPath, upgradeTask.LegacyConfigFile) + if _, err := os.Stat(legacyConfigFilePath); os.IsNotExist(err) { + // if legacy file does not exist, there is no upgrade to be performed + return nil + } + legacyConfigBytes, err := ioutil.ReadFile(legacyConfigFilePath) + if err != nil { + return errors.Wrapf(err, "failed to read legacy configuration file") + } + + var ymlConfig yaml.MapSlice + if err := yaml.Unmarshal(legacyConfigBytes, &ymlConfig); err != nil { + return errors.Wrapf(err, "failed to unmarshal YAML configuration") + } + // add "legacy-config: true" as a key to indicate that this is a legacy configuration + ymlConfig = append([]yaml.MapItem{{Key: "legacy-config", Value: true}}, ymlConfig...) + + ymlCfgBytes, err := yaml.Marshal(ymlConfig) + if err != nil { + return errors.Wrapf(err, "failed to marshal YAML") + } + upgradedCfgBytes, err := upgradeTask.Run(ymlCfgBytes, global, stdout) + if err != nil { + return errors.Wrapf(err, "failed to upgrade configuration") + } + + // back up old configuration + if err := backupConfigFile(legacyConfigFilePath, dryRun, stdout); err != nil { + return errors.Wrapf(err, "failed to back up legacy configuration file") + } + + // back up destination file if it already exists + dstFilePath := path.Join(configDirPath, upgradeTask.ConfigFile) + if err := backupConfigFile(dstFilePath, dryRun, stdout); err != nil { + return errors.Wrapf(err, "failed to back up existing configuration file") + } + + // upgraded configuration is empty: no need to write + if string(upgradedCfgBytes) == "" { + return nil + } + + if !dryRun { + // write migrated configuration + if err := ioutil.WriteFile(dstFilePath, upgradedCfgBytes, 0644); err != nil { + return errors.Wrapf(err, "failed to write upgraded configuration") + } + } + printUpgradedConfig(upgradeTask.ConfigFile, upgradedCfgBytes, dryRun, printContent, stdout) + return nil +} + +func processUnhandledYMLFiles(configDir string, unknownYMLFiles []string, dryRun bool, stdout io.Writer) error { + if len(unknownYMLFiles) == 0 { + return nil + } + + var unknownNonEmptyFiles []string + for _, currUnknownFile := range unknownYMLFiles { + currPath := path.Join(configDir, currUnknownFile) + bytes, err := ioutil.ReadFile(currPath) + if err != nil { + return errors.Wrapf(err, "failed to read configuration file") + } + // if unknown file is empty, just back it up + if string(bytes) == "" { + if err := backupConfigFile(currPath, dryRun, stdout); err != nil { + return err + } + continue + } + unknownNonEmptyFiles = append(unknownNonEmptyFiles, currUnknownFile) + } + + if len(unknownNonEmptyFiles) == 0 { + return nil + } + + // if non-empty unknown files were present, print warning + dryRunPrintln(stdout, dryRun, fmt.Sprintf(`WARNING: The following configuration file(s) were non-empty and had no known upgraders for legacy configuration: %v`, unknownNonEmptyFiles)) + dryRunPrintln(stdout, dryRun, fmt.Sprintf(` If these configuration file(s) are for plugins, add the plugins to the configuration and rerun the upgrade task.`)) + return nil +} diff --git a/vendor/github.com/palantir/godel/framework/builtintasks/upgradelegacyconfig.go b/vendor/github.com/palantir/godel/framework/builtintasks/upgradelegacyconfig.go deleted file mode 100644 index e80e8859..00000000 --- a/vendor/github.com/palantir/godel/framework/builtintasks/upgradelegacyconfig.go +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2016 Palantir Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package builtintasks - -import ( - "fmt" - "io" - "io/ioutil" - "os" - "path" - "sort" - - "github.com/pkg/errors" - "github.com/spf13/cobra" - "gopkg.in/yaml.v2" - - "github.com/palantir/godel/framework/godellauncher" - "github.com/palantir/godel/framework/internal/legacyplugins" -) - -func UpgradeLegacyConfigTask(upgradeTasks []godellauncher.UpgradeConfigTask) godellauncher.Task { - const ( - upgradeLegacyConfigCmdName = "upgrade-legacy-config" - dryRunFlagName = "dry-run" - printContentFlagName = "print-content" - ) - - var ( - dryRunFlagVal bool - printContentFlagVal bool - ) - - cmd := &cobra.Command{ - Use: upgradeLegacyConfigCmdName, - Short: "Upgrade the legacy configuration", - } - - cmd.Flags().BoolVar(&dryRunFlagVal, dryRunFlagName, false, "print what the upgrade operation would do without writing changes") - cmd.Flags().BoolVar(&printContentFlagVal, printContentFlagName, false, "print the content of the changes to stdout in addition to writing them") - - cmd.SilenceErrors = true - cmd.SilenceUsage = true - return godellauncher.Task{ - Name: cmd.Use, - Description: cmd.Short, - RunImpl: func(t *godellauncher.Task, global godellauncher.GlobalConfig, stdout io.Writer) error { - args := []string{global.Executable} - args = append(args, global.Task) - args = append(args, global.TaskArgs...) - os.Args = args - - cmd.RunE = func(cmd *cobra.Command, args []string) error { - projectDir, err := global.ProjectDir() - if err != nil { - return err - } - cfgDirPath, err := godellauncher.ConfigDirPath(projectDir) - if err != nil { - return err - } - - upgradeTasksMap := make(map[string]godellauncher.UpgradeConfigTask) - for _, upgradeTask := range upgradeTasks { - upgradeTasksMap[upgradeTask.ID] = upgradeTask - } - - var legacyConfigUpgraderKeys []string - for k := range legacyplugins.LegacyConfigUpgraders { - legacyConfigUpgraderKeys = append(legacyConfigUpgraderKeys, k) - } - sort.Strings(legacyConfigUpgraderKeys) - - var failedUpgrades []string - for _, k := range legacyConfigUpgraderKeys { - upgradeTask, ok := upgradeTasksMap[k] - if !ok { - // legacy task does not have an upgrader: continue - continue - } - if err := upgradeLegacyConfig(upgradeTask, cfgDirPath, global, dryRunFlagVal, printContentFlagVal, stdout); err != nil { - failedUpgrades = append(failedUpgrades, upgradeError(projectDir, path.Join(cfgDirPath, upgradeTask.ConfigFile), err)) - continue - } - } - - if len(failedUpgrades) == 0 { - return nil - } - dryRunPrintln(stdout, dryRunFlagVal, "Failed to upgrade configuration:") - for _, upgrade := range failedUpgrades { - dryRunPrintln(stdout, dryRunFlagVal, "\t"+upgrade) - } - return fmt.Errorf("") - } - - rootCmd := godellauncher.CobraCmdToRootCmd(cmd) - rootCmd.SetOutput(stdout) - return rootCmd.Execute() - }, - } -} - -func upgradeLegacyConfig(upgradeTask godellauncher.UpgradeConfigTask, configDirPath string, global godellauncher.GlobalConfig, dryRun, printContent bool, stdout io.Writer) error { - legacyConfigFilePath := path.Join(configDirPath, legacyplugins.LegacyConfigUpgraders[upgradeTask.ID].LegacyConfigFileName) - if _, err := os.Stat(legacyConfigFilePath); os.IsNotExist(err) { - // if legacy file does not exist, there is no upgrade to be performed - return nil - } - - legacyConfigBytes, err := ioutil.ReadFile(legacyConfigFilePath) - if err != nil { - return errors.Wrapf(err, "failed to read legacy configuration file") - } - - var ymlConfig yaml.MapSlice - if err := yaml.Unmarshal(legacyConfigBytes, &ymlConfig); err != nil { - return errors.Wrapf(err, "failed to unmarshal YAML configuration") - } - // add "legacy-config: true" as a key to indicate that this is a legacy configuration - ymlConfig = append([]yaml.MapItem{{Key: "legacy-config", Value: true}}, ymlConfig...) - - ymlCfgBytes, err := yaml.Marshal(ymlConfig) - if err != nil { - return errors.Wrapf(err, "failed to marshal YAML") - } - upgradedCfgBytes, err := upgradeTask.Run(ymlCfgBytes, global, stdout) - if err != nil { - return errors.Wrapf(err, "failed to upgrade configuration") - } - - // back up old configuration by moving it - if err := backupConfigFile(legacyConfigFilePath, dryRun, stdout); err != nil { - return errors.Wrapf(err, "failed to back up legacy configuration file") - } - - // upgraded configuration is empty: no need to write - if string(upgradedCfgBytes) == "" { - return nil - } - - if !dryRun { - // write migrated configuration - if err := ioutil.WriteFile(path.Join(configDirPath, upgradeTask.ConfigFile), upgradedCfgBytes, 0644); err != nil { - return errors.Wrapf(err, "failed to write upgraded configuration") - } - } - printUpgradedConfig(upgradeTask.ConfigFile, upgradedCfgBytes, dryRun, printContent, stdout) - - return nil -} diff --git a/vendor/github.com/palantir/godel/framework/artifactresolver/config.go b/vendor/github.com/palantir/godel/framework/godel/config/artifactresolver.go similarity index 53% rename from vendor/github.com/palantir/godel/framework/artifactresolver/config.go rename to vendor/github.com/palantir/godel/framework/godel/config/artifactresolver.go index 5ecc8389..fd6ea4f1 100644 --- a/vendor/github.com/palantir/godel/framework/artifactresolver/config.go +++ b/vendor/github.com/palantir/godel/framework/godel/config/artifactresolver.go @@ -12,41 +12,50 @@ // See the License for the specific language governing permissions and // limitations under the License. -package artifactresolver +package config import ( - "fmt" "strings" "github.com/pkg/errors" + "github.com/palantir/godel/framework/artifactresolver" + "github.com/palantir/godel/framework/godel/config/internal/v0" "github.com/palantir/godel/pkg/osarch" ) -type LocatorWithResolverParam struct { - LocatorWithChecksums LocatorParam - Resolver Resolver +type LocatorWithResolverConfig v0.LocatorWithResolverConfig + +func ToLocatorWithResolverConfig(in LocatorWithResolverConfig) v0.LocatorWithResolverConfig { + return v0.LocatorWithResolverConfig(in) } -type LocatorWithResolverConfig struct { - Locator LocatorConfig `yaml:"locator"` - Resolver string `yaml:"resolver"` +func ToLocatorWithResolverConfigs(in []LocatorWithResolverConfig) []v0.LocatorWithResolverConfig { + if in == nil { + return nil + } + out := make([]v0.LocatorWithResolverConfig, len(in)) + for i, v := range in { + out[i] = ToLocatorWithResolverConfig(v) + } + return out } -func (c *LocatorWithResolverConfig) ToParam() (LocatorWithResolverParam, error) { - locator, err := c.Locator.ToParam() +func (c *LocatorWithResolverConfig) ToParam() (artifactresolver.LocatorWithResolverParam, error) { + locatorCfg := LocatorConfig(c.Locator) + locator, err := locatorCfg.ToParam() if err != nil { - return LocatorWithResolverParam{}, errors.Wrapf(err, "invalid locator") + return artifactresolver.LocatorWithResolverParam{}, errors.Wrapf(err, "invalid locator") } - var resolver Resolver + var resolver artifactresolver.Resolver if c.Resolver != "" { - resolverVal, err := NewTemplateResolver(c.Resolver) + resolverVal, err := artifactresolver.NewTemplateResolver(c.Resolver) if err != nil { - return LocatorWithResolverParam{}, errors.Wrapf(err, "invalid resolver") + return artifactresolver.LocatorWithResolverParam{}, errors.Wrapf(err, "invalid resolver") } resolver = resolverVal } - return LocatorWithResolverParam{ + return artifactresolver.LocatorWithResolverParam{ LocatorWithChecksums: locator, Resolver: resolver, }, nil @@ -55,39 +64,33 @@ func (c *LocatorWithResolverConfig) ToParam() (LocatorWithResolverParam, error) // ConfigProviderLocatorWithResolverConfig is the configuration for a locator with resolver for a configuration // provider. It differs from a LocatorWithResolverConfig in that the locator is a ConfigProviderLocatorConfig rather // than a LocatorConfig. -type ConfigProviderLocatorWithResolverConfig struct { - Locator ConfigProviderLocatorConfig `yaml:"locator"` - Resolver string `yaml:"resolver"` -} +type ConfigProviderLocatorWithResolverConfig v0.ConfigProviderLocatorWithResolverConfig // ToParam converts the configuration into a LocatorWithResolverParam. Any checksums that exist are put in a map where // the key is the current OS/Arch. -func (c *ConfigProviderLocatorWithResolverConfig) ToParam() (LocatorWithResolverParam, error) { - locatorCfg, err := c.Locator.ToLocatorConfig() +func (c *ConfigProviderLocatorWithResolverConfig) ToParam() (artifactresolver.LocatorWithResolverParam, error) { + providerLocatorCfg := ConfigProviderLocatorConfig(c.Locator) + locatorCfg, err := providerLocatorCfg.ToLocatorConfig() if err != nil { - return LocatorWithResolverParam{}, err + return artifactresolver.LocatorWithResolverParam{}, err } cfg := LocatorWithResolverConfig{ - Locator: locatorCfg, + Locator: v0.LocatorConfig(locatorCfg), Resolver: c.Resolver, } return cfg.ToParam() } -type LocatorParam struct { - Locator - Checksums map[osarch.OSArch]string -} +type LocatorConfig v0.LocatorConfig -type LocatorConfig struct { - ID string `yaml:"id"` - Checksums map[string]string `yaml:"checksums"` +func ToLocatorConfig(in LocatorConfig) v0.LocatorConfig { + return v0.LocatorConfig(in) } -func (c *LocatorConfig) ToParam() (LocatorParam, error) { +func (c *LocatorConfig) ToParam() (artifactresolver.LocatorParam, error) { parts := strings.Split(c.ID, ":") if len(parts) != 3 { - return LocatorParam{}, errors.Errorf("locator ID must consist of 3 colon-delimited components ([group]:[product]:[version]), but had %d: %q", len(parts), c.ID) + return artifactresolver.LocatorParam{}, errors.Errorf("locator ID must consist of 3 colon-delimited components ([group]:[product]:[version]), but had %d: %q", len(parts), c.ID) } var checksums map[osarch.OSArch]string if c.Checksums != nil { @@ -95,13 +98,13 @@ func (c *LocatorConfig) ToParam() (LocatorParam, error) { for k, v := range c.Checksums { osArchKey, err := osarch.New(k) if err != nil { - return LocatorParam{}, errors.Wrapf(err, "invalid OSArch specified in checksum key for %s", c.ID) + return artifactresolver.LocatorParam{}, errors.Wrapf(err, "invalid OSArch specified in checksum key for %s", c.ID) } checksums[osArchKey] = v } } - param := LocatorParam{ - Locator: Locator{ + param := artifactresolver.LocatorParam{ + Locator: artifactresolver.Locator{ Group: parts[0], Product: parts[1], Version: parts[2], @@ -116,10 +119,7 @@ var configProviderOSArch = osarch.Current() // ConfigProviderLocatorConfig is the configuration for a locator for a configuration provider. It differs from a // LocatorConfig in that only a single checksum can be specified. -type ConfigProviderLocatorConfig struct { - ID string `yaml:"id"` - Checksum string `yaml:"checksum"` -} +type ConfigProviderLocatorConfig v0.ConfigProviderLocatorConfig // ToLocatorConfig translates the ConfigProviderLocatorConfig into a LocatorConfig where the checksum (if any exists) is // keyed as the current OS/Arch. @@ -135,13 +135,3 @@ func (c *ConfigProviderLocatorConfig) ToLocatorConfig() (LocatorConfig, error) { Checksums: checksums, }, nil } - -type Locator struct { - Group string - Product string - Version string -} - -func (l Locator) String() string { - return fmt.Sprintf("%s:%s:%s", l.Group, l.Product, l.Version) -} diff --git a/vendor/github.com/palantir/godel/framework/godellauncher/config_test.go b/vendor/github.com/palantir/godel/framework/godel/config/config_test.go similarity index 65% rename from vendor/github.com/palantir/godel/framework/godellauncher/config_test.go rename to vendor/github.com/palantir/godel/framework/godel/config/config_test.go index 2cfc20a9..dea8daed 100644 --- a/vendor/github.com/palantir/godel/framework/godellauncher/config_test.go +++ b/vendor/github.com/palantir/godel/framework/godel/config/config_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package godellauncher_test +package config_test import ( "testing" @@ -21,32 +21,31 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/yaml.v2" - "github.com/palantir/godel/framework/artifactresolver" - "github.com/palantir/godel/framework/godellauncher" + "github.com/palantir/godel/framework/godel/config" ) func TestMarshalConfig(t *testing.T) { - cfg := godellauncher.GodelConfig{ - TasksConfig: godellauncher.TasksConfig{ - Plugins: godellauncher.PluginsConfig{ - Plugins: []godellauncher.SinglePluginConfig{ + cfg := config.GodelConfig{ + TasksConfig: config.ToTasksConfig(config.TasksConfig{ + Plugins: config.ToPluginsConfig(config.PluginsConfig{ + Plugins: config.ToSinglePluginConfigs([]config.SinglePluginConfig{ { - LocatorWithResolverConfig: artifactresolver.LocatorWithResolverConfig{ - Locator: artifactresolver.LocatorConfig{ + LocatorWithResolverConfig: config.ToLocatorWithResolverConfig(config.LocatorWithResolverConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ ID: "com.palantir:plugin:1.0.0", - }, - }, - Assets: []artifactresolver.LocatorWithResolverConfig{ + }), + }), + Assets: config.ToLocatorWithResolverConfigs([]config.LocatorWithResolverConfig{ { - Locator: artifactresolver.LocatorConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ ID: "com.palantir:asset:1.0.0", - }, + }), }, - }, + }), }, - }, - }, - }, + }), + }), + }), } got, err := yaml.Marshal(cfg) require.NoError(t, err) @@ -89,34 +88,34 @@ plugins: - locator: id: "com.palantir:asset:1.0.0" ` - var got godellauncher.GodelConfig + var got config.GodelConfig err := yaml.Unmarshal([]byte(cfgYAML), &got) require.NoError(t, err) - want := godellauncher.GodelConfig{ - TasksConfig: godellauncher.TasksConfig{ - Plugins: godellauncher.PluginsConfig{ + want := config.GodelConfig{ + TasksConfig: config.ToTasksConfig(config.TasksConfig{ + Plugins: config.ToPluginsConfig(config.PluginsConfig{ DefaultResolvers: []string{ "foo/repo/{{GroupPath}}/{{Product}}/{{Version}}/{{Product}}-{{OS}}-{{Arch}}-{{Version}}.tgz", }, - Plugins: []godellauncher.SinglePluginConfig{ + Plugins: config.ToSinglePluginConfigs([]config.SinglePluginConfig{ { - LocatorWithResolverConfig: artifactresolver.LocatorWithResolverConfig{ - Locator: artifactresolver.LocatorConfig{ + LocatorWithResolverConfig: config.ToLocatorWithResolverConfig(config.LocatorWithResolverConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ ID: "com.palantir:plugin:1.0.0", - }, - }, - Assets: []artifactresolver.LocatorWithResolverConfig{ + }), + }), + Assets: config.ToLocatorWithResolverConfigs([]config.LocatorWithResolverConfig{ { - Locator: artifactresolver.LocatorConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ ID: "com.palantir:asset:1.0.0", - }, + }), }, - }, + }), }, - }, - }, - }, + }), + }), + }), } assert.Equal(t, want, got) } @@ -144,54 +143,54 @@ plugins: - locator: id: "com.palantir:asset:1.0.0" ` - var got godellauncher.GodelConfig + var got config.GodelConfig err := yaml.Unmarshal([]byte(cfgYAML), &got) require.NoError(t, err) - want := godellauncher.GodelConfig{ - TasksConfig: godellauncher.TasksConfig{ - DefaultTasks: godellauncher.DefaultTasksConfig{ + want := config.GodelConfig{ + TasksConfig: config.ToTasksConfig(config.TasksConfig{ + DefaultTasks: config.ToDefaultTasksConfig(config.DefaultTasksConfig{ DefaultResolvers: []string{ "default/repo/{{GroupPath}}/{{Product}}/{{Version}}/{{Product}}-{{OS}}-{{Arch}}-{{Version}}.tgz", }, - Tasks: map[string]godellauncher.SingleDefaultTaskConfig{ + Tasks: config.ToTasks(map[string]config.SingleDefaultTaskConfig{ "com.palantir.godel:format": { DefaultAssetsToExclude: []string{ "com.palantir.godel:foo-asset", "com.palantir.godel:bar-asset", }, - Assets: []artifactresolver.LocatorWithResolverConfig{ + Assets: config.ToLocatorWithResolverConfigs([]config.LocatorWithResolverConfig{ { - Locator: artifactresolver.LocatorConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ ID: "com.palantir.godel:bar-asset:1.0.0", - }, + }), }, - }, + }), }, - }, - }, - Plugins: godellauncher.PluginsConfig{ + }), + }), + Plugins: config.ToPluginsConfig(config.PluginsConfig{ DefaultResolvers: []string{ "foo/repo/{{GroupPath}}/{{Product}}/{{Version}}/{{Product}}-{{OS}}-{{Arch}}-{{Version}}.tgz", }, - Plugins: []godellauncher.SinglePluginConfig{ + Plugins: config.ToSinglePluginConfigs([]config.SinglePluginConfig{ { - LocatorWithResolverConfig: artifactresolver.LocatorWithResolverConfig{ - Locator: artifactresolver.LocatorConfig{ + LocatorWithResolverConfig: config.ToLocatorWithResolverConfig(config.LocatorWithResolverConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ ID: "com.palantir:plugin:1.0.0", - }, - }, - Assets: []artifactresolver.LocatorWithResolverConfig{ + }), + }), + Assets: config.ToLocatorWithResolverConfigs([]config.LocatorWithResolverConfig{ { - Locator: artifactresolver.LocatorConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ ID: "com.palantir:asset:1.0.0", - }, + }), }, - }, + }), }, - }, - }, - }, + }), + }), + }), } assert.Equal(t, want, got) } @@ -206,7 +205,7 @@ plugins: checksums: darwin-amd64: d22c0ac9d3b65ebe5b830c1324f3d43e777ebc085c580af7c39fb1e5e3c909a7 ` - var cfg godellauncher.PluginsConfig + var cfg config.PluginsConfig err := yaml.Unmarshal([]byte(cfgContent), &cfg) require.NoError(t, err) _, err = cfg.ToParam() @@ -219,7 +218,7 @@ plugins: - locator: id: "tester:1.0.0" ` - var cfg godellauncher.PluginsConfig + var cfg config.PluginsConfig err := yaml.Unmarshal([]byte(cfgContent), &cfg) require.NoError(t, err) _, err = cfg.ToParam() diff --git a/vendor/github.com/palantir/godel/framework/godel/config/godel.go b/vendor/github.com/palantir/godel/framework/godel/config/godel.go new file mode 100644 index 00000000..d78e3d47 --- /dev/null +++ b/vendor/github.com/palantir/godel/framework/godel/config/godel.go @@ -0,0 +1,181 @@ +// Copyright 2016 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright (c) 2016 Palantir Technologies Inc. All rights reserved. +// Use of this source code is governed by the Apache License, Version 2.0 +// that can be found in the LICENSE file. + +package config + +import ( + "github.com/palantir/godel/framework/artifactresolver" + "github.com/palantir/godel/framework/godel/config/internal/v0" + "github.com/palantir/godel/framework/godellauncher" +) + +type GodelConfig v0.GodelConfig + +type TasksConfig v0.TasksConfig + +type TasksConfigInfo struct { + // BuiltinPluginsConfig is the configuration for built-in plugins that is built as part of gödel. + BuiltinPluginsConfig PluginsConfig + // TasksConfig is the fully resolved user-provided tasks configuration. + TasksConfig TasksConfig + // DefaultTasksPluginsConfig is the plugin configuration used to load the default tasks. It is a result of combining + // the BuiltinPluginsConfig with the DefaultTasks config of TasksConfig. + DefaultTasksPluginsConfig PluginsConfig +} + +func ToTasksConfig(in TasksConfig) v0.TasksConfig { + return v0.TasksConfig(in) +} + +// Combine combines the provided TasksConfig configurations with the base configuration. In cases where values are +// overwritten, the last (most recent) values in the inputs will take precedence. +func (c *TasksConfig) Combine(configs ...TasksConfig) { + if c.DefaultTasks.Tasks == nil { + c.DefaultTasks.Tasks = make(map[string]v0.SingleDefaultTaskConfig) + } + + for _, cfg := range configs { + // DefaultTask resolvers are appended + c.DefaultTasks.DefaultResolvers = append(c.DefaultTasks.DefaultResolvers, cfg.DefaultTasks.DefaultResolvers...) + // DefaultTask tasks key/values are simply copied (and overwritten with last writer wins for any duplicate keys) + for k, v := range cfg.DefaultTasks.Tasks { + c.DefaultTasks.Tasks[k] = v + } + + // Plugin resolvers and definitions are appended + c.Plugins.DefaultResolvers = append(c.Plugins.DefaultResolvers, cfg.Plugins.DefaultResolvers...) + c.Plugins.Plugins = append(c.Plugins.Plugins, cfg.Plugins.Plugins...) + } +} + +type DefaultTasksConfig v0.DefaultTasksConfig + +func ToDefaultTasksConfig(in DefaultTasksConfig) v0.DefaultTasksConfig { + return v0.DefaultTasksConfig(in) +} + +type TasksConfigProvidersConfig v0.TasksConfigProvidersConfig + +func (c *TasksConfigProvidersConfig) ToParam() (godellauncher.TasksConfigProvidersParam, error) { + var defaultResolvers []artifactresolver.Resolver + for _, resolverStr := range c.DefaultResolvers { + resolver, err := artifactresolver.NewTemplateResolver(resolverStr) + if err != nil { + return godellauncher.TasksConfigProvidersParam{}, err + } + defaultResolvers = append(defaultResolvers, resolver) + } + var configProviders []artifactresolver.LocatorWithResolverParam + for _, provider := range c.ConfigProviders { + provider := ConfigProviderLocatorWithResolverConfig(provider) + providerVal, err := provider.ToParam() + if err != nil { + return godellauncher.TasksConfigProvidersParam{}, err + } + configProviders = append(configProviders, providerVal) + } + return godellauncher.TasksConfigProvidersParam{ + DefaultResolvers: defaultResolvers, + ConfigProviders: configProviders, + }, nil +} + +type SingleDefaultTaskConfig v0.SingleDefaultTaskConfig + +func ToSingleDefaultTaskConfig(in SingleDefaultTaskConfig) v0.SingleDefaultTaskConfig { + return v0.SingleDefaultTaskConfig(in) +} + +func ToTasks(in map[string]SingleDefaultTaskConfig) map[string]v0.SingleDefaultTaskConfig { + if in == nil { + return nil + } + out := make(map[string]v0.SingleDefaultTaskConfig, len(in)) + for k, v := range in { + out[k] = ToSingleDefaultTaskConfig(v) + } + return out +} + +type PluginsConfig v0.PluginsConfig + +func ToPluginsConfig(in PluginsConfig) v0.PluginsConfig { + return v0.PluginsConfig(in) +} + +func (c *PluginsConfig) ToParam() (godellauncher.PluginsParam, error) { + var defaultResolvers []artifactresolver.Resolver + for _, resolverStr := range c.DefaultResolvers { + resolver, err := artifactresolver.NewTemplateResolver(resolverStr) + if err != nil { + return godellauncher.PluginsParam{}, err + } + defaultResolvers = append(defaultResolvers, resolver) + } + var plugins []godellauncher.SinglePluginParam + for _, plugin := range c.Plugins { + plugin := SinglePluginConfig(plugin) + pluginParam, err := plugin.ToParam() + if err != nil { + return godellauncher.PluginsParam{}, err + } + plugins = append(plugins, pluginParam) + } + return godellauncher.PluginsParam{ + DefaultResolvers: defaultResolvers, + Plugins: plugins, + }, nil +} + +type SinglePluginConfig v0.SinglePluginConfig + +func ToSinglePluginConfig(in SinglePluginConfig) v0.SinglePluginConfig { + return v0.SinglePluginConfig(in) +} + +func ToSinglePluginConfigs(in []SinglePluginConfig) []v0.SinglePluginConfig { + if in == nil { + return nil + } + out := make([]v0.SinglePluginConfig, len(in)) + for i, v := range in { + out[i] = ToSinglePluginConfig(v) + } + return out +} + +func (c *SinglePluginConfig) ToParam() (godellauncher.SinglePluginParam, error) { + locatorWithResolverConfig := LocatorWithResolverConfig(c.LocatorWithResolverConfig) + locatorWithResolverParam, err := locatorWithResolverConfig.ToParam() + if err != nil { + return godellauncher.SinglePluginParam{}, err + } + var assets []artifactresolver.LocatorWithResolverParam + for _, assetCfg := range c.Assets { + assetCfg := LocatorWithResolverConfig(assetCfg) + assetParamVal, err := assetCfg.ToParam() + if err != nil { + return godellauncher.SinglePluginParam{}, err + } + assets = append(assets, assetParamVal) + } + return godellauncher.SinglePluginParam{ + LocatorWithResolverParam: locatorWithResolverParam, + Assets: assets, + }, nil +} diff --git a/vendor/github.com/palantir/godel/framework/godel/config/internal/legacy/config.go b/vendor/github.com/palantir/godel/framework/godel/config/internal/legacy/config.go new file mode 100644 index 00000000..b7551bc3 --- /dev/null +++ b/vendor/github.com/palantir/godel/framework/godel/config/internal/legacy/config.go @@ -0,0 +1,143 @@ +// Copyright 2016 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright (c) 2016 Palantir Technologies Inc. All rights reserved. +// Use of this source code is governed by the Apache License, Version 2.0 +// that can be found in the LICENSE file. + +package legacy + +import ( + "sort" + + "github.com/palantir/pkg/matcher" + "github.com/pkg/errors" + "gopkg.in/yaml.v2" + + "github.com/palantir/godel/framework/godel/config/internal/v0" +) + +type GodelConfig struct { + // DefaultTasks specifies the configuration for the default tasks for gödel. + DefaultTasks DefaultTasksConfig `yaml:"default-tasks"` + // Plugins specifies the configuration for the plugins configured for gödel. + Plugins PluginsConfig `yaml:"plugins"` + // Exclude specifies the files and directories that should be excluded from gödel operations. + Exclude matcher.NamesPathsCfg `yaml:"exclude"` +} + +type DefaultTasksConfig map[string]SingleDefaultTaskConfig + +type SingleDefaultTaskConfig struct { + // LocatorWithResolverConfig contains the configuration for the locator and resolver. Any value provided here + // overrides the default value. + LocatorWithResolverConfig `yaml:",inline"` + // ExcludeAllDefaultAssets specifies whether or not all of the default assets should be excluded. If this value is + // true, then DefaultAssetsToExclude is ignored. + ExcludeAllDefaultAssets bool `yaml:"exclude-all-default-assets"` + // DefaultAssetsToExclude specifies the assets that should be excluded if they are provided by the default + // configuration. Only used if ExcludeAllDefaultAssets is false. + DefaultAssetsToExclude []string `yaml:"exclude-default-assets"` + // Assets specifies the custom assets that should be added to the default task. + Assets []LocatorWithResolverConfig `yaml:"assets"` +} + +type PluginsConfig struct { + DefaultResolvers []string `yaml:"resolvers"` + Plugins []SinglePluginConfig `yaml:"plugins"` +} + +type SinglePluginConfig struct { + // LocatorWithResolverConfig stores the locator and the resolver for the plugin. + LocatorWithResolverConfig `yaml:",inline"` + // Assets stores the locators and resolvers for the assets for this plugin. + Assets []LocatorWithResolverConfig `yaml:"assets"` +} + +type LocatorWithResolverConfig struct { + Locator LocatorConfig `yaml:"locator"` + Resolver string `yaml:"resolver"` +} + +type LocatorConfig struct { + ID string `yaml:"id"` + Checksums map[string]string `yaml:"checksums"` +} + +func UpgradeConfig(cfgBytes []byte) ([]byte, error) { + var legacyCfg GodelConfig + if err := yaml.UnmarshalStrict(cfgBytes, &legacyCfg); err != nil { + return nil, errors.Wrapf(err, "failed to unmarshal license-plugin legacy configuration") + } + + v0Cfg := v0.GodelConfig{} + + // DefaultTasks + var sortedKeys []string + for k := range legacyCfg.DefaultTasks { + sortedKeys = append(sortedKeys, k) + } + sort.Strings(sortedKeys) + if len(sortedKeys) > 0 { + v0Cfg.TasksConfig.DefaultTasks.Tasks = make(map[string]v0.SingleDefaultTaskConfig) + for _, k := range sortedKeys { + legacyDefaultTaskCfg := legacyCfg.DefaultTasks[k] + v0Cfg.TasksConfig.DefaultTasks.Tasks[k] = v0.SingleDefaultTaskConfig{ + LocatorWithResolverConfig: toV0LocatorWithResolverConfig(legacyDefaultTaskCfg.LocatorWithResolverConfig), + ExcludeAllDefaultAssets: legacyDefaultTaskCfg.ExcludeAllDefaultAssets, + DefaultAssetsToExclude: legacyDefaultTaskCfg.DefaultAssetsToExclude, + Assets: toV0LocatorWithResolverConfigs(legacyDefaultTaskCfg.Assets), + } + } + + } + + // Plugins + for _, legacyPluginConfig := range legacyCfg.Plugins.Plugins { + v0Cfg.Plugins.Plugins = append(v0Cfg.Plugins.Plugins, v0.SinglePluginConfig{ + LocatorWithResolverConfig: toV0LocatorWithResolverConfig(legacyPluginConfig.LocatorWithResolverConfig), + Assets: toV0LocatorWithResolverConfigs(legacyPluginConfig.Assets), + }) + } + + // Exclude + v0Cfg.Exclude = legacyCfg.Exclude + + upgradedBytes, err := yaml.Marshal(v0Cfg) + if err != nil { + return nil, errors.Wrapf(err, "failed to marshal godel v0 configuration") + } + return upgradedBytes, nil +} + +func toV0LocatorWithResolverConfig(in LocatorWithResolverConfig) v0.LocatorWithResolverConfig { + return v0.LocatorWithResolverConfig{ + Locator: v0.LocatorConfig{ + ID: in.Locator.ID, + Checksums: in.Locator.Checksums, + }, + Resolver: in.Resolver, + } +} + +func toV0LocatorWithResolverConfigs(in []LocatorWithResolverConfig) []v0.LocatorWithResolverConfig { + if in == nil { + return nil + } + out := make([]v0.LocatorWithResolverConfig, len(in)) + for i, v := range in { + out[i] = toV0LocatorWithResolverConfig(v) + } + return out +} diff --git a/vendor/github.com/palantir/godel/framework/godel/config/internal/v0/artifactresolver.go b/vendor/github.com/palantir/godel/framework/godel/config/internal/v0/artifactresolver.go new file mode 100644 index 00000000..a80330bf --- /dev/null +++ b/vendor/github.com/palantir/godel/framework/godel/config/internal/v0/artifactresolver.go @@ -0,0 +1,40 @@ +// Copyright 2016 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v0 + +type LocatorWithResolverConfig struct { + Locator LocatorConfig `yaml:"locator"` + Resolver string `yaml:"resolver"` +} + +// ConfigProviderLocatorWithResolverConfig is the configuration for a locator with resolver for a configuration +// provider. It differs from a LocatorWithResolverConfig in that the locator is a ConfigProviderLocatorConfig rather +// than a LocatorConfig. +type ConfigProviderLocatorWithResolverConfig struct { + Locator ConfigProviderLocatorConfig `yaml:"locator"` + Resolver string `yaml:"resolver"` +} + +type LocatorConfig struct { + ID string `yaml:"id"` + Checksums map[string]string `yaml:"checksums"` +} + +// ConfigProviderLocatorConfig is the configuration for a locator for a configuration provider. It differs from a +// LocatorConfig in that only a single checksum can be specified. +type ConfigProviderLocatorConfig struct { + ID string `yaml:"id"` + Checksum string `yaml:"checksum"` +} diff --git a/vendor/github.com/palantir/godel/framework/godel/config/internal/v0/godel.go b/vendor/github.com/palantir/godel/framework/godel/config/internal/v0/godel.go new file mode 100644 index 00000000..58dc658d --- /dev/null +++ b/vendor/github.com/palantir/godel/framework/godel/config/internal/v0/godel.go @@ -0,0 +1,82 @@ +// Copyright 2016 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright (c) 2016 Palantir Technologies Inc. All rights reserved. +// Use of this source code is governed by the Apache License, Version 2.0 +// that can be found in the LICENSE file. + +package v0 + +import ( + "github.com/palantir/pkg/matcher" + + "github.com/palantir/godel/pkg/versionedconfig" +) + +type GodelConfig struct { + // Version of the configuration + versionedconfig.ConfigWithVersion `yaml:",inline"` + + // TasksConfigProviders specifies the providers used to load provided task configuration. + TasksConfigProviders TasksConfigProvidersConfig `yaml:"tasks-config-providers"` + + // TasksConfig contains the configuration for the tasks (default and plugin). + TasksConfig `yaml:",inline"` + + // Exclude specifies the files and directories that should be excluded from gödel operations. + Exclude matcher.NamesPathsCfg `yaml:"exclude"` +} + +type TasksConfig struct { + // DefaultTasks specifies the configuration for the default tasks for gödel. + DefaultTasks DefaultTasksConfig `yaml:"default-tasks"` + // Plugins specifies the configuration for the plugins configured for gödel. + Plugins PluginsConfig `yaml:"plugins"` +} + +type DefaultTasksConfig struct { + DefaultResolvers []string `yaml:"resolvers"` + Tasks map[string]SingleDefaultTaskConfig `yaml:"tasks"` +} + +type TasksConfigProvidersConfig struct { + DefaultResolvers []string `yaml:"resolvers"` + ConfigProviders []ConfigProviderLocatorWithResolverConfig `yaml:"providers"` +} + +type SingleDefaultTaskConfig struct { + // LocatorWithResolverConfig contains the configuration for the locator and resolver. Any value provided here + // overrides the default value. + LocatorWithResolverConfig `yaml:",inline"` + // ExcludeAllDefaultAssets specifies whether or not all of the default assets should be excluded. If this value is + // true, then DefaultAssetsToExclude is ignored. + ExcludeAllDefaultAssets bool `yaml:"exclude-all-default-assets"` + // DefaultAssetsToExclude specifies the assets that should be excluded if they are provided by the default + // configuration. Only used if ExcludeAllDefaultAssets is false. + DefaultAssetsToExclude []string `yaml:"exclude-default-assets"` + // Assets specifies the custom assets that should be added to the default task. + Assets []LocatorWithResolverConfig `yaml:"assets"` +} + +type PluginsConfig struct { + DefaultResolvers []string `yaml:"resolvers"` + Plugins []SinglePluginConfig `yaml:"plugins"` +} + +type SinglePluginConfig struct { + // LocatorWithResolverConfig stores the locator and the resolver for the plugin. + LocatorWithResolverConfig `yaml:",inline"` + // Assets stores the locators and resolvers for the assets for this plugin. + Assets []LocatorWithResolverConfig `yaml:"assets"` +} diff --git a/vendor/github.com/palantir/godel/framework/godel/config/internal/v0/upgradeconfig.go b/vendor/github.com/palantir/godel/framework/godel/config/internal/v0/upgradeconfig.go new file mode 100644 index 00000000..836dcbef --- /dev/null +++ b/vendor/github.com/palantir/godel/framework/godel/config/internal/v0/upgradeconfig.go @@ -0,0 +1,32 @@ +// Copyright 2016 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright (c) 2016 Palantir Technologies Inc. All rights reserved. +// Use of this source code is governed by the Apache License, Version 2.0 +// that can be found in the LICENSE file. + +package v0 + +import ( + "github.com/pkg/errors" + "gopkg.in/yaml.v2" +) + +func UpgradeConfig(cfgBytes []byte) ([]byte, error) { + var cfg GodelConfig + if err := yaml.UnmarshalStrict(cfgBytes, &cfg); err != nil { + return nil, errors.Wrapf(err, "failed to unmarshal godel v0 configuration") + } + return cfgBytes, nil +} diff --git a/vendor/github.com/palantir/godel/framework/godel/config/readconfig.go b/vendor/github.com/palantir/godel/framework/godel/config/readconfig.go new file mode 100644 index 00000000..7d1524fa --- /dev/null +++ b/vendor/github.com/palantir/godel/framework/godel/config/readconfig.go @@ -0,0 +1,57 @@ +// Copyright 2016 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package config + +import ( + "io/ioutil" + "os" + "path" + + "github.com/pkg/errors" + "gopkg.in/yaml.v2" + + "github.com/palantir/godel/framework/godellauncher" +) + +// ReadGodelConfigFromProjectDir reads the gödel configuration from the "godel.yml" file in the configuration directory +// for the gödel project with the specified project directory and returns it. Returns an empty configuration if the +// configuration file does not exist. +func ReadGodelConfigFromProjectDir(projectDir string) (GodelConfig, error) { + cfgDir, err := godellauncher.ConfigDirPath(projectDir) + if err != nil { + return GodelConfig{}, err + } + return ReadGodelConfigFromFile(path.Join(cfgDir, godellauncher.GodelConfigYML)) +} + +// ReadGodelConfigFromFile reads the gödel configuration from the provided file and returns the loaded configuration. +// Returns an empty configuration if the file does not exist. +func ReadGodelConfigFromFile(cfgFile string) (GodelConfig, error) { + var godelCfg GodelConfig + if _, err := os.Stat(cfgFile); err == nil { + bytes, err := ioutil.ReadFile(cfgFile) + if err != nil { + return GodelConfig{}, errors.Wrapf(err, "failed to read file %s", cfgFile) + } + upgradedBytes, err := UpgradeConfig(bytes) + if err != nil { + return GodelConfig{}, errors.Wrapf(err, "failed to upgrade configuration") + } + if err := yaml.Unmarshal(upgradedBytes, &godelCfg); err != nil { + return GodelConfig{}, errors.Wrapf(err, "failed to unmarshal gödel config YAML") + } + } + return godelCfg, nil +} diff --git a/vendor/github.com/palantir/godel/framework/godel/config/upgradeconfig.go b/vendor/github.com/palantir/godel/framework/godel/config/upgradeconfig.go new file mode 100644 index 00000000..553386e7 --- /dev/null +++ b/vendor/github.com/palantir/godel/framework/godel/config/upgradeconfig.go @@ -0,0 +1,47 @@ +// Copyright 2016 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Copyright (c) 2016 Palantir Technologies Inc. All rights reserved. +// Use of this source code is governed by the Apache License, Version 2.0 +// that can be found in the LICENSE file. + +package config + +import ( + "github.com/pkg/errors" + + "github.com/palantir/godel/framework/godel/config/internal/legacy" + "github.com/palantir/godel/framework/godel/config/internal/v0" + "github.com/palantir/godel/pkg/versionedconfig" +) + +func UpgradeConfig(cfgBytes []byte) ([]byte, error) { + if versionedconfig.IsLegacyConfig(cfgBytes) { + v0Bytes, err := legacy.UpgradeConfig(cfgBytes) + if err != nil { + return nil, err + } + cfgBytes = v0Bytes + } + version, err := versionedconfig.ConfigVersion(cfgBytes) + if err != nil { + return nil, err + } + switch version { + case "", "0": + return v0.UpgradeConfig(cfgBytes) + default: + return nil, errors.Errorf("unsupported version: %s", version) + } +} diff --git a/vendor/github.com/palantir/godel/framework/godellauncher/config.go b/vendor/github.com/palantir/godel/framework/godellauncher/config.go deleted file mode 100644 index d54dfc8a..00000000 --- a/vendor/github.com/palantir/godel/framework/godellauncher/config.go +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright 2016 Palantir Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package godellauncher - -import ( - "io/ioutil" - "os" - "path" - - "github.com/palantir/pkg/matcher" - "github.com/palantir/pkg/specdir" - "github.com/pkg/errors" - "gopkg.in/yaml.v2" - - "github.com/palantir/godel/framework/artifactresolver" - "github.com/palantir/godel/framework/builtintasks/installupdate/layout" - "github.com/palantir/godel/pkg/versionedconfig" -) - -const ( - GodelConfigYML = "godel.yml" -) - -type GodelConfig struct { - // Version of the configuration - versionedconfig.ConfigWithVersion `yaml:",inline"` - - // TasksConfigProviders specifies the providers used to load provided task configuration. - TasksConfigProviders TasksConfigProvidersConfig `yaml:"tasks-config-providers"` - - // TasksConfig contains the configuration for the tasks (default and plugin). - TasksConfig `yaml:",inline"` - - // Exclude specifies the files and directories that should be excluded from gödel operations. - Exclude matcher.NamesPathsCfg `yaml:"exclude"` -} - -type TasksConfig struct { - // DefaultTasks specifies the configuration for the default tasks for gödel. - DefaultTasks DefaultTasksConfig `yaml:"default-tasks"` - // Plugins specifies the configuration for the plugins configured for gödel. - Plugins PluginsConfig `yaml:"plugins"` -} - -// Combine combines the provided TasksConfig configurations with the base configuration. In cases where values are -// overwritten, the last (most recent) values in the inputs will take precedence. -func (c *TasksConfig) Combine(configs ...TasksConfig) { - if c.DefaultTasks.Tasks == nil { - c.DefaultTasks.Tasks = make(map[string]SingleDefaultTaskConfig) - } - - for _, cfg := range configs { - // DefaultTask resolvers are appended - c.DefaultTasks.DefaultResolvers = append(c.DefaultTasks.DefaultResolvers, cfg.DefaultTasks.DefaultResolvers...) - // DefaultTask tasks key/values are simply copied (and overwritten with last writer wins for any duplicate keys) - for k, v := range cfg.DefaultTasks.Tasks { - c.DefaultTasks.Tasks[k] = v - } - - // Plugin resolvers and definitions are appended - c.Plugins.DefaultResolvers = append(c.Plugins.DefaultResolvers, cfg.Plugins.DefaultResolvers...) - c.Plugins.Plugins = append(c.Plugins.Plugins, cfg.Plugins.Plugins...) - } -} - -type DefaultTasksConfig struct { - DefaultResolvers []string `yaml:"resolvers"` - Tasks map[string]SingleDefaultTaskConfig `yaml:"tasks"` -} - -type TasksConfigProvidersParam struct { - DefaultResolvers []artifactresolver.Resolver - ConfigProviders []artifactresolver.LocatorWithResolverParam -} - -type TasksConfigProvidersConfig struct { - DefaultResolvers []string `yaml:"resolvers"` - ConfigProviders []artifactresolver.ConfigProviderLocatorWithResolverConfig `yaml:"providers"` -} - -func (c *TasksConfigProvidersConfig) ToParam() (TasksConfigProvidersParam, error) { - var defaultResolvers []artifactresolver.Resolver - for _, resolverStr := range c.DefaultResolvers { - resolver, err := artifactresolver.NewTemplateResolver(resolverStr) - if err != nil { - return TasksConfigProvidersParam{}, err - } - defaultResolvers = append(defaultResolvers, resolver) - } - var configProviders []artifactresolver.LocatorWithResolverParam - for _, provider := range c.ConfigProviders { - providerVal, err := provider.ToParam() - if err != nil { - return TasksConfigProvidersParam{}, err - } - configProviders = append(configProviders, providerVal) - } - return TasksConfigProvidersParam{ - DefaultResolvers: defaultResolvers, - ConfigProviders: configProviders, - }, nil -} - -type SingleDefaultTaskConfig struct { - // LocatorWithResolverConfig contains the configuration for the locator and resolver. Any value provided here - // overrides the default value. - artifactresolver.LocatorWithResolverConfig `yaml:",inline"` - // ExcludeAllDefaultAssets specifies whether or not all of the default assets should be excluded. If this value is - // true, then DefaultAssetsToExclude is ignored. - ExcludeAllDefaultAssets bool `yaml:"exclude-all-default-assets"` - // DefaultAssetsToExclude specifies the assets that should be excluded if they are provided by the default - // configuration. Only used if ExcludeAllDefaultAssets is false. - DefaultAssetsToExclude []string `yaml:"exclude-default-assets"` - // Assets specifies the custom assets that should be added to the default task. - Assets []artifactresolver.LocatorWithResolverConfig `yaml:"assets"` -} - -type PluginsParam struct { - DefaultResolvers []artifactresolver.Resolver - Plugins []SinglePluginParam -} - -type PluginsConfig struct { - DefaultResolvers []string `yaml:"resolvers"` - Plugins []SinglePluginConfig `yaml:"plugins"` -} - -func (c *PluginsConfig) ToParam() (PluginsParam, error) { - var defaultResolvers []artifactresolver.Resolver - for _, resolverStr := range c.DefaultResolvers { - resolver, err := artifactresolver.NewTemplateResolver(resolverStr) - if err != nil { - return PluginsParam{}, err - } - defaultResolvers = append(defaultResolvers, resolver) - } - var plugins []SinglePluginParam - for _, plugin := range c.Plugins { - pluginParam, err := plugin.ToParam() - if err != nil { - return PluginsParam{}, err - } - plugins = append(plugins, pluginParam) - } - return PluginsParam{ - DefaultResolvers: defaultResolvers, - Plugins: plugins, - }, nil -} - -type SinglePluginParam struct { - artifactresolver.LocatorWithResolverParam - Assets []artifactresolver.LocatorWithResolverParam -} - -type SinglePluginConfig struct { - // LocatorWithResolverConfig stores the locator and the resolver for the plugin. - artifactresolver.LocatorWithResolverConfig `yaml:",inline"` - // Assets stores the locators and resolvers for the assets for this plugin. - Assets []artifactresolver.LocatorWithResolverConfig `yaml:"assets"` -} - -func (c *SinglePluginConfig) ToParam() (SinglePluginParam, error) { - locatorWithResolverParam, err := c.LocatorWithResolverConfig.ToParam() - if err != nil { - return SinglePluginParam{}, err - } - var assets []artifactresolver.LocatorWithResolverParam - for _, assetCfg := range c.Assets { - assetParamVal, err := assetCfg.ToParam() - if err != nil { - return SinglePluginParam{}, err - } - assets = append(assets, assetParamVal) - } - return SinglePluginParam{ - LocatorWithResolverParam: locatorWithResolverParam, - Assets: assets, - }, nil -} - -// ConfigDirPath returns the path to the gödel configuration directory given the path to the project directory. Returns -// an error if the directory structure does not match what is expected. -func ConfigDirPath(projectDirPath string) (string, error) { - if projectDirPath == "" { - return "", errors.Errorf("projectDirPath was empty") - } - wrapper, err := specdir.New(projectDirPath, layout.WrapperSpec(), nil, specdir.Validate) - if err != nil { - return "", err - } - return wrapper.Path(layout.WrapperConfigDir), nil -} - -// ReadGodelConfigFromProjectDir reads the gödel configuration from the "godel.yml" file in the configuration file for -// the gödel project with the specified project directory and returns it. -func ReadGodelConfigFromProjectDir(projectDir string) (GodelConfig, error) { - cfgDir, err := ConfigDirPath(projectDir) - if err != nil { - return GodelConfig{}, err - } - cfg, err := ReadGodelConfig(cfgDir) - if err != nil { - return GodelConfig{}, err - } - return cfg, nil -} - -// ReadGodelConfig reads the gödel configuration from the "godel.yml" file in the specified directory and returns it. -func ReadGodelConfig(cfgDir string) (GodelConfig, error) { - var godelCfg GodelConfig - godelYML := path.Join(cfgDir, GodelConfigYML) - if _, err := os.Stat(godelYML); err == nil { - bytes, err := ioutil.ReadFile(godelYML) - if err != nil { - return GodelConfig{}, errors.Wrapf(err, "failed to read file %s", godelYML) - } - upgradedBytes, err := UpgradeGodelConfig(bytes) - if err != nil { - return GodelConfig{}, errors.Wrapf(err, "failed to upgrade configuration") - } - if err := yaml.Unmarshal(upgradedBytes, &godelCfg); err != nil { - return GodelConfig{}, errors.Wrapf(err, "failed to unmarshal gödel config YAML") - } - } - return godelCfg, nil -} - -func UpgradeGodelConfig(cfgBytes []byte) ([]byte, error) { - version, err := versionedconfig.ConfigVersion(cfgBytes) - if err != nil { - return nil, errors.Wrapf(err, "failed to unmarshal version") - } - switch version { - case "", "0": - // verify that configuration is valid - var cfg GodelConfig - if err := yaml.UnmarshalStrict(cfgBytes, &cfg); err != nil { - return nil, errors.Wrapf(err, "failed to unmarshal configuration") - } - // configuration is valid and is current version: return input bytes - return cfgBytes, nil - default: - return nil, errors.Errorf("unsupported version: %s", version) - } -} diff --git a/vendor/github.com/palantir/godel/framework/godellauncher/defaulttasks.go b/vendor/github.com/palantir/godel/framework/godellauncher/defaulttasks.go deleted file mode 100644 index 685fabab..00000000 --- a/vendor/github.com/palantir/godel/framework/godellauncher/defaulttasks.go +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright 2016 Palantir Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package godellauncher - -import ( - "strings" - - "github.com/palantir/godel/framework/artifactresolver" -) - -const defaultResolver = "https://palantir.bintray.com/releases/{{GroupPath}}/{{Product}}/{{Version}}/{{Product}}-{{Version}}-{{OS}}-{{Arch}}.tgz" - -var defaultPluginsConfig = PluginsConfig{ - DefaultResolvers: []string{ - defaultResolver, - }, - Plugins: []SinglePluginConfig{ - { - LocatorWithResolverConfig: artifactresolver.LocatorWithResolverConfig{ - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.distgo:distgo-plugin:1.0.0-rc3", - }, - }, - }, - { - LocatorWithResolverConfig: artifactresolver.LocatorWithResolverConfig{ - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel-format-plugin:format-plugin:1.0.0-rc2", - }, - }, - Assets: []artifactresolver.LocatorWithResolverConfig{ - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel-format-asset-ptimports:ptimports-asset:1.0.0-rc3", - }, - }, - }, - }, - { - LocatorWithResolverConfig: artifactresolver.LocatorWithResolverConfig{ - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel-goland-plugin:goland-plugin:1.0.0-rc1", - }, - }, - }, - { - LocatorWithResolverConfig: artifactresolver.LocatorWithResolverConfig{ - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.okgo:okgo-plugin:1.0.0-rc2", - }, - }, - Assets: []artifactresolver.LocatorWithResolverConfig{ - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel-okgo-asset-compiles:compiles-asset:1.0.0-rc2", - }, - }, - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel-okgo-asset-deadcode:deadcode-asset:1.0.0-rc1", - }, - }, - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel-okgo-asset-errcheck:errcheck-asset:1.0.0-rc1", - }, - }, - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel-okgo-asset-extimport:extimport-asset:1.0.0-rc1", - }, - }, - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel-okgo-asset-golint:golint-asset:1.0.0-rc2", - }, - }, - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel-okgo-asset-govet:govet-asset:1.0.0-rc2", - }, - }, - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel-okgo-asset-importalias:importalias-asset:1.0.0-rc1", - }, - }, - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel-okgo-asset-ineffassign:ineffassign-asset:1.0.0-rc1", - }, - }, - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel-okgo-asset-novendor:novendor-asset:1.0.0-rc1", - }, - }, - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel-okgo-asset-outparamcheck:outparamcheck-asset:1.0.0-rc1", - }, - }, - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel-okgo-asset-unconvert:unconvert-asset:1.0.0-rc2", - }, - }, - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel-okgo-asset-varcheck:varcheck-asset:1.0.0-rc1", - }, - }, - }, - }, - { - LocatorWithResolverConfig: artifactresolver.LocatorWithResolverConfig{ - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.go-license:license-plugin:1.0.0-rc2", - }, - }, - }, - { - LocatorWithResolverConfig: artifactresolver.LocatorWithResolverConfig{ - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel-test-plugin:test-plugin:1.0.0-rc3", - }, - }, - }, - }, -} - -type TasksConfigInfo struct { - // BuiltinPluginsConfig is the configuration for built-in plugins that is built as part of gödel. - BuiltinPluginsConfig PluginsConfig - // TasksConfig is the fully resolved user-provided tasks configuration. - TasksConfig TasksConfig - // DefaultTasksPluginsConfig is the plugin configuration used to load the default tasks. It is a result of combining - // the BuiltinPluginsConfig with the DefaultTasks config of TasksConfig. - DefaultTasksPluginsConfig PluginsConfig -} - -func BuiltinDefaultPluginsConfig() PluginsConfig { - return defaultPluginsConfig -} - -func DefaultTasksPluginsConfig(config DefaultTasksConfig) PluginsConfig { - // start with configuration that uses default resolver - pluginsCfg := PluginsConfig{ - DefaultResolvers: defaultPluginsConfig.DefaultResolvers, - } - // append default resolvers provided by the configuration - pluginsCfg.DefaultResolvers = append(pluginsCfg.DefaultResolvers, config.DefaultResolvers...) - - for _, currPlugin := range defaultPluginsConfig.Plugins { - currKey := locatorIDWithoutVersion(currPlugin.Locator.ID) - - cfgParam, ok := config.Tasks[currKey] - if !ok { - // if custom configuration is not specified, use default and continue - pluginsCfg.Plugins = append(pluginsCfg.Plugins, currPlugin) - continue - } - - // custom configuration was non-empty: start it with default LocatorWithResolver configuration - currCfg := SinglePluginConfig{ - LocatorWithResolverConfig: currPlugin.LocatorWithResolverConfig, - } - if cfgParam.Locator.ID != "" { - currCfg.Locator = cfgParam.Locator - } - if cfgParam.Resolver != "" { - currCfg.Resolver = cfgParam.Resolver - } - - currCfg.Assets = append(currCfg.Assets, assetConfigFromDefault(currPlugin.Assets, cfgParam)...) - currCfg.Assets = append(currCfg.Assets, cfgParam.Assets...) - pluginsCfg.Plugins = append(pluginsCfg.Plugins, currCfg) - } - return pluginsCfg -} - -func assetConfigFromDefault(baseCfg []artifactresolver.LocatorWithResolverConfig, cfg SingleDefaultTaskConfig) []artifactresolver.LocatorWithResolverConfig { - if cfg.ExcludeAllDefaultAssets { - return nil - } - exclude := make(map[string]struct{}) - for _, currExclude := range cfg.DefaultAssetsToExclude { - exclude[currExclude] = struct{}{} - } - var out []artifactresolver.LocatorWithResolverConfig - for _, asset := range baseCfg { - if _, ok := exclude[locatorIDWithoutVersion(asset.Locator.ID)]; ok { - continue - } - out = append(out, asset) - } - return out -} - -func locatorIDWithoutVersion(locatorID string) string { - parts := strings.Split(locatorID, ":") - return strings.Join(parts[:2], ":") -} diff --git a/vendor/github.com/palantir/godel/framework/godellauncher/defaulttasks/defaulttasks.go b/vendor/github.com/palantir/godel/framework/godellauncher/defaulttasks/defaulttasks.go new file mode 100644 index 00000000..87300abd --- /dev/null +++ b/vendor/github.com/palantir/godel/framework/godellauncher/defaulttasks/defaulttasks.go @@ -0,0 +1,234 @@ +// Copyright 2016 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package defaulttasks + +import ( + "sort" + "strings" + + "github.com/pkg/errors" + + "github.com/palantir/godel/framework/godel/config" +) + +const defaultResolver = "https://palantir.bintray.com/releases/{{GroupPath}}/{{Product}}/{{Version}}/{{Product}}-{{Version}}-{{OS}}-{{Arch}}.tgz" + +var defaultPluginsConfig = config.PluginsConfig{ + DefaultResolvers: []string{ + defaultResolver, + }, + Plugins: config.ToSinglePluginConfigs([]config.SinglePluginConfig{ + { + LocatorWithResolverConfig: config.ToLocatorWithResolverConfig(config.LocatorWithResolverConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.distgo:distgo-plugin:1.0.0-rc3", + }), + }), + }, + { + LocatorWithResolverConfig: config.ToLocatorWithResolverConfig(config.LocatorWithResolverConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel-format-plugin:format-plugin:1.0.0-rc2", + }), + }), + Assets: config.ToLocatorWithResolverConfigs([]config.LocatorWithResolverConfig{ + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel-format-asset-ptimports:ptimports-asset:1.0.0-rc3", + }), + }, + }), + }, + { + LocatorWithResolverConfig: config.ToLocatorWithResolverConfig(config.LocatorWithResolverConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel-goland-plugin:goland-plugin:1.0.0-rc1", + }), + }), + }, + { + LocatorWithResolverConfig: config.ToLocatorWithResolverConfig(config.LocatorWithResolverConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.okgo:okgo-plugin:1.0.0-rc2", + }), + }), + Assets: config.ToLocatorWithResolverConfigs([]config.LocatorWithResolverConfig{ + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel-okgo-asset-compiles:compiles-asset:1.0.0-rc2", + }), + }, + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel-okgo-asset-deadcode:deadcode-asset:1.0.0-rc1", + }), + }, + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel-okgo-asset-errcheck:errcheck-asset:1.0.0-rc1", + }), + }, + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel-okgo-asset-extimport:extimport-asset:1.0.0-rc1", + }), + }, + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel-okgo-asset-golint:golint-asset:1.0.0-rc2", + }), + }, + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel-okgo-asset-govet:govet-asset:1.0.0-rc2", + }), + }, + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel-okgo-asset-importalias:importalias-asset:1.0.0-rc1", + }), + }, + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel-okgo-asset-ineffassign:ineffassign-asset:1.0.0-rc1", + }), + }, + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel-okgo-asset-novendor:novendor-asset:1.0.0-rc1", + }), + }, + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel-okgo-asset-outparamcheck:outparamcheck-asset:1.0.0-rc1", + }), + }, + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel-okgo-asset-unconvert:unconvert-asset:1.0.0-rc2", + }), + }, + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel-okgo-asset-varcheck:varcheck-asset:1.0.0-rc1", + }), + }, + }), + }, + { + LocatorWithResolverConfig: config.ToLocatorWithResolverConfig(config.LocatorWithResolverConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.go-license:license-plugin:1.0.0-rc2", + }), + }), + }, + { + LocatorWithResolverConfig: config.ToLocatorWithResolverConfig(config.LocatorWithResolverConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel-test-plugin:test-plugin:1.0.0-rc3", + }), + }), + }, + }), +} + +func BuiltinPluginsConfig() config.PluginsConfig { + return defaultPluginsConfig +} + +func PluginsConfig(cfg config.DefaultTasksConfig) (config.PluginsConfig, error) { + // start with configuration that uses default resolver + pluginsCfg := config.PluginsConfig{ + DefaultResolvers: defaultPluginsConfig.DefaultResolvers, + } + // append default resolvers provided by the configuration + pluginsCfg.DefaultResolvers = append(pluginsCfg.DefaultResolvers, cfg.DefaultResolvers...) + + defaultPluginKeys := make(map[string]struct{}) + for _, currPlugin := range defaultPluginsConfig.Plugins { + currKey := locatorIDWithoutVersion(currPlugin.Locator.ID) + defaultPluginKeys[currKey] = struct{}{} + + var assets []config.LocatorWithResolverConfig + for _, asset := range currPlugin.Assets { + assets = append(assets, config.LocatorWithResolverConfig(asset)) + } + taskCfgV0, ok := cfg.Tasks[currKey] + if !ok { + // if custom configuration is not specified, use default and continue + pluginsCfg.Plugins = append(pluginsCfg.Plugins, currPlugin) + continue + } + taskCfg := config.SingleDefaultTaskConfig(taskCfgV0) + + // custom configuration was non-empty: start it with default LocatorWithResolver configuration + currCfg := config.SinglePluginConfig{ + LocatorWithResolverConfig: currPlugin.LocatorWithResolverConfig, + } + if taskCfg.Locator.ID != "" { + currCfg.Locator = taskCfg.Locator + } + if taskCfg.Resolver != "" { + currCfg.Resolver = taskCfg.Resolver + } + + currCfg.Assets = append(currCfg.Assets, config.ToLocatorWithResolverConfigs(assetConfigFromDefault(assets, taskCfg))...) + currCfg.Assets = append(currCfg.Assets, taskCfg.Assets...) + pluginsCfg.Plugins = append(pluginsCfg.Plugins, config.ToSinglePluginConfig(currCfg)) + } + + var invalidKeys []string + for providedDefaultCfgKey := range cfg.Tasks { + if _, ok := defaultPluginKeys[providedDefaultCfgKey]; ok { + continue + } + invalidKeys = append(invalidKeys, providedDefaultCfgKey) + } + sort.Strings(invalidKeys) + + if len(invalidKeys) > 0 { + var validKeys []string + for k := range defaultPluginKeys { + validKeys = append(validKeys, k) + } + sort.Strings(validKeys) + return config.PluginsConfig{}, errors.Errorf("default-task key(s) specified but are not valid: %v. Valid values: %v", invalidKeys, validKeys) + } + + return pluginsCfg, nil +} + +func assetConfigFromDefault(baseCfg []config.LocatorWithResolverConfig, cfg config.SingleDefaultTaskConfig) []config.LocatorWithResolverConfig { + if cfg.ExcludeAllDefaultAssets { + return nil + } + exclude := make(map[string]struct{}) + for _, currExclude := range cfg.DefaultAssetsToExclude { + exclude[currExclude] = struct{}{} + } + var out []config.LocatorWithResolverConfig + for _, asset := range baseCfg { + if _, ok := exclude[locatorIDWithoutVersion(asset.Locator.ID)]; ok { + continue + } + out = append(out, asset) + } + return out +} + +func locatorIDWithoutVersion(locatorID string) string { + parts := strings.Split(locatorID, ":") + return strings.Join(parts[:2], ":") +} diff --git a/vendor/github.com/palantir/godel/framework/godellauncher/defaulttasks/defaulttasks_test.go b/vendor/github.com/palantir/godel/framework/godellauncher/defaulttasks/defaulttasks_test.go new file mode 100644 index 00000000..16921259 --- /dev/null +++ b/vendor/github.com/palantir/godel/framework/godellauncher/defaulttasks/defaulttasks_test.go @@ -0,0 +1,381 @@ +// Copyright 2016 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package defaulttasks + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/palantir/godel/framework/godel/config" +) + +func testDefaultPluginsConfig() config.PluginsConfig { + return config.PluginsConfig{ + DefaultResolvers: []string{defaultResolver}, + Plugins: config.ToSinglePluginConfigs([]config.SinglePluginConfig{ + { + LocatorWithResolverConfig: config.ToLocatorWithResolverConfig(config.LocatorWithResolverConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.test:test-plugin:1.2.3", + }), + }), + Assets: config.ToLocatorWithResolverConfigs([]config.LocatorWithResolverConfig{ + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.test:test-asset-1:2.3.4", + }), + }, + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.test:test-asset-2:3.4.5", + }), + }, + }), + }, + }), + } +} + +func TestDefaultTasksPluginsConfig(t *testing.T) { + original := defaultPluginsConfig + defer func() { + defaultPluginsConfig = original + }() + defaultPluginsConfig = testDefaultPluginsConfig() + + for i, tc := range []struct { + name string + in config.DefaultTasksConfig + wantError string + want config.PluginsConfig + }{ + { + "empty task param results in default configuration", + config.DefaultTasksConfig{}, + "", + config.PluginsConfig{ + DefaultResolvers: []string{ + defaultResolver, + }, + Plugins: config.ToSinglePluginConfigs([]config.SinglePluginConfig{ + { + LocatorWithResolverConfig: config.ToLocatorWithResolverConfig(config.LocatorWithResolverConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.test:test-plugin:1.2.3", + }), + }), + Assets: config.ToLocatorWithResolverConfigs([]config.LocatorWithResolverConfig{ + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.test:test-asset-1:2.3.4", + }), + }, + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.test:test-asset-2:3.4.5", + }), + }, + }), + }, + }), + }, + }, + { + "specifying custom resolver overrides resolver", + config.DefaultTasksConfig{ + Tasks: config.ToTasks(map[string]config.SingleDefaultTaskConfig{ + "com.palantir.test:test-plugin": { + LocatorWithResolverConfig: config.ToLocatorWithResolverConfig(config.LocatorWithResolverConfig{ + Resolver: "custom-resolver", + }), + }, + }), + }, + "", + config.PluginsConfig{ + DefaultResolvers: []string{ + defaultResolver, + }, + Plugins: config.ToSinglePluginConfigs([]config.SinglePluginConfig{ + { + LocatorWithResolverConfig: config.ToLocatorWithResolverConfig(config.LocatorWithResolverConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.test:test-plugin:1.2.3", + }), + Resolver: "custom-resolver", + }), + Assets: config.ToLocatorWithResolverConfigs([]config.LocatorWithResolverConfig{ + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.test:test-asset-1:2.3.4", + }), + }, + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.test:test-asset-2:3.4.5", + }), + }, + }), + }, + }), + }, + }, + { + "specifying custom locator overrides locator", + config.DefaultTasksConfig{ + Tasks: config.ToTasks(map[string]config.SingleDefaultTaskConfig{ + "com.palantir.test:test-plugin": { + LocatorWithResolverConfig: config.ToLocatorWithResolverConfig(config.LocatorWithResolverConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel:override:1.2.3", + }), + }), + }, + }), + }, + "", + config.PluginsConfig{ + DefaultResolvers: []string{ + defaultResolver, + }, + Plugins: config.ToSinglePluginConfigs([]config.SinglePluginConfig{ + { + LocatorWithResolverConfig: config.ToLocatorWithResolverConfig(config.LocatorWithResolverConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel:override:1.2.3", + }), + }), + Assets: config.ToLocatorWithResolverConfigs([]config.LocatorWithResolverConfig{ + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.test:test-asset-1:2.3.4", + }), + }, + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.test:test-asset-2:3.4.5", + }), + }, + }), + }, + }), + }, + }, + { + "specifying default resolver appends default resolver", + config.DefaultTasksConfig{ + DefaultResolvers: []string{ + "default/repo/{{GroupPath}}/{{Product}}/{{Version}}/{{Product}}-{{OS}}-{{Arch}}-{{Version}}.tgz", + }, + Tasks: config.ToTasks(map[string]config.SingleDefaultTaskConfig{ + "com.palantir.test:test-plugin": { + LocatorWithResolverConfig: config.ToLocatorWithResolverConfig(config.LocatorWithResolverConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel:override:1.2.3", + }), + }), + }, + }), + }, + "", + config.PluginsConfig{ + DefaultResolvers: []string{ + defaultResolver, + "default/repo/{{GroupPath}}/{{Product}}/{{Version}}/{{Product}}-{{OS}}-{{Arch}}-{{Version}}.tgz", + }, + Plugins: config.ToSinglePluginConfigs([]config.SinglePluginConfig{ + { + LocatorWithResolverConfig: config.ToLocatorWithResolverConfig(config.LocatorWithResolverConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel:override:1.2.3", + }), + }), + Assets: config.ToLocatorWithResolverConfigs([]config.LocatorWithResolverConfig{ + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.test:test-asset-1:2.3.4", + }), + }, + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.test:test-asset-2:3.4.5", + }), + }, + }), + }, + }), + }, + }, + { + "specifying custom asset adds only that asset", + config.DefaultTasksConfig{ + Tasks: config.ToTasks(map[string]config.SingleDefaultTaskConfig{ + "com.palantir.test:test-plugin": { + Assets: config.ToLocatorWithResolverConfigs([]config.LocatorWithResolverConfig{ + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel:custom-asset:1.2.3", + }), + }, + }), + }, + }), + }, + "", + config.PluginsConfig{ + DefaultResolvers: []string{ + defaultResolver, + }, + Plugins: config.ToSinglePluginConfigs([]config.SinglePluginConfig{ + { + LocatorWithResolverConfig: config.ToLocatorWithResolverConfig(config.LocatorWithResolverConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.test:test-plugin:1.2.3", + }), + }), + Assets: config.ToLocatorWithResolverConfigs([]config.LocatorWithResolverConfig{ + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.test:test-asset-1:2.3.4", + }), + }, + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.test:test-asset-2:3.4.5", + }), + }, + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel:custom-asset:1.2.3", + }), + }, + }), + }, + }), + }, + }, + { + "setting exclude all and specifying custom asset adds asset to default", + config.DefaultTasksConfig{ + Tasks: config.ToTasks(map[string]config.SingleDefaultTaskConfig{ + "com.palantir.test:test-plugin": { + ExcludeAllDefaultAssets: true, + Assets: config.ToLocatorWithResolverConfigs([]config.LocatorWithResolverConfig{ + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel:custom-asset:1.2.3", + }), + }, + }), + }, + }), + }, + "", + config.PluginsConfig{ + DefaultResolvers: []string{ + defaultResolver, + }, + Plugins: config.ToSinglePluginConfigs([]config.SinglePluginConfig{ + { + LocatorWithResolverConfig: config.ToLocatorWithResolverConfig(config.LocatorWithResolverConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.test:test-plugin:1.2.3", + }), + }), + Assets: config.ToLocatorWithResolverConfigs([]config.LocatorWithResolverConfig{ + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel:custom-asset:1.2.3", + }), + }, + }), + }, + }), + }, + }, + { + "specifying default asset with exclude and custom asset adds asset", + config.DefaultTasksConfig{ + Tasks: config.ToTasks(map[string]config.SingleDefaultTaskConfig{ + "com.palantir.test:test-plugin": { + DefaultAssetsToExclude: []string{ + "com.palantir.test:test-asset-2", + }, + Assets: config.ToLocatorWithResolverConfigs([]config.LocatorWithResolverConfig{ + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel:custom-asset:1.2.3", + }), + }, + }), + }, + }), + }, + "", + config.PluginsConfig{ + DefaultResolvers: []string{ + defaultResolver, + }, + Plugins: config.ToSinglePluginConfigs([]config.SinglePluginConfig{ + { + LocatorWithResolverConfig: config.ToLocatorWithResolverConfig(config.LocatorWithResolverConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.test:test-plugin:1.2.3", + }), + }), + Assets: config.ToLocatorWithResolverConfigs([]config.LocatorWithResolverConfig{ + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.test:test-asset-1:2.3.4", + }), + }, + { + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel:custom-asset:1.2.3", + }), + }, + }), + }, + }), + }, + }, + { + "specifying invalid key results in error", + config.DefaultTasksConfig{ + Tasks: config.ToTasks(map[string]config.SingleDefaultTaskConfig{ + "com.palantir.test:test": { + LocatorWithResolverConfig: config.ToLocatorWithResolverConfig(config.LocatorWithResolverConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ + ID: "com.palantir.godel:override:1.2.3", + }), + }), + }, + }), + }, + `default-task key(s) specified but are not valid: [com.palantir.test:test]. Valid values: [com.palantir.test:test-plugin]`, + config.PluginsConfig{}, + }, + } { + got, err := PluginsConfig(tc.in) + if tc.wantError == "" { + require.NoError(t, err) + assert.Equal(t, tc.want, got, "Case %d: %s", i, tc.name) + } else { + assert.EqualError(t, err, tc.wantError, "Case %d: %s", i, tc.name) + } + } +} diff --git a/vendor/github.com/palantir/godel/framework/godellauncher/defaulttasks/defaultupgradetasks.go b/vendor/github.com/palantir/godel/framework/godellauncher/defaulttasks/defaultupgradetasks.go new file mode 100644 index 00000000..a64f5b4f --- /dev/null +++ b/vendor/github.com/palantir/godel/framework/godellauncher/defaulttasks/defaultupgradetasks.go @@ -0,0 +1,38 @@ +// Copyright 2016 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package defaulttasks + +import ( + "io" + + "github.com/palantir/godel/framework/godel/config" + "github.com/palantir/godel/framework/godellauncher" +) + +func BuiltinUpgradeConfigTasks() []godellauncher.UpgradeConfigTask { + return []godellauncher.UpgradeConfigTask{ + upgradeGodelConfigTask(), + } +} + +func upgradeGodelConfigTask() godellauncher.UpgradeConfigTask { + return godellauncher.UpgradeConfigTask{ + ID: "com.palantir.godel:godel", + ConfigFile: "godel.yml", + RunImpl: func(t *godellauncher.UpgradeConfigTask, global godellauncher.GlobalConfig, configBytes []byte, stdout io.Writer) ([]byte, error) { + return config.UpgradeConfig(configBytes) + }, + } +} diff --git a/vendor/github.com/palantir/godel/framework/godellauncher/defaulttasks_test.go b/vendor/github.com/palantir/godel/framework/godellauncher/defaulttasks_test.go deleted file mode 100644 index ee37ac24..00000000 --- a/vendor/github.com/palantir/godel/framework/godellauncher/defaulttasks_test.go +++ /dev/null @@ -1,351 +0,0 @@ -// Copyright 2016 Palantir Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package godellauncher - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/palantir/godel/framework/artifactresolver" -) - -func testDefaultPluginsConfig() PluginsConfig { - return PluginsConfig{ - DefaultResolvers: []string{defaultResolver}, - Plugins: []SinglePluginConfig{ - { - LocatorWithResolverConfig: artifactresolver.LocatorWithResolverConfig{ - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.test:test-plugin:1.2.3", - }, - }, - Assets: []artifactresolver.LocatorWithResolverConfig{ - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.test:test-asset-1:2.3.4", - }, - }, - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.test:test-asset-2:3.4.5", - }, - }, - }, - }, - }, - } -} - -func TestDefaultTasksPluginsConfig(t *testing.T) { - original := defaultPluginsConfig - defer func() { - defaultPluginsConfig = original - }() - defaultPluginsConfig = testDefaultPluginsConfig() - - for i, tc := range []struct { - name string - in DefaultTasksConfig - want PluginsConfig - }{ - { - "empty task param results in default configuration", - DefaultTasksConfig{}, - PluginsConfig{ - DefaultResolvers: []string{ - defaultResolver, - }, - Plugins: []SinglePluginConfig{ - { - LocatorWithResolverConfig: artifactresolver.LocatorWithResolverConfig{ - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.test:test-plugin:1.2.3", - }, - }, - Assets: []artifactresolver.LocatorWithResolverConfig{ - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.test:test-asset-1:2.3.4", - }, - }, - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.test:test-asset-2:3.4.5", - }, - }, - }, - }, - }, - }, - }, - { - "specifying custom resolver overrides resolver", - DefaultTasksConfig{ - Tasks: map[string]SingleDefaultTaskConfig{ - "com.palantir.test:test-plugin": { - LocatorWithResolverConfig: artifactresolver.LocatorWithResolverConfig{ - Resolver: "custom-resolver", - }, - }, - }, - }, - PluginsConfig{ - DefaultResolvers: []string{ - defaultResolver, - }, - Plugins: []SinglePluginConfig{ - { - LocatorWithResolverConfig: artifactresolver.LocatorWithResolverConfig{ - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.test:test-plugin:1.2.3", - }, - Resolver: "custom-resolver", - }, - Assets: []artifactresolver.LocatorWithResolverConfig{ - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.test:test-asset-1:2.3.4", - }, - }, - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.test:test-asset-2:3.4.5", - }, - }, - }, - }, - }, - }, - }, - { - "specifying custom locator overrides locator", - DefaultTasksConfig{ - Tasks: map[string]SingleDefaultTaskConfig{ - "com.palantir.test:test-plugin": { - LocatorWithResolverConfig: artifactresolver.LocatorWithResolverConfig{ - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel:override:1.2.3", - }, - }, - }, - }, - }, - PluginsConfig{ - DefaultResolvers: []string{ - defaultResolver, - }, - Plugins: []SinglePluginConfig{ - { - LocatorWithResolverConfig: artifactresolver.LocatorWithResolverConfig{ - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel:override:1.2.3", - }, - }, - Assets: []artifactresolver.LocatorWithResolverConfig{ - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.test:test-asset-1:2.3.4", - }, - }, - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.test:test-asset-2:3.4.5", - }, - }, - }, - }, - }, - }, - }, - { - "specifying default resolver appends default resolver", - DefaultTasksConfig{ - DefaultResolvers: []string{ - "default/repo/{{GroupPath}}/{{Product}}/{{Version}}/{{Product}}-{{OS}}-{{Arch}}-{{Version}}.tgz", - }, - Tasks: map[string]SingleDefaultTaskConfig{ - "com.palantir.test:test-plugin": { - LocatorWithResolverConfig: artifactresolver.LocatorWithResolverConfig{ - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel:override:1.2.3", - }, - }, - }, - }, - }, - PluginsConfig{ - DefaultResolvers: []string{ - defaultResolver, - "default/repo/{{GroupPath}}/{{Product}}/{{Version}}/{{Product}}-{{OS}}-{{Arch}}-{{Version}}.tgz", - }, - Plugins: []SinglePluginConfig{ - { - LocatorWithResolverConfig: artifactresolver.LocatorWithResolverConfig{ - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel:override:1.2.3", - }, - }, - Assets: []artifactresolver.LocatorWithResolverConfig{ - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.test:test-asset-1:2.3.4", - }, - }, - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.test:test-asset-2:3.4.5", - }, - }, - }, - }, - }, - }, - }, - { - "specifying custom asset adds only that asset", - DefaultTasksConfig{ - Tasks: map[string]SingleDefaultTaskConfig{ - "com.palantir.test:test-plugin": { - Assets: []artifactresolver.LocatorWithResolverConfig{ - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel:custom-asset:1.2.3", - }, - }, - }, - }, - }, - }, - PluginsConfig{ - DefaultResolvers: []string{ - defaultResolver, - }, - Plugins: []SinglePluginConfig{ - { - LocatorWithResolverConfig: artifactresolver.LocatorWithResolverConfig{ - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.test:test-plugin:1.2.3", - }, - }, - Assets: []artifactresolver.LocatorWithResolverConfig{ - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.test:test-asset-1:2.3.4", - }, - }, - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.test:test-asset-2:3.4.5", - }, - }, - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel:custom-asset:1.2.3", - }, - }, - }, - }, - }, - }, - }, - { - "setting exclude all and specifying custom asset adds asset to default", - DefaultTasksConfig{ - Tasks: map[string]SingleDefaultTaskConfig{ - "com.palantir.test:test-plugin": { - ExcludeAllDefaultAssets: true, - Assets: []artifactresolver.LocatorWithResolverConfig{ - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel:custom-asset:1.2.3", - }, - }, - }, - }, - }, - }, - PluginsConfig{ - DefaultResolvers: []string{ - defaultResolver, - }, - Plugins: []SinglePluginConfig{ - { - LocatorWithResolverConfig: artifactresolver.LocatorWithResolverConfig{ - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.test:test-plugin:1.2.3", - }, - }, - Assets: []artifactresolver.LocatorWithResolverConfig{ - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel:custom-asset:1.2.3", - }, - }, - }, - }, - }, - }, - }, - { - "specifying default asset with exclude and custom asset adds asset", - DefaultTasksConfig{ - Tasks: map[string]SingleDefaultTaskConfig{ - "com.palantir.test:test-plugin": { - DefaultAssetsToExclude: []string{ - "com.palantir.test:test-asset-2", - }, - Assets: []artifactresolver.LocatorWithResolverConfig{ - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel:custom-asset:1.2.3", - }, - }, - }, - }, - }, - }, - PluginsConfig{ - DefaultResolvers: []string{ - defaultResolver, - }, - Plugins: []SinglePluginConfig{ - { - LocatorWithResolverConfig: artifactresolver.LocatorWithResolverConfig{ - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.test:test-plugin:1.2.3", - }, - }, - Assets: []artifactresolver.LocatorWithResolverConfig{ - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.test:test-asset-1:2.3.4", - }, - }, - { - Locator: artifactresolver.LocatorConfig{ - ID: "com.palantir.godel:custom-asset:1.2.3", - }, - }, - }, - }, - }, - }, - }, - } { - got := DefaultTasksPluginsConfig(tc.in) - assert.Equal(t, tc.want, got, "Case %d: %s", i, tc.name) - } -} diff --git a/vendor/github.com/palantir/godel/framework/godellauncher/globalconfig.go b/vendor/github.com/palantir/godel/framework/godellauncher/globalconfig.go index 03498e71..36667227 100644 --- a/vendor/github.com/palantir/godel/framework/godellauncher/globalconfig.go +++ b/vendor/github.com/palantir/godel/framework/godellauncher/globalconfig.go @@ -20,7 +20,7 @@ import ( "github.com/pkg/errors" ) -// GlobalConfig stores the configuration provided to the initial invocation of gödel. +// GlobalConfig stores the configuration provided to the initial invocation of gödel. type GlobalConfig struct { // Path to the gödel executable Executable string diff --git a/vendor/github.com/palantir/godel/framework/godellauncher/param.go b/vendor/github.com/palantir/godel/framework/godellauncher/param.go new file mode 100644 index 00000000..d5ea6e06 --- /dev/null +++ b/vendor/github.com/palantir/godel/framework/godellauncher/param.go @@ -0,0 +1,55 @@ +// Copyright 2016 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package godellauncher + +import ( + "github.com/palantir/pkg/specdir" + "github.com/pkg/errors" + + "github.com/palantir/godel/framework/artifactresolver" + "github.com/palantir/godel/framework/builtintasks/installupdate/layout" +) + +const ( + GodelConfigYML = "godel.yml" +) + +type TasksConfigProvidersParam struct { + DefaultResolvers []artifactresolver.Resolver + ConfigProviders []artifactresolver.LocatorWithResolverParam +} + +type PluginsParam struct { + DefaultResolvers []artifactresolver.Resolver + Plugins []SinglePluginParam +} + +type SinglePluginParam struct { + artifactresolver.LocatorWithResolverParam + Assets []artifactresolver.LocatorWithResolverParam +} + +// ConfigDirPath returns the path to the gödel configuration directory given the path to the project directory. Returns +// an error if the directory structure does not match what is expected. +func ConfigDirPath(projectDirPath string) (string, error) { + if projectDirPath == "" { + return "", errors.Errorf("projectDirPath was empty") + } + wrapper, err := specdir.New(projectDirPath, layout.WrapperSpec(), nil, specdir.Validate) + if err != nil { + return "", err + } + return wrapper.Path(layout.WrapperConfigDir), nil +} diff --git a/vendor/github.com/palantir/godel/framework/godellauncher/upgradeconfigtask.go b/vendor/github.com/palantir/godel/framework/godellauncher/upgradeconfigtask.go index 04c54c8a..9d590af8 100644 --- a/vendor/github.com/palantir/godel/framework/godellauncher/upgradeconfigtask.go +++ b/vendor/github.com/palantir/godel/framework/godellauncher/upgradeconfigtask.go @@ -23,9 +23,12 @@ type UpgradeConfigTask struct { // "com.palantir.format-plugin:format-plugin", etc.). ID string - // The name of the configuration file for the task ("godel.yml", "okgo-plugin.yml" etc.). + // The name of the configuration file for the task ("godel.yml", "check-plugin.yml" etc.). ConfigFile string + // The name of the legacy configuration file for the task. Blank if none exists. + LegacyConfigFile string + // Configures the manner in which the global flags are processed. GlobalFlagOpts GlobalFlagOptions diff --git a/vendor/github.com/palantir/godel/framework/internal/legacyplugins/legacyplugins.go b/vendor/github.com/palantir/godel/framework/internal/legacyplugins/legacyplugins.go deleted file mode 100644 index 70431df8..00000000 --- a/vendor/github.com/palantir/godel/framework/internal/legacyplugins/legacyplugins.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2016 Palantir Technologies, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package legacyplugins - -type LegacyConfigUpgrader struct { - LegacyConfigFileName string -} - -var LegacyConfigUpgraders = map[string]LegacyConfigUpgrader{ - "com.palantir.okgo:check-plugin": { - LegacyConfigFileName: "check.yml", - }, - "com.palantir.distgo:dist-plugin": { - LegacyConfigFileName: "dist.yml", - }, - "com.palantir.godel-format-plugin:format-plugin": { - LegacyConfigFileName: "format.yml", - }, - "com.palantir.generate:generate-plugin": { - LegacyConfigFileName: "generate.yml", - }, - "com.palantir.go-license:license-plugin": { - LegacyConfigFileName: "license.yml", - }, - "com.palantir.godel-test-plugin:test-plugin": { - LegacyConfigFileName: "test.yml", - }, -} - -func ReservedConfigFileNames() map[string]struct{} { - reservedNames := make(map[string]struct{}) - for _, v := range LegacyConfigUpgraders { - reservedNames[v.LegacyConfigFileName] = struct{}{} - } - return reservedNames -} diff --git a/vendor/github.com/palantir/godel/framework/pluginapi/plugininfo.go b/vendor/github.com/palantir/godel/framework/pluginapi/plugininfo.go index 571156ee..5b338631 100644 --- a/vendor/github.com/palantir/godel/framework/pluginapi/plugininfo.go +++ b/vendor/github.com/palantir/godel/framework/pluginapi/plugininfo.go @@ -22,7 +22,6 @@ import ( "github.com/pkg/errors" "github.com/palantir/godel/framework/godellauncher" - "github.com/palantir/godel/framework/internal/legacyplugins" ) const ( @@ -41,9 +40,6 @@ type PluginInfo interface { ConfigFileName() string // Tasks returns the tasks provided by the plugin. Requires the path to the plugin executable and assets as input. Tasks(pluginExecPath string, assets []string) []godellauncher.Task - // UpgradeConfigTask returns the task that upgrades the configuration for this plugin. Returns nil if the plugin - // does not support upgrading configuration. - UpgradeConfigTask(pluginExecPath string, assets []string) *godellauncher.UpgradeConfigTask // private function on interface to keep implementation private to package. private() @@ -75,10 +71,6 @@ func NewPluginInfo(group, product, version string, params ...PluginInfoParam) (P for i := range builder.tasks { builder.tasks[i].GlobalFlagOptionsVar = builder.globalFlagOpts } - if builder.upgradeConfigTask != nil { - builder.upgradeConfigTask.PluginID = fmt.Sprintf("%s:%s", group, product) - builder.upgradeConfigTask.GlobalFlagOptionsVar = builder.globalFlagOpts - } taskNameMap := make(map[string]struct{}) for _, task := range builder.tasks { @@ -93,28 +85,18 @@ func NewPluginInfo(group, product, version string, params ...PluginInfoParam) (P configFileName = product + ".yml" } - if builder.upgradeConfigTask != nil && !builder.usesConfigFile { - return nil, errors.Errorf(`plugin %s provides a configuration upgrade task but does not specify that it uses configuration`, id) - } - - if _, ok := legacyplugins.ReservedConfigFileNames()[configFileName]; ok { - return nil, errors.Errorf(`plugin %s uses configuration file %s, which is a reserved name. Use a different name if possible. If this is not possible, please file an issue for discussion.`, id, configFileName) - } - return pluginInfoImpl{ PluginSchemaVersionVar: CurrentSchemaVersion, - IDVar: id, - ConfigFileNameVar: configFileName, - TasksVar: builder.tasks, - UpgradeConfigTaskVar: builder.upgradeConfigTask, + IDVar: id, + ConfigFileNameVar: configFileName, + TasksVar: builder.tasks, }, nil } type pluginInfoBuilder struct { - usesConfigFile bool - tasks []taskInfoImpl - globalFlagOpts *globalFlagOptionsImpl - upgradeConfigTask *upgradeConfigTaskInfoImpl + usesConfigFile bool + tasks []taskInfoImpl + globalFlagOpts *globalFlagOptionsImpl } type PluginInfoParam interface { @@ -155,16 +137,6 @@ func PluginInfoGlobalFlagOptions(params ...GlobalFlagOptionsParam) PluginInfoPar }) } -func PluginInfoUpgradeConfigTaskInfo(params ...UpgradeConfigTaskInfoParam) PluginInfoParam { - return pluginInfoParamFunc(func(impl *pluginInfoBuilder) error { - if len(params) == 0 { - return errors.Errorf("at least one param must be provided for upgrade configuration") - } - impl.upgradeConfigTask = newUpgradeConfigTaskInfoImpl(params...) - return nil - }) -} - // pluginInfoImpl is a concrete implementation of Info. Note that the functions are defined on non-pointer receivers to reduce // bugs in calling functions in closures. type pluginInfoImpl struct { @@ -175,8 +147,6 @@ type pluginInfoImpl struct { ConfigFileNameVar string `json:"configFileName"` // The tasks provided by the plugin. TasksVar []taskInfoImpl `json:"tasks"` - // The configuration upgrade task provided by the plugin. - UpgradeConfigTaskVar *upgradeConfigTaskInfoImpl `json:"upgradeTask"` } func (infoImpl pluginInfoImpl) PluginSchemaVersion() string { @@ -199,14 +169,6 @@ func (infoImpl pluginInfoImpl) Tasks(pluginExecPath string, assets []string) []g return tasks } -func (infoImpl pluginInfoImpl) UpgradeConfigTask(pluginExecPath string, assets []string) *godellauncher.UpgradeConfigTask { - if infoImpl.UpgradeConfigTaskVar == nil { - return nil - } - taskVar := infoImpl.UpgradeConfigTaskVar.toTask(pluginExecPath, infoImpl.ConfigFileNameVar, assets) - return &taskVar -} - func (infoImpl pluginInfoImpl) private() {} // InfoFromPlugin returns the Info for the plugin at the specified path. Does so by invoking the InfoCommand on the @@ -218,9 +180,17 @@ func InfoFromPlugin(pluginPath string) (PluginInfo, error) { return nil, errors.Wrapf(err, "command %v failed.\nError:\n%v\nOutput:\n%s\n", cmd.Args, err, string(bytes)) } + info, err := InfoFromBytes(bytes) + if err != nil { + return nil, errors.Wrapf(err, "failed to unmarshal plugin information for plugin %s", pluginPath) + } + return info, nil +} + +func InfoFromBytes(infoBytes []byte) (PluginInfo, error) { var info pluginInfoImpl - if err := json.Unmarshal(bytes, &info); err != nil { - return nil, errors.Wrapf(err, "failed to unmarshal plugin information for plugin %s from output %q", pluginPath, string(bytes)) + if err := json.Unmarshal(infoBytes, &info); err != nil { + return nil, errors.Wrapf(err, "failed to unmarshal plugin information from output %q", string(infoBytes)) } return info, nil } diff --git a/vendor/github.com/palantir/godel/framework/pluginapi/plugininfo_test.go b/vendor/github.com/palantir/godel/framework/pluginapi/plugininfo_test.go index 06622b6a..c33e611a 100644 --- a/vendor/github.com/palantir/godel/framework/pluginapi/plugininfo_test.go +++ b/vendor/github.com/palantir/godel/framework/pluginapi/plugininfo_test.go @@ -28,7 +28,7 @@ import ( "github.com/palantir/godel/framework/builtintasks" "github.com/palantir/godel/framework/godellauncher" - "github.com/palantir/godel/framework/pluginapi" + "github.com/palantir/godel/framework/pluginapi/v2/pluginapi" ) var echoPluginTmpl = fmt.Sprintf(`#!/bin/sh @@ -41,13 +41,15 @@ echo $@ `, pluginapi.PluginInfoCommandName, `%s`) func TestNewPluginInfo(t *testing.T) { - info, err := pluginapi.NewPluginInfo("group", "product", "1.0.0", + info, err := pluginapi.NewPluginInfo("group", "product-plugin", "1.0.0", pluginapi.PluginInfoUsesConfigFile(), ) require.NoError(t, err) assert.Equal(t, pluginapi.CurrentSchemaVersion, info.PluginSchemaVersion()) - assert.Equal(t, "group:product:1.0.0", info.ID()) + assert.Equal(t, "group", info.Group()) + assert.Equal(t, "product-plugin", info.Product()) + assert.Equal(t, "1.0.0", info.Version()) assert.Nil(t, info.Tasks("", nil)) assert.Nil(t, info.UpgradeConfigTask("", nil)) } @@ -59,33 +61,33 @@ func TestPluginInfoJSONMarshal(t *testing.T) { want string }{ { - "group", "product", "1.0.0", + "group", "product-plugin", "1.0.0", []pluginapi.PluginInfoParam{ pluginapi.PluginInfoUsesConfigFile(), }, - `{"pluginSchemaVersion":"1","id":"group:product:1.0.0","configFileName":"product.yml","tasks":null,"upgradeTask":null}`, + `{"pluginSchemaVersion":"2","group":"group","product":"product-plugin","version":"1.0.0","usesConfig":true,"tasks":null,"upgradeTask":null}`, }, { - "group", "product", "1.0.0", + "group", "product-plugin", "1.0.0", []pluginapi.PluginInfoParam{ pluginapi.PluginInfoUsesConfigFile(), pluginapi.PluginInfoTaskInfo("foo", "does foo things"), }, - `{"pluginSchemaVersion":"1","id":"group:product:1.0.0","configFileName":"product.yml","tasks":[{"name":"foo","description":"does foo things","command":null,"globalFlagOptions":null,"verifyOptions":null}],"upgradeTask":null}`, + `{"pluginSchemaVersion":"2","group":"group","product":"product-plugin","version":"1.0.0","usesConfig":true,"tasks":[{"name":"foo","description":"does foo things","command":null,"globalFlagOptions":null,"verifyOptions":null}],"upgradeTask":null}`, }, { - "group", "product", "1.0.0", + "group", "product-plugin", "1.0.0", []pluginapi.PluginInfoParam{ pluginapi.PluginInfoUsesConfigFile(), pluginapi.PluginInfoTaskInfo("foo", "does foo things", pluginapi.TaskInfoCommand("foo"), - pluginapi.TaskInfoVerifyOptions(pluginapi.NewVerifyOptions()), + pluginapi.TaskInfoVerifyOptions(), ), }, - `{"pluginSchemaVersion":"1","id":"group:product:1.0.0","configFileName":"product.yml","tasks":[{"name":"foo","description":"does foo things","command":["foo"],"globalFlagOptions":null,"verifyOptions":{"verifyTaskFlags":null,"ordering":null,"applyTrueArgs":null,"applyFalseArgs":null}}],"upgradeTask":null}`, + `{"pluginSchemaVersion":"2","group":"group","product":"product-plugin","version":"1.0.0","usesConfig":true,"tasks":[{"name":"foo","description":"does foo things","command":["foo"],"globalFlagOptions":null,"verifyOptions":{"verifyTaskFlags":null,"ordering":null,"applyTrueArgs":null,"applyFalseArgs":null}}],"upgradeTask":null}`, }, { - "group", "product", "1.0.0", + "group", "product-plugin", "1.0.0", []pluginapi.PluginInfoParam{ pluginapi.PluginInfoUsesConfigFile(), pluginapi.PluginInfoGlobalFlagOptions( @@ -93,10 +95,10 @@ func TestPluginInfoJSONMarshal(t *testing.T) { ), pluginapi.PluginInfoTaskInfo("foo", "does foo things", pluginapi.TaskInfoCommand("foo"), - pluginapi.TaskInfoVerifyOptions(pluginapi.NewVerifyOptions()), + pluginapi.TaskInfoVerifyOptions(), ), }, - `{"pluginSchemaVersion":"1","id":"group:product:1.0.0","configFileName":"product.yml","tasks":[{"name":"foo","description":"does foo things","command":["foo"],"globalFlagOptions":{"debugFlag":"","projectDirFlag":"--project-dir","godelConfigFlag":"","configFlag":""},"verifyOptions":{"verifyTaskFlags":null,"ordering":null,"applyTrueArgs":null,"applyFalseArgs":null}}],"upgradeTask":null}`, + `{"pluginSchemaVersion":"2","group":"group","product":"product-plugin","version":"1.0.0","usesConfig":true,"tasks":[{"name":"foo","description":"does foo things","command":["foo"],"globalFlagOptions":{"debugFlag":"","projectDirFlag":"--project-dir","godelConfigFlag":"","configFlag":""},"verifyOptions":{"verifyTaskFlags":null,"ordering":null,"applyTrueArgs":null,"applyFalseArgs":null}}],"upgradeTask":null}`, }, } { info, err := pluginapi.NewPluginInfo(tc.group, tc.product, tc.version, tc.params...) @@ -105,7 +107,7 @@ func TestPluginInfoJSONMarshal(t *testing.T) { bytes, err := json.Marshal(info) require.NoError(t, err, "Case %d", i) - assert.Equal(t, tc.want, string(bytes), "Case %d", i) + assert.Equal(t, tc.want, string(bytes), "Case %d\nGot:\n%s", i, string(bytes)) } } @@ -118,28 +120,20 @@ func TestNewPluginInfoError(t *testing.T) { }{ { "plugins cannot provide multiple tasks with the same name", - "group", "product", "1.0.0", + "group", "product-plugin", "1.0.0", []pluginapi.PluginInfoParam{ pluginapi.PluginInfoTaskInfo("name", "description"), pluginapi.PluginInfoTaskInfo("name", "description-2"), }, - `plugin group:product:1.0.0 specifies multiple tasks with name "name"`, + `plugin group:product-plugin:1.0.0 specifies multiple tasks with name "name"`, }, { "plugin cannot provide upgrade task if it does not use configuration", - "group", "product", "1.0.0", + "group", "product-plugin", "1.0.0", []pluginapi.PluginInfoParam{ pluginapi.PluginInfoUpgradeConfigTaskInfo(pluginapi.UpgradeConfigTaskInfoCommand("upgrade-task")), }, - `plugin group:product:1.0.0 provides a configuration upgrade task but does not specify that it uses configuration`, - }, - { - "plugin cannot have a name that conflicts with a reserved config file name", - "group", "generate", "1.0.0", - []pluginapi.PluginInfoParam{ - pluginapi.PluginInfoUsesConfigFile(), - }, - `plugin group:generate:1.0.0 uses configuration file generate.yml, which is a reserved name. Use a different name if possible. If this is not possible, please file an issue for discussion.`, + `plugin group:product-plugin:1.0.0 provides a configuration upgrade task but does not specify that it uses configuration`, }, } { _, err := pluginapi.NewPluginInfo(tc.group, tc.product, tc.version, tc.params...) @@ -221,7 +215,7 @@ func TestRunPluginFromInfo(t *testing.T) { }, 0, func(assetDir string) string { - return "--project-dir ../.. --godel-config ../../godel/config/godel.yml --config ../../godel/config/echo.yml --echo-bool-flag -f echo-str-flag-val echo-arg\n" + return "--project-dir ../.. --godel-config ../../godel/config/godel.yml --config ../../godel/config/echo-plugin.yml --echo-bool-flag -f echo-str-flag-val echo-arg\n" }, }, { @@ -247,7 +241,7 @@ func TestRunPluginFromInfo(t *testing.T) { }, }, } { - pluginInfo, err := pluginapi.NewPluginInfo("group", "echo", "1.0.0", + pluginInfo, err := pluginapi.NewPluginInfo("group", "echo-plugin", "1.0.0", append([]pluginapi.PluginInfoParam{ pluginapi.PluginInfoUsesConfigFile(), pluginapi.PluginInfoTaskInfo("echo", "echoes the provided input"), @@ -303,10 +297,10 @@ func TestRunPluginVerify(t *testing.T) { nil, []pluginapi.TaskInfoParam{ pluginapi.TaskInfoCommand("verify-subcmd"), - pluginapi.TaskInfoVerifyOptions(pluginapi.NewVerifyOptions( + pluginapi.TaskInfoVerifyOptions( pluginapi.VerifyOptionsApplyFalseArgs("--no-apply"), pluginapi.VerifyOptionsApplyTrueArgs("--apply"), - )), + ), }, godellauncher.GlobalConfig{ TaskArgs: []string{"verify"}, @@ -318,10 +312,10 @@ func TestRunPluginVerify(t *testing.T) { nil, []pluginapi.TaskInfoParam{ pluginapi.TaskInfoCommand("verify-subcmd"), - pluginapi.TaskInfoVerifyOptions(pluginapi.NewVerifyOptions( + pluginapi.TaskInfoVerifyOptions( pluginapi.VerifyOptionsApplyFalseArgs("--no-apply"), pluginapi.VerifyOptionsApplyTrueArgs("--apply"), - )), + ), }, godellauncher.GlobalConfig{ TaskArgs: []string{"verify", "--apply=false"}, @@ -337,10 +331,10 @@ func TestRunPluginVerify(t *testing.T) { }, []pluginapi.TaskInfoParam{ pluginapi.TaskInfoCommand("verify-subcmd"), - pluginapi.TaskInfoVerifyOptions(pluginapi.NewVerifyOptions( + pluginapi.TaskInfoVerifyOptions( pluginapi.VerifyOptionsApplyFalseArgs("--no-apply"), pluginapi.VerifyOptionsApplyTrueArgs("--apply"), - )), + ), }, godellauncher.GlobalConfig{ TaskArgs: []string{"verify"}, @@ -349,7 +343,7 @@ func TestRunPluginVerify(t *testing.T) { "Running echo...\n--project-dir . verify-subcmd --apply\n", }, } { - pluginInfo, err := pluginapi.NewPluginInfo("group", "echo", "1.0.0", + pluginInfo, err := pluginapi.NewPluginInfo("group", "echo-plugin", "1.0.0", append([]pluginapi.PluginInfoParam{ pluginapi.PluginInfoUsesConfigFile(), pluginapi.PluginInfoTaskInfo("echo", "echoes the provided input", tc.taskInfoParams...), diff --git a/vendor/github.com/palantir/godel/godelconfig/VersionedConfig.go b/vendor/github.com/palantir/godel/framework/pluginapi/schemaversion.go similarity index 83% rename from vendor/github.com/palantir/godel/godelconfig/VersionedConfig.go rename to vendor/github.com/palantir/godel/framework/pluginapi/schemaversion.go index d094e8af..66fd7616 100644 --- a/vendor/github.com/palantir/godel/godelconfig/VersionedConfig.go +++ b/vendor/github.com/palantir/godel/framework/pluginapi/schemaversion.go @@ -12,9 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -package godelconfig +package pluginapi -type VersionedConfig struct { - // Version of the current configuration. - Version int `yaml:"version"` +type SchemaVersion struct { + PluginSchemaVersionVar string `json:"pluginSchemaVersion"` } diff --git a/vendor/github.com/palantir/godel/framework/pluginapi/taskinfo.go b/vendor/github.com/palantir/godel/framework/pluginapi/taskinfo.go index 9e4dda30..1a4312c3 100644 --- a/vendor/github.com/palantir/godel/framework/pluginapi/taskinfo.go +++ b/vendor/github.com/palantir/godel/framework/pluginapi/taskinfo.go @@ -66,8 +66,9 @@ func TaskInfoCommand(command ...string) TaskInfoParam { }) } -func TaskInfoVerifyOptions(verifyOpts VerifyOptions) TaskInfoParam { +func TaskInfoVerifyOptions(params ...VerifyOptionsParam) TaskInfoParam { return taskInfoParamFunc(func(impl *taskInfoImpl) { + verifyOpts := newVerifyOptionsImpl(params...) var verifyImpls []verifyFlagImpl for _, v := range verifyOpts.VerifyTaskFlags() { verifyImpls = append(verifyImpls, verifyFlagImpl{ diff --git a/vendor/github.com/palantir/godel/framework/godellauncher/defaultupgradetasks.go b/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/cli.go similarity index 58% rename from vendor/github.com/palantir/godel/framework/godellauncher/defaultupgradetasks.go rename to vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/cli.go index ef99d5e3..d1fbbeb3 100644 --- a/vendor/github.com/palantir/godel/framework/godellauncher/defaultupgradetasks.go +++ b/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/cli.go @@ -12,24 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -package godellauncher +package pluginapi import ( "io" ) -func BuiltinUpgradeConfigTasks() []UpgradeConfigTask { - return []UpgradeConfigTask{ - upgradeGodelConfigTask(), - } -} - -func upgradeGodelConfigTask() UpgradeConfigTask { - return UpgradeConfigTask{ - ID: "com.palantir.godel:godel", - ConfigFile: "godel.yml", - RunImpl: func(t *UpgradeConfigTask, global GlobalConfig, configBytes []byte, stdout io.Writer) ([]byte, error) { - return UpgradeGodelConfig(configBytes) - }, +func InfoCmd(osArgs []string, stdout io.Writer, info PluginInfo) bool { + if len(osArgs) < 2 || osArgs[1] != PluginInfoCommandName { + return false } + _ = infoAction(info, stdout) + return true } diff --git a/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/cobracli.go b/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/cobracli.go new file mode 100644 index 00000000..7987ede9 --- /dev/null +++ b/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/cobracli.go @@ -0,0 +1,75 @@ +// Copyright 2016 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pluginapi + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "io" + + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +const usage = "Prints the gödel plugin.Info struct in its JSON-serialized form" + +func CobraInfoCmd(info PluginInfo) *cobra.Command { + return &cobra.Command{ + Use: PluginInfoCommandName, + Short: usage, + Hidden: true, + RunE: func(cmd *cobra.Command, args []string) error { + return infoAction(info, cmd.OutOrStdout()) + }, + } +} + +type UpgradeConfigFn func(cfg []byte) ([]byte, error) + +func CobraUpgradeConfigCmd(upgradeFn UpgradeConfigFn) *cobra.Command { + return &cobra.Command{ + Use: "upgrade-config [base64-config-content]", + Short: "Print the upgraded version of the provided config", + Long: `Prints the base64-encoded representation of the updated version of the provided configuration, which is +provided as a base64-encoded string. If the provided configuration is a valid representation of the newest version, it +is printed unmodified. If the upgrade fails, exits with a non-0 exit code and prints the error.`, + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) != 1 { + return errors.Errorf("input must be exactly one argument, was %d: %v", len(args), args) + } + cfgBytes, err := base64.StdEncoding.DecodeString(args[0]) + if err != nil { + return errors.Wrapf(err, "failed to decode input as base64") + } + + upgradedCfg, err := upgradeFn(cfgBytes) + if err != nil { + return err + } + cmd.Print(base64.StdEncoding.EncodeToString(upgradedCfg)) + return nil + }, + } +} + +func infoAction(info PluginInfo, w io.Writer) error { + bytes, err := json.Marshal(info) + if err != nil { + return fmt.Errorf("failed to marshal plugin info: %v", err) + } + fmt.Fprint(w, string(bytes)) + return nil +} diff --git a/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/flags.go b/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/flags.go new file mode 100644 index 00000000..d46b258a --- /dev/null +++ b/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/flags.go @@ -0,0 +1,104 @@ +// Copyright 2016 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pluginapi + +import ( + "flag" +) + +const ( + // DebugFlagName is the name of the boolean flag that will be provided as "--" if "debug" is true. + DebugFlagName = "debug" + // ProjectDirFlagName is the name of the string flag that is provided as "-- ", where + // "" is the + // path to the project directory. + ProjectDirFlagName = "project-dir" + // GodelConfigFlagName is the name of the string flag that is provided as "-- ", where + // "" is the path to the configuration file for gödel. + GodelConfigFlagName = "godel-config" + // ConfigFlagName is the name of the string flag that is provided as "-- ", where "" + // is the path to the configuration file for the plugin. + ConfigFlagName = "config" + // AssetsFlagName is the name of the assets flag that is provided as "-- ", where "" + // is a comma-delimited list of the paths to the assets for the plugin. + AssetsFlagName = "assets" +) + +func AddDebugFlag(fset *flag.FlagSet) *bool { + var debug bool + AddDebugFlagPtr(fset, &debug) + return &debug +} + +func AddDebugFlagPtr(fset *flag.FlagSet, debug *bool) { + if debug == nil { + return + } + fset.BoolVar(debug, DebugFlagName, false, "run in debug mode") +} + +func AddProjectDirFlag(fset *flag.FlagSet) *string { + return addStringFlag(fset, AddProjectDirFlagPtr) +} + +func AddProjectDirFlagPtr(fset *flag.FlagSet, projectDir *string) { + if projectDir == nil { + return + } + fset.StringVar(projectDir, ProjectDirFlagName, "", "path to project directory") +} + +func AddGodelConfigFlag(fset *flag.FlagSet) *string { + return addStringFlag(fset, AddGodelConfigFlagPtr) +} + +func AddGodelConfigFlagPtr(fset *flag.FlagSet, godelConfig *string) { + if godelConfig == nil { + return + } + fset.StringVar(godelConfig, GodelConfigFlagName, "", "path to the godel.yml configuration file") +} + +func AddConfigFlag(fset *flag.FlagSet) *string { + return addStringFlag(fset, AddConfigFlagPtr) +} + +func AddConfigFlagPtr(fset *flag.FlagSet, config *string) { + if config == nil { + return + } + fset.String(ConfigFlagName, "", "path to the plugin configuration file") +} + +func addStringFlag(fset *flag.FlagSet, fn func(*flag.FlagSet, *string)) *string { + var str string + fn(fset, &str) + return &str +} + +func AddAllFlags(fset *flag.FlagSet) (debug *bool, projectDir *string, godelConfig *string, config *string) { + debug = AddDebugFlag(fset) + projectDir = AddProjectDirFlag(fset) + godelConfig = AddGodelConfigFlag(fset) + config = AddConfigFlag(fset) + return +} + +func AddAllFlagsPtrs(fset *flag.FlagSet, debug *bool, projectDir *string, godelConfig *string, config *string) { + AddDebugFlagPtr(fset, debug) + AddProjectDirFlagPtr(fset, projectDir) + AddGodelConfigFlagPtr(fset, godelConfig) + AddConfigFlagPtr(fset, config) +} diff --git a/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/globalflagopts.go b/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/globalflagopts.go new file mode 100644 index 00000000..bfc5d254 --- /dev/null +++ b/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/globalflagopts.go @@ -0,0 +1,112 @@ +// Copyright 2016 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pluginapi + +import ( + "github.com/palantir/godel/framework/godellauncher" +) + +// GlobalFlagOptions is a JSON-serializable interface that can be translated into a godellauncher.GlobalFlagOptions. +// See godellauncher.GlobalFlagOptions for documentation. +type GlobalFlagOptions interface { + DebugFlag() string + ProjectDirFlag() string + GodelConfigFlag() string + ConfigFlag() string + + toGodelGlobalFlagOptions() godellauncher.GlobalFlagOptions +} + +// globalFlagOptionsImpl is a concrete implementation of GlobalFlagOptions. Note that the functions are defined on +// non-pointer receivers to reduce bugs in calling functions in closures. +type globalFlagOptionsImpl struct { + DebugFlagVar string `json:"debugFlag"` + ProjectDirFlagVar string `json:"projectDirFlag"` + GodelConfigFlagVar string `json:"godelConfigFlag"` + ConfigFlagVar string `json:"configFlag"` +} + +type GlobalFlagOptionsParam interface { + apply(*globalFlagOptionsImpl) +} + +type globalFlagOptionsParamFunc func(*globalFlagOptionsImpl) + +func (f globalFlagOptionsParamFunc) apply(impl *globalFlagOptionsImpl) { + f(impl) +} + +func GlobalFlagOptionsParamDebugFlag(debugFlag string) GlobalFlagOptionsParam { + return globalFlagOptionsParamFunc(func(impl *globalFlagOptionsImpl) { + impl.DebugFlagVar = debugFlag + }) +} + +func GlobalFlagOptionsParamProjectDirFlag(projectDirFlag string) GlobalFlagOptionsParam { + return globalFlagOptionsParamFunc(func(impl *globalFlagOptionsImpl) { + impl.ProjectDirFlagVar = projectDirFlag + }) +} + +func GlobalFlagOptionsParamGodelConfigFlag(godelConfigFlag string) GlobalFlagOptionsParam { + return globalFlagOptionsParamFunc(func(impl *globalFlagOptionsImpl) { + impl.GodelConfigFlagVar = godelConfigFlag + }) +} + +func GlobalFlagOptionsParamConfigFlag(configFlag string) GlobalFlagOptionsParam { + return globalFlagOptionsParamFunc(func(impl *globalFlagOptionsImpl) { + impl.ConfigFlagVar = configFlag + }) +} + +func newGlobalFlagOptionsImpl(params ...GlobalFlagOptionsParam) *globalFlagOptionsImpl { + if len(params) == 0 { + return nil + } + impl := &globalFlagOptionsImpl{} + for _, p := range params { + if p == nil { + continue + } + p.apply(impl) + } + return impl +} + +func (g globalFlagOptionsImpl) DebugFlag() string { + return g.DebugFlagVar +} + +func (g globalFlagOptionsImpl) ProjectDirFlag() string { + return g.ProjectDirFlagVar +} + +func (g globalFlagOptionsImpl) GodelConfigFlag() string { + return g.GodelConfigFlagVar +} + +func (g globalFlagOptionsImpl) ConfigFlag() string { + return g.ConfigFlagVar +} + +func (g globalFlagOptionsImpl) toGodelGlobalFlagOptions() godellauncher.GlobalFlagOptions { + return godellauncher.GlobalFlagOptions{ + DebugFlag: g.DebugFlagVar, + ProjectDirFlag: g.ProjectDirFlagVar, + GodelConfigFlag: g.GodelConfigFlagVar, + ConfigFlag: g.ConfigFlagVar, + } +} diff --git a/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/pflags.go b/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/pflags.go new file mode 100644 index 00000000..e1befdc1 --- /dev/null +++ b/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/pflags.go @@ -0,0 +1,105 @@ +// Copyright 2016 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pluginapi + +import ( + "flag" + + "github.com/spf13/pflag" +) + +func AddAllPFlags(fset *pflag.FlagSet) (debug *bool, projectDir *string, godelConfig *string, config *string, assets *[]string) { + goFlagSet := &flag.FlagSet{} + debug, projectDir, godelConfig, config = AddAllFlags(goFlagSet) + fset.AddGoFlagSet(goFlagSet) + assets = AddAssetsPFlag(fset) + return +} + +func AddAllPFlagsPtrs(fset *pflag.FlagSet, debug *bool, projectDir *string, godelConfig *string, config *string, assets *[]string) { + goFlagSet := &flag.FlagSet{} + AddAllFlagsPtrs(goFlagSet, debug, projectDir, godelConfig, config) + fset.AddGoFlagSet(goFlagSet) + AddAssetsPFlagPtr(fset, assets) +} + +func AddDebugPFlag(fset *pflag.FlagSet) *bool { + gofset := &flag.FlagSet{} + debug := AddDebugFlag(gofset) + fset.AddGoFlagSet(gofset) + return debug +} + +func AddDebugPFlagPtr(fset *pflag.FlagSet, debug *bool) { + if debug == nil { + return + } + fset.BoolVar(debug, DebugFlagName, false, "run in debug mode") +} + +func AddProjectDirPFlag(fset *pflag.FlagSet) *string { + gofset := &flag.FlagSet{} + projectDir := AddProjectDirFlag(gofset) + fset.AddGoFlagSet(gofset) + return projectDir +} + +func AddProjectDirPFlagPtr(fset *pflag.FlagSet, projectDir *string) { + if projectDir == nil { + return + } + fset.StringVar(projectDir, ProjectDirFlagName, "", "path to project directory") +} + +func AddGodelConfigPFlag(fset *pflag.FlagSet) *string { + gofset := &flag.FlagSet{} + godelConfig := AddGodelConfigFlag(gofset) + fset.AddGoFlagSet(gofset) + return godelConfig +} + +func AddGodelConfigPFlagPtr(fset *pflag.FlagSet, godelConfig *string) { + if godelConfig == nil { + return + } + fset.StringVar(godelConfig, GodelConfigFlagName, "", "path to the godel.yml configuration file") +} + +func AddConfigPFlag(fset *pflag.FlagSet) *string { + gofset := &flag.FlagSet{} + config := AddConfigFlag(gofset) + fset.AddGoFlagSet(gofset) + return config +} + +func AddConfigPFlagPtr(fset *pflag.FlagSet, config *string) { + if config == nil { + return + } + fset.StringVar(config, ConfigFlagName, "", "path to the plugin configuration file") +} + +func AddAssetsPFlag(fset *pflag.FlagSet) *[]string { + var assets []string + AddAssetsPFlagPtr(fset, &assets) + return &assets +} + +func AddAssetsPFlagPtr(fset *pflag.FlagSet, assets *[]string) { + if assets == nil { + return + } + fset.StringSliceVar(assets, AssetsFlagName, nil, "path(s) to the plugin asset(s)") +} diff --git a/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/plugininfo.go b/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/plugininfo.go new file mode 100644 index 00000000..d9adefde --- /dev/null +++ b/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/plugininfo.go @@ -0,0 +1,341 @@ +// Copyright 2016 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pluginapi + +import ( + "encoding/json" + "fmt" + "os/exec" + "strings" + + "github.com/pkg/errors" + + "github.com/palantir/godel/framework/godellauncher" + v1 "github.com/palantir/godel/framework/pluginapi" +) + +const ( + CurrentSchemaVersion = "2" + PluginInfoCommandName = v1.PluginInfoCommandName +) + +// PluginInfo specifies the information for a plugin and the tasks that it provides. +type PluginInfo interface { + // PluginSchemaVersion returns the schema version for the plugin. + PluginSchemaVersion() string + + // The Group, Product and Version functions return the "group", "product" and "version" components of the plugin. + // When colon-delimited, they form a Maven identifier. All must be non-empty. + + // Group returns the group of the plugin. + Group() string + // Product returns the product name of the plugin. Must have the suffix "-plugin". + Product() string + // Version returns the version of hte plugin. + Version() string + + // UsesConfig returns true if this plugin uses configuration, false otherwise. + UsesConfig() bool + + // Tasks returns the tasks provided by the plugin. Requires the path to the plugin executable and assets as input. + Tasks(pluginExecPath string, assets []string) []godellauncher.Task + + // UpgradeConfigTask returns the task that upgrades the configuration for this plugin. Returns nil if the plugin + // does not support upgrading configuration. + UpgradeConfigTask(pluginExecPath string, assets []string) *godellauncher.UpgradeConfigTask + + // private function on interface to keep implementation private to package. + private() +} + +// MustNewPluginInfo returns the result of calling NewInfo with the provided parameters. Panics if the call to +// NewPluginInfo returns an error, so this function should only be used when the inputs are static and known to be valid. +func MustNewPluginInfo(group, product, version string, params ...PluginInfoParam) PluginInfo { + cmd, err := NewPluginInfo(group, product, version, params...) + if err != nil { + panic(errors.Wrapf(err, "failed to create plugin info")) + } + return cmd +} + +// NewPluginInfo creates a new PluginInfo for the plugin using the provided configuration. Returns an error if the +// provided configuration is not valid (can occur if multiple tasks have the same name or if a task is not valid). +func NewPluginInfo(group, product, version string, params ...PluginInfoParam) (PluginInfo, error) { + if err := validateComponent("group", group); err != nil { + return nil, err + } + if err := validateComponent("product", product); err != nil { + return nil, err + } + if !strings.HasSuffix(product, "-plugin") { + return nil, errors.Errorf(`product must end with "-plugin", was %q`, product) + } + if err := validateComponent("version", version); err != nil { + return nil, err + } + + id := fmt.Sprintf("%s:%s:%s", group, product, version) + + builder := pluginInfoBuilder{} + for _, param := range params { + if err := param.apply(&builder); err != nil { + return nil, err + } + } + + // set global flag options based on builder + for i := range builder.tasks { + builder.tasks[i].GlobalFlagOptionsVar = builder.globalFlagOpts + } + if builder.upgradeConfigTask != nil { + builder.upgradeConfigTask.GroupID = group + builder.upgradeConfigTask.ProductID = product + builder.upgradeConfigTask.GlobalFlagOptionsVar = builder.globalFlagOpts + } + + taskNameMap := make(map[string]struct{}) + for _, task := range builder.tasks { + if _, ok := taskNameMap[task.Name()]; ok { + return nil, errors.Errorf(`plugin %s specifies multiple tasks with name "%s"`, id, task.Name()) + } + taskNameMap[task.Name()] = struct{}{} + } + + if builder.upgradeConfigTask != nil && !builder.usesConfigFile { + return nil, errors.Errorf(`plugin %s provides a configuration upgrade task but does not specify that it uses configuration`, id) + } + + return pluginInfoImpl{ + PluginSchemaVersionVar: CurrentSchemaVersion, + GroupVar: group, + ProductVar: product, + VersionVar: version, + UsesConfigVar: builder.usesConfigFile, + TasksVar: builder.tasks, + UpgradeConfigTaskVar: builder.upgradeConfigTask, + }, nil +} + +func validateComponent(name, val string) error { + if val == "" { + return errors.Errorf("%s must be non-empty", name) + } + if strings.Contains(val, ":") { + return errors.Errorf("%s cannot contain a ':', was %q", name, val) + } + return nil +} + +type pluginInfoBuilder struct { + usesConfigFile bool + tasks []taskInfoImpl + globalFlagOpts *globalFlagOptionsImpl + upgradeConfigTask *upgradeConfigTaskInfoImpl +} + +type PluginInfoParam interface { + apply(*pluginInfoBuilder) error +} + +type pluginInfoParamFunc func(*pluginInfoBuilder) error + +func (f pluginInfoParamFunc) apply(impl *pluginInfoBuilder) error { + return f(impl) +} + +func PluginInfoUsesConfigFile() PluginInfoParam { + return pluginInfoParamFunc(func(impl *pluginInfoBuilder) error { + impl.usesConfigFile = true + return nil + }) +} + +func PluginInfoTaskInfo(name, description string, params ...TaskInfoParam) PluginInfoParam { + return pluginInfoParamFunc(func(impl *pluginInfoBuilder) error { + taskInfoImpl, err := newTaskInfoImpl(name, description, params...) + if err != nil { + return err + } + impl.tasks = append(impl.tasks, taskInfoImpl) + return nil + }) +} + +func PluginInfoGlobalFlagOptions(params ...GlobalFlagOptionsParam) PluginInfoParam { + return pluginInfoParamFunc(func(impl *pluginInfoBuilder) error { + if len(params) == 0 { + return errors.Errorf("at least one param must be provided for global flag options configuration") + } + impl.globalFlagOpts = newGlobalFlagOptionsImpl(params...) + return nil + }) +} + +func PluginInfoUpgradeConfigTaskInfo(params ...UpgradeConfigTaskInfoParam) PluginInfoParam { + return pluginInfoParamFunc(func(impl *pluginInfoBuilder) error { + if len(params) == 0 { + return errors.Errorf("at least one param must be provided for upgrade configuration") + } + impl.upgradeConfigTask = newUpgradeConfigTaskInfoImpl(params...) + return nil + }) +} + +// pluginInfoImpl is a concrete implementation of Info. Note that the functions are defined on non-pointer receivers to reduce +// bugs in calling functions in closures. +type pluginInfoImpl struct { + PluginSchemaVersionVar string `json:"pluginSchemaVersion"` + // The Maven group identifier for the plugin. Must be non-empty. + GroupVar string `json:"group"` + // The Maven product identifier for the plugin. Must be non-empty and must have "-plugin" as its suffix. + ProductVar string `json:"product"` + // The Maven version identifier for the plugin. Must be non-empty. + VersionVar string `json:"version"` + // True if this plugin uses configuration, false otherwise. + UsesConfigVar bool `json:"usesConfig"` + // The tasks provided by the plugin. + TasksVar []taskInfoImpl `json:"tasks"` + // The configuration upgrade task provided by the plugin. + UpgradeConfigTaskVar *upgradeConfigTaskInfoImpl `json:"upgradeTask"` +} + +func (infoImpl pluginInfoImpl) PluginSchemaVersion() string { + return infoImpl.PluginSchemaVersionVar +} + +func (infoImpl pluginInfoImpl) Group() string { + return infoImpl.GroupVar +} + +func (infoImpl pluginInfoImpl) Product() string { + return infoImpl.ProductVar +} + +func (infoImpl pluginInfoImpl) Version() string { + return infoImpl.VersionVar +} + +func (infoImpl pluginInfoImpl) UsesConfig() bool { + return infoImpl.UsesConfigVar +} + +func (infoImpl pluginInfoImpl) configFileName() string { + var configFileName string + if infoImpl.UsesConfigVar { + configFileName = infoImpl.ProductVar + ".yml" + } + return configFileName +} + +func (infoImpl pluginInfoImpl) Tasks(pluginExecPath string, assets []string) []godellauncher.Task { + var tasks []godellauncher.Task + for _, ti := range infoImpl.TasksVar { + tasks = append(tasks, ti.toTask(pluginExecPath, infoImpl.configFileName(), assets)) + } + return tasks +} + +func (infoImpl pluginInfoImpl) UpgradeConfigTask(pluginExecPath string, assets []string) *godellauncher.UpgradeConfigTask { + if infoImpl.UpgradeConfigTaskVar == nil { + return nil + } + taskVar := infoImpl.UpgradeConfigTaskVar.toTask(pluginExecPath, infoImpl.configFileName(), assets) + return &taskVar +} + +func (infoImpl pluginInfoImpl) private() {} + +// InfoFromPlugin returns the Info for the plugin at the specified path. Does so by invoking the InfoCommand on the +// plugin and parsing the output. +func InfoFromPlugin(pluginPath string) (PluginInfo, error) { + cmd := exec.Command(pluginPath, PluginInfoCommandName) + bytes, err := cmd.CombinedOutput() + if err != nil { + return nil, errors.Wrapf(err, "command %v failed.\nError:\n%v\nOutput:\n%s\n", cmd.Args, err, string(bytes)) + } + + var schemaVersionVar v1.SchemaVersion + if err := json.Unmarshal(bytes, &schemaVersionVar); err != nil { + return nil, errors.Wrapf(err, "failed to unmarshal plugin schema version for plugin %s from output %q", pluginPath, string(bytes)) + } + + var pluginInfo PluginInfo + switch version := schemaVersionVar.PluginSchemaVersionVar; version { + case v1.CurrentSchemaVersion: + v1Info, err := v1.InfoFromBytes(bytes) + if err != nil { + return nil, errors.Wrapf(err, "failed to unmarshal v1 plugin information") + } + + // do baseline check/validation + parts := strings.Split(v1Info.ID(), ":") + if len(parts) != 3 { + return nil, errors.Wrapf(err, "v1 plugin information provided invalid ID: %q", v1Info.ID()) + } + if _, err := NewPluginInfo(parts[0], parts[1], parts[2]); err != nil { + return nil, errors.Wrapf(err, "could not create v2 plugin info from v1 plugin info") + } + pluginInfo = wrappedV1PluginInfoImpl{ + v1PluginInfo: v1Info, + } + case CurrentSchemaVersion: + var v2Info pluginInfoImpl + if err := json.Unmarshal(bytes, &v2Info); err != nil { + return nil, errors.Wrapf(err, "failed to unmarshal plugin information for plugin %s from output %q", pluginPath, string(bytes)) + } + pluginInfo = v2Info + default: + return nil, errors.Errorf("unsupported plugin schema version: %s", version) + } + + if !strings.HasSuffix(pluginInfo.Product(), "-plugin") { + return nil, errors.Errorf(`plugin %s has an invalid product name: product names must have suffix "-plugin", but was %q`, pluginPath, pluginInfo.Product()) + } + return pluginInfo, nil +} + +type wrappedV1PluginInfoImpl struct { + v1PluginInfo v1.PluginInfo +} + +func (infoImpl wrappedV1PluginInfoImpl) PluginSchemaVersion() string { + return CurrentSchemaVersion +} + +func (infoImpl wrappedV1PluginInfoImpl) Group() string { + return strings.Split(infoImpl.v1PluginInfo.ID(), ":")[0] +} + +func (infoImpl wrappedV1PluginInfoImpl) Product() string { + return strings.Split(infoImpl.v1PluginInfo.ID(), ":")[1] +} + +func (infoImpl wrappedV1PluginInfoImpl) Version() string { + return strings.Split(infoImpl.v1PluginInfo.ID(), ":")[2] +} + +func (infoImpl wrappedV1PluginInfoImpl) UsesConfig() bool { + return infoImpl.v1PluginInfo.ConfigFileName() != "" +} + +func (infoImpl wrappedV1PluginInfoImpl) Tasks(pluginExecPath string, assets []string) []godellauncher.Task { + return infoImpl.v1PluginInfo.Tasks(pluginExecPath, assets) +} + +func (infoImpl wrappedV1PluginInfoImpl) UpgradeConfigTask(pluginExecPath string, assets []string) *godellauncher.UpgradeConfigTask { + return nil +} + +func (infoImpl wrappedV1PluginInfoImpl) private() {} diff --git a/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/taskinfo.go b/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/taskinfo.go new file mode 100644 index 00000000..1a4312c3 --- /dev/null +++ b/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/taskinfo.go @@ -0,0 +1,213 @@ +// Copyright 2016 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pluginapi + +import ( + "fmt" + "io" + "os" + "os/exec" + "path" + "strings" + "unicode" + + "github.com/pkg/errors" + + "github.com/palantir/godel/framework/godellauncher" +) + +// TaskInfo is a JSON-serializable interface that can be translated into a godellauncher.Task. Refer to that struct for +// field documentation. +type TaskInfo interface { + Name() string + Description() string + Command() []string + GlobalFlagOptions() GlobalFlagOptions + VerifyOptions() VerifyOptions + + toTask(pluginExecPath, cfgFileName string, assets []string) godellauncher.Task +} + +// taskInfoImpl is a concrete implementation of TaskInfo. Note that the functions are defined on non-pointer receivers +// to reduce bugs in calling functions in closures. +type taskInfoImpl struct { + NameVar string `json:"name"` + DescriptionVar string `json:"description"` + CommandVar []string `json:"command"` + GlobalFlagOptionsVar *globalFlagOptionsImpl `json:"globalFlagOptions"` + VerifyOptionsVar *verifyOptionsImpl `json:"verifyOptions"` +} + +type TaskInfoParam interface { + apply(*taskInfoImpl) +} + +type taskInfoParamFunc func(*taskInfoImpl) + +func (f taskInfoParamFunc) apply(impl *taskInfoImpl) { + f(impl) +} + +func TaskInfoCommand(command ...string) TaskInfoParam { + return taskInfoParamFunc(func(impl *taskInfoImpl) { + impl.CommandVar = command + }) +} + +func TaskInfoVerifyOptions(params ...VerifyOptionsParam) TaskInfoParam { + return taskInfoParamFunc(func(impl *taskInfoImpl) { + verifyOpts := newVerifyOptionsImpl(params...) + var verifyImpls []verifyFlagImpl + for _, v := range verifyOpts.VerifyTaskFlags() { + verifyImpls = append(verifyImpls, verifyFlagImpl{ + NameVar: v.Name(), + DescriptionVar: v.Description(), + TypeVar: v.Type(), + }) + } + impl.VerifyOptionsVar = &verifyOptionsImpl{ + VerifyTaskFlagsVar: verifyImpls, + OrderingVar: verifyOpts.Ordering(), + ApplyTrueArgsVar: verifyOpts.ApplyTrueArgs(), + ApplyFalseArgsVar: verifyOpts.ApplyFalseArgs(), + } + }) +} + +func newTaskInfoImpl(name, description string, params ...TaskInfoParam) (taskInfoImpl, error) { + for _, r := range name { + if unicode.IsSpace(r) { + return taskInfoImpl{}, errors.Errorf("task name cannot contain whitespace: %q", name) + } + } + impl := taskInfoImpl{ + NameVar: name, + DescriptionVar: description, + } + for _, p := range params { + if p == nil { + continue + } + p.apply(&impl) + } + return impl, nil +} + +func (ti taskInfoImpl) Name() string { + return ti.NameVar +} + +func (ti taskInfoImpl) Description() string { + return ti.DescriptionVar +} + +func (ti taskInfoImpl) Command() []string { + return ti.CommandVar +} + +func (ti taskInfoImpl) VerifyOptions() VerifyOptions { + if ti.VerifyOptionsVar == nil { + return nil + } + return ti.VerifyOptionsVar +} + +func (ti taskInfoImpl) GlobalFlagOptions() GlobalFlagOptions { + if ti.GlobalFlagOptionsVar == nil { + return nil + } + return ti.GlobalFlagOptionsVar +} + +func (ti taskInfoImpl) toTask(pluginExecPath, cfgFileName string, assets []string) godellauncher.Task { + var verifyOpts *godellauncher.VerifyOptions + if ti.VerifyOptions() != nil { + opts := ti.VerifyOptionsVar.toGodelVerifyOptions() + verifyOpts = &opts + } + var globalFlagOpts godellauncher.GlobalFlagOptions + if ti.GlobalFlagOptionsVar != nil { + globalFlagOpts = ti.GlobalFlagOptionsVar.toGodelGlobalFlagOptions() + } + return godellauncher.Task{ + Name: ti.NameVar, + Description: ti.DescriptionVar, + ConfigFile: cfgFileName, + Verify: verifyOpts, + GlobalFlagOpts: globalFlagOpts, + RunImpl: func(t *godellauncher.Task, global godellauncher.GlobalConfig, stdout io.Writer) error { + cmdArgs, err := globalFlagArgs(t.GlobalFlagOpts, t.ConfigFile, global) + if err != nil { + return err + } + // if assets are specified, provide as slice argument + if len(assets) > 0 { + cmdArgs = append(cmdArgs, "--"+AssetsFlagName) + cmdArgs = append(cmdArgs, strings.Join(assets, ",")) + } + cmdArgs = append(cmdArgs, ti.CommandVar...) + cmdArgs = append(cmdArgs, global.TaskArgs...) + cmd := exec.Command(pluginExecPath, cmdArgs...) + cmd.Stdout = stdout + cmd.Stderr = stdout + cmd.Stdin = os.Stdin + if err := cmd.Run(); err != nil { + if _, ok := err.(*exec.ExitError); ok { + // create empty error because command will likely print its own error + return fmt.Errorf("") + } + return errors.Wrapf(err, "plugin execution failed") + } + return nil + }, + } +} + +func globalFlagArgs(globalFlagOpts godellauncher.GlobalFlagOptions, configFileName string, global godellauncher.GlobalConfig) ([]string, error) { + var args []string + if global.Debug && globalFlagOpts.DebugFlag != "" { + args = append(args, globalFlagOpts.DebugFlag) + } + + // the rest of the arguments depend on "--wrapper" being specified in the global configuration + if global.Wrapper == "" { + return args, nil + } + + projectDir := path.Dir(global.Wrapper) + if globalFlagOpts.ProjectDirFlag != "" { + args = append(args, globalFlagOpts.ProjectDirFlag, projectDir) + } + + // if config dir flags were not specified, nothing more to do + if globalFlagOpts.GodelConfigFlag == "" && (globalFlagOpts.ConfigFlag == "" || configFileName == "") { + return args, nil + } + + cfgDir, err := godellauncher.ConfigDirPath(projectDir) + if err != nil { + return nil, errors.Wrapf(err, "failed to determine config directory path") + } + + if globalFlagOpts.GodelConfigFlag != "" { + args = append(args, globalFlagOpts.GodelConfigFlag, path.Join(cfgDir, godellauncher.GodelConfigYML)) + } + + if globalFlagOpts.ConfigFlag != "" && configFileName != "" { + args = append(args, globalFlagOpts.ConfigFlag, path.Join(cfgDir, configFileName)) + } + + return args, nil +} diff --git a/vendor/github.com/palantir/godel/framework/pluginapi/upgradeconfigtaskinfo.go b/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/upgradeconfigtaskinfo.go similarity index 83% rename from vendor/github.com/palantir/godel/framework/pluginapi/upgradeconfigtaskinfo.go rename to vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/upgradeconfigtaskinfo.go index 0aefb46c..bcacc67a 100644 --- a/vendor/github.com/palantir/godel/framework/pluginapi/upgradeconfigtaskinfo.go +++ b/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/upgradeconfigtaskinfo.go @@ -32,6 +32,9 @@ import ( type UpgradeConfigTaskInfo interface { Command() []string GlobalFlagOptions() GlobalFlagOptions + // LegacyConfigFile returns the name of the legacy configuration file (the name of the configuration file used in + // version 1 of gödel). Blank if this plugin does not have a legacy file or does not support upgrading legacy files. + LegacyConfigFile() string toTask(pluginExecPath, cfgFileName string, assets []string) godellauncher.UpgradeConfigTask } @@ -51,13 +54,22 @@ func UpgradeConfigTaskInfoCommand(command ...string) UpgradeConfigTaskInfoParam }) } +func LegacyConfigFile(legacyConfigFile string) UpgradeConfigTaskInfoParam { + return upgradeConfigTaskInfoParamFunc(func(impl *upgradeConfigTaskInfoImpl) { + impl.LegacyConfigFile = legacyConfigFile + }) +} + // upgradeConfigTaskInfoImpl is a concrete implementation of UpgradeConfigTaskInfo. Note that the functions are defined // on non-pointer receivers to reduce bugs in calling functions in closures. type upgradeConfigTaskInfoImpl struct { - // PluginID is the identifier for the plugin of the form "groupID:productID" ("com.palantir.format-plugin:format-plugin") - PluginID string `json:"pluginId"` + // GroupID is the group ID of the plugin. + GroupID string `json:"groupId"` + // ProductID is the product ID of the plugin. + ProductID string `json:"productId"` // CommandVar stores the commands to invoke to run the "upgrade-config" task CommandVar []string `json:"command"` + LegacyConfigFile string `json:"legacyConfigFile"` GlobalFlagOptionsVar *globalFlagOptionsImpl `json:"globalFlagOptions"` } @@ -92,9 +104,10 @@ func (ti upgradeConfigTaskInfoImpl) toTask(pluginExecPath, cfgFileName string, a globalFlagOpts = ti.GlobalFlagOptionsVar.toGodelGlobalFlagOptions() } return godellauncher.UpgradeConfigTask{ - ID: ti.PluginID, - ConfigFile: cfgFileName, - GlobalFlagOpts: globalFlagOpts, + ID: ti.GroupID + ":" + ti.ProductID, + ConfigFile: cfgFileName, + LegacyConfigFile: ti.LegacyConfigFile, + GlobalFlagOpts: globalFlagOpts, RunImpl: func(t *godellauncher.UpgradeConfigTask, global godellauncher.GlobalConfig, configBytes []byte, stdout io.Writer) ([]byte, error) { cmdArgs, err := globalFlagArgs(t.GlobalFlagOpts, t.ConfigFile, global) if err != nil { diff --git a/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/verifyopts.go b/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/verifyopts.go new file mode 100644 index 00000000..50748ac1 --- /dev/null +++ b/vendor/github.com/palantir/godel/framework/pluginapi/v2/pluginapi/verifyopts.go @@ -0,0 +1,175 @@ +// Copyright 2016 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pluginapi + +import ( + "github.com/palantir/godel/framework/godellauncher" + "github.com/palantir/godel/framework/verifyorder" +) + +// VerifyOptions is a JSON-serializable interface that can be translated into a godellauncher.VerifyOptions. Refer to +// that struct for field documentation. +type VerifyOptions interface { + VerifyTaskFlags() []VerifyFlag + Ordering() *int + ApplyTrueArgs() []string + ApplyFalseArgs() []string + + toGodelVerifyOptions() godellauncher.VerifyOptions +} + +// verifyOptionsImpl is a concrete implementation of VerifyOptions. Note that the functions are defined on non-pointer +// receivers to reduce bugs in calling functions in closures. +type verifyOptionsImpl struct { + VerifyTaskFlagsVar []verifyFlagImpl `json:"verifyTaskFlags"` + OrderingVar *int `json:"ordering"` + ApplyTrueArgsVar []string `json:"applyTrueArgs"` + ApplyFalseArgsVar []string `json:"applyFalseArgs"` +} + +type VerifyOptionsParam interface { + apply(*verifyOptionsImpl) +} + +type verifyOptsFunc func(*verifyOptionsImpl) + +func (f verifyOptsFunc) apply(impl *verifyOptionsImpl) { + f(impl) +} + +func VerifyOptionsTaskFlags(flags ...VerifyFlag) VerifyOptionsParam { + return verifyOptsFunc(func(impl *verifyOptionsImpl) { + for _, f := range flags { + impl.VerifyTaskFlagsVar = append(impl.VerifyTaskFlagsVar, verifyFlagImpl{ + NameVar: f.Name(), + DescriptionVar: f.Description(), + TypeVar: f.Type(), + }) + } + }) +} + +func VerifyOptionsOrdering(ordering *int) VerifyOptionsParam { + return verifyOptsFunc(func(impl *verifyOptionsImpl) { + impl.OrderingVar = ordering + }) +} + +func VerifyOptionsApplyTrueArgs(args ...string) VerifyOptionsParam { + return verifyOptsFunc(func(impl *verifyOptionsImpl) { + impl.ApplyTrueArgsVar = args + }) +} + +func VerifyOptionsApplyFalseArgs(args ...string) VerifyOptionsParam { + return verifyOptsFunc(func(impl *verifyOptionsImpl) { + impl.ApplyFalseArgsVar = args + }) +} + +func newVerifyOptionsImpl(params ...VerifyOptionsParam) verifyOptionsImpl { + vOpts := verifyOptionsImpl{} + for _, p := range params { + if p == nil { + continue + } + p.apply(&vOpts) + } + return vOpts +} + +func (vo verifyOptionsImpl) VerifyTaskFlags() []VerifyFlag { + var flags []VerifyFlag + for _, flag := range vo.VerifyTaskFlagsVar { + flags = append(flags, flag) + } + return flags +} + +func (vo verifyOptionsImpl) Ordering() *int { + return vo.OrderingVar +} + +func (vo verifyOptionsImpl) ApplyTrueArgs() []string { + return vo.ApplyTrueArgsVar +} + +func (vo verifyOptionsImpl) ApplyFalseArgs() []string { + return vo.ApplyFalseArgsVar +} + +func (vo verifyOptionsImpl) toGodelVerifyOptions() godellauncher.VerifyOptions { + var flags []godellauncher.VerifyFlag + for _, f := range vo.VerifyTaskFlagsVar { + flags = append(flags, f.toGodelVerifyFlag()) + } + + ordering := verifyorder.Default + if vo.OrderingVar != nil { + ordering = *vo.OrderingVar + } + return godellauncher.VerifyOptions{ + VerifyTaskFlags: flags, + Ordering: ordering, + ApplyTrueArgs: vo.ApplyTrueArgsVar, + ApplyFalseArgs: vo.ApplyFalseArgsVar, + } +} + +// VerifyFlag is a JSON-serializable interface that can be translated into a godellauncher.VerifyFlag. Refer to that +// struct for field documentation. +type VerifyFlag interface { + Name() string + Description() string + Type() godellauncher.FlagType + + toGodelVerifyFlag() godellauncher.VerifyFlag +} + +// verifyFlagImpl is a concrete implementation of VerifyFlag. Note that the functions are defined on non-pointer +// receivers to reduce bugs in calling functions in closures. +type verifyFlagImpl struct { + NameVar string `json:"name"` + DescriptionVar string `json:"description"` + TypeVar godellauncher.FlagType `json:"type"` +} + +func NewVerifyFlag(name, description string, typ godellauncher.FlagType) VerifyFlag { + return verifyFlagImpl{ + NameVar: name, + DescriptionVar: description, + TypeVar: typ, + } +} + +func (vf verifyFlagImpl) Name() string { + return vf.NameVar +} + +func (vf verifyFlagImpl) Description() string { + return vf.DescriptionVar +} + +func (vf verifyFlagImpl) Type() godellauncher.FlagType { + return vf.TypeVar +} + +func (vf verifyFlagImpl) toGodelVerifyFlag() godellauncher.VerifyFlag { + return godellauncher.VerifyFlag{ + Name: vf.NameVar, + Description: vf.DescriptionVar, + Type: vf.TypeVar, + } +} diff --git a/vendor/github.com/palantir/godel/framework/pluginapi/verifyopts.go b/vendor/github.com/palantir/godel/framework/pluginapi/verifyopts.go index 6b1ca7ab..50748ac1 100644 --- a/vendor/github.com/palantir/godel/framework/pluginapi/verifyopts.go +++ b/vendor/github.com/palantir/godel/framework/pluginapi/verifyopts.go @@ -79,7 +79,7 @@ func VerifyOptionsApplyFalseArgs(args ...string) VerifyOptionsParam { }) } -func NewVerifyOptions(params ...VerifyOptionsParam) VerifyOptions { +func newVerifyOptionsImpl(params ...VerifyOptionsParam) verifyOptionsImpl { vOpts := verifyOptionsImpl{} for _, p := range params { if p == nil { diff --git a/vendor/github.com/palantir/godel/framework/pluginapitester/plugintester.go b/vendor/github.com/palantir/godel/framework/pluginapitester/plugintester.go index aea403eb..e540c9f2 100644 --- a/vendor/github.com/palantir/godel/framework/pluginapitester/plugintester.go +++ b/vendor/github.com/palantir/godel/framework/pluginapitester/plugintester.go @@ -27,7 +27,7 @@ import ( "github.com/pkg/errors" "github.com/palantir/godel/framework/godellauncher" - "github.com/palantir/godel/framework/pluginapi" + "github.com/palantir/godel/framework/pluginapi/v2/pluginapi" ) // RunPlugin runs a plugin with the specified arguments. The plugin is loaded in the same manner that it would be for diff --git a/vendor/github.com/palantir/godel/framework/pluginapitester/providers.go b/vendor/github.com/palantir/godel/framework/pluginapitester/providers.go index bb0586ae..57aab286 100644 --- a/vendor/github.com/palantir/godel/framework/pluginapitester/providers.go +++ b/vendor/github.com/palantir/godel/framework/pluginapitester/providers.go @@ -20,6 +20,7 @@ import ( "github.com/pkg/errors" "github.com/palantir/godel/framework/artifactresolver" + "github.com/palantir/godel/framework/godel/config" "github.com/palantir/godel/framework/godellauncher" "github.com/palantir/godel/framework/internal/pathsinternal" "github.com/palantir/godel/framework/plugins" @@ -44,10 +45,10 @@ func NewPluginProvider(pluginPath string) PluginProvider { } func NewPluginProviderFromLocator(pluginLocator, pluginResolver string) (PluginProvider, error) { - lwrConfig := artifactresolver.LocatorWithResolverConfig{ - Locator: artifactresolver.LocatorConfig{ + lwrConfig := config.LocatorWithResolverConfig{ + Locator: config.ToLocatorConfig(config.LocatorConfig{ ID: pluginLocator, - }, + }), Resolver: pluginResolver, } lwrParam, err := lwrConfig.ToParam() diff --git a/vendor/github.com/palantir/godel/framework/pluginapitester/upgradeconfigtester.go b/vendor/github.com/palantir/godel/framework/pluginapitester/upgradeconfigtester.go index ffd8fa10..c1cbed87 100644 --- a/vendor/github.com/palantir/godel/framework/pluginapitester/upgradeconfigtester.go +++ b/vendor/github.com/palantir/godel/framework/pluginapitester/upgradeconfigtester.go @@ -34,7 +34,7 @@ import ( "github.com/palantir/godel/framework/builtintasks" "github.com/palantir/godel/framework/godellauncher" - "github.com/palantir/godel/framework/pluginapi" + "github.com/palantir/godel/framework/pluginapi/v2/pluginapi" ) // RunUpgradeConfig runs the "upgrade-config" task with the provided plugin and assets loaded. The plugin is loaded in diff --git a/vendor/github.com/palantir/godel/framework/plugins/configprovider.go b/vendor/github.com/palantir/godel/framework/plugins/configprovider.go index 33dea2b4..6631c822 100644 --- a/vendor/github.com/palantir/godel/framework/plugins/configprovider.go +++ b/vendor/github.com/palantir/godel/framework/plugins/configprovider.go @@ -28,6 +28,7 @@ import ( "github.com/palantir/godel/framework/artifactresolver" "github.com/palantir/godel/framework/builtintasks/installupdate/layout" + "github.com/palantir/godel/framework/godel/config" "github.com/palantir/godel/framework/godellauncher" "github.com/palantir/godel/framework/internal/pathsinternal" "github.com/palantir/godel/pkg/osarch" @@ -41,7 +42,7 @@ import ( // * Unmarshals all of the resolved configurations into godellauncher.TasksConfig structs. // // Returns all of the unmarshaled configurations. -func LoadProvidedConfigurations(taskConfigProvidersParam godellauncher.TasksConfigProvidersParam, stdout io.Writer) ([]godellauncher.TasksConfig, error) { +func LoadProvidedConfigurations(taskConfigProvidersParam godellauncher.TasksConfigProvidersParam, stdout io.Writer) ([]config.TasksConfig, error) { gödelHomeSpecDir, err := layout.GodelHomeSpecDir(specdir.Create) if err != nil { return nil, errors.Wrapf(err, "failed to create gödel home directory") @@ -67,8 +68,8 @@ func LoadProvidedConfigurations(taskConfigProvidersParam godellauncher.TasksConf // matches the specified checksum // * Unmarshal the downloaded YML as godellauncher.TasksConfig // * If the unmarshal fails, return an error -func resolveConfigProviders(configsDir, downloadsDir string, taskConfigProvidersParam godellauncher.TasksConfigProvidersParam, stdout io.Writer) ([]godellauncher.TasksConfig, error) { - var configs []godellauncher.TasksConfig +func resolveConfigProviders(configsDir, downloadsDir string, taskConfigProvidersParam godellauncher.TasksConfigProvidersParam, stdout io.Writer) ([]config.TasksConfig, error) { + var configs []config.TasksConfig providerErrors := make(map[artifactresolver.Locator]error) for _, currProvider := range taskConfigProvidersParam.ConfigProviders { currProviderLocator, ok := resolveAndVerifyConfigProvider( @@ -164,17 +165,17 @@ func resolveAndVerifyConfigProvider( return currLocator, true } -func readConfigFromProvider(locator artifactresolver.Locator, configsDir string) (godellauncher.TasksConfig, error) { +func readConfigFromProvider(locator artifactresolver.Locator, configsDir string) (config.TasksConfig, error) { cfgPath := path.Join(configsDir, pathsinternal.ConfigProviderFileName(locator)) cfgBytes, err := ioutil.ReadFile(cfgPath) if err != nil { - return godellauncher.TasksConfig{}, errors.Wrapf(err, "failed to read %s", cfgPath) + return config.TasksConfig{}, errors.Wrapf(err, "failed to read %s", cfgPath) } - var tasksCfg godellauncher.TasksConfig + var tasksCfg config.TasksConfig if err := yaml.Unmarshal(cfgBytes, &tasksCfg); err != nil { - return godellauncher.TasksConfig{}, errors.Wrapf(err, "failed to unmarshal %q as godellauncher.GodelConfig", string(cfgBytes)) + return config.TasksConfig{}, errors.Wrapf(err, "failed to unmarshal %q as godellauncher.GodelConfig", string(cfgBytes)) } return tasksCfg, nil } diff --git a/vendor/github.com/palantir/godel/framework/plugins/plugin.go b/vendor/github.com/palantir/godel/framework/plugins/plugin.go index ad8679a1..c8cd12d6 100644 --- a/vendor/github.com/palantir/godel/framework/plugins/plugin.go +++ b/vendor/github.com/palantir/godel/framework/plugins/plugin.go @@ -27,7 +27,7 @@ import ( "github.com/palantir/godel/framework/artifactresolver" "github.com/palantir/godel/framework/godellauncher" "github.com/palantir/godel/framework/internal/pathsinternal" - "github.com/palantir/godel/framework/pluginapi" + "github.com/palantir/godel/framework/pluginapi/v2/pluginapi" "github.com/palantir/godel/pkg/osarch" ) @@ -320,9 +320,7 @@ func verifySinglePluginCompatibility(plugin artifactresolver.Locator, plugins ma if plugin.Product == otherPlugin.Product { // if product names are the same, verify that they do not both use configuration (if they do, the // configuration files will conflict) - currPluginUsesConfig := plugins[plugin].PluginInfo.ConfigFileName() != "" - otherPluginUsesConfig := otherPluginInfo.PluginInfo.ConfigFileName() != "" - if currPluginUsesConfig && otherPluginUsesConfig { + if plugins[plugin].PluginInfo.UsesConfig() && otherPluginInfo.PluginInfo.UsesConfig() { errs[otherPlugin] = fmt.Errorf("plugins have the same product name and both use configuration (this not currently supported -- if this situation is encountered, please file an issue to flag it)") continue } diff --git a/vendor/github.com/palantir/godel/framework/plugins/plugin_test.go b/vendor/github.com/palantir/godel/framework/plugins/plugin_test.go index cabb51e0..71cbeeeb 100644 --- a/vendor/github.com/palantir/godel/framework/plugins/plugin_test.go +++ b/vendor/github.com/palantir/godel/framework/plugins/plugin_test.go @@ -33,16 +33,33 @@ import ( "github.com/palantir/godel/framework/artifactresolver" "github.com/palantir/godel/framework/godellauncher" "github.com/palantir/godel/framework/internal/pathsinternal" - "github.com/palantir/godel/framework/pluginapi" + "github.com/palantir/godel/framework/pluginapi/v2/pluginapi" "github.com/palantir/godel/pkg/osarch" ) var pluginScriptTmpl = fmt.Sprintf(`#!/usr/bin/env bash if [ "$1" = "%s" ]; then - echo '{"pluginSchemaVersion":"1","id":"com.palantir:%s:1.0.0","configFileName":"%s.yml","tasks":[{"name":"fooTest","description":"","command":["foo"],"globalFlagOptions":null,"verifyOptions":null}],"upgradeTask":null}' + echo '{"pluginSchemaVersion":"2","group":"com.palantir","product":"%s","version":"1.0.0","usesConfig":true,"tasks":[{"name":"fooTest","description":"","command":["foo"],"globalFlagOptions":null,"verifyOptions":null}],"upgradeTask":null}' fi -`, pluginapi.PluginInfoCommandName, "%s", "%s") +`, pluginapi.PluginInfoCommandName, "%s") + +// If the plugin JSON schema changes, uncomment the following and run it to generate the "echo" line in the pluginScriptTmpl above. + +//func TestPrintPluginInfoJSON(t *testing.T) { +// pluginInfo, err := pluginapi.NewPluginInfo("com.palantir", "placeholder-plugin", "1.0.0", +// pluginapi.PluginInfoUsesConfigFile(), +// pluginapi.PluginInfoTaskInfo( +// "fooTest", +// "", +// pluginapi.TaskInfoCommand("foo"), +// ), +// ) +// require.NoError(t, err) +// bytes, err := json.Marshal(pluginInfo) +// require.NoError(t, err) +// fmt.Println(`echo '` + strings.Replace(string(bytes), "placeholder-plugin", `%s`, 1) + `'`) +//} func TestInfoFromResolved(t *testing.T) { tmpDir, cleanup, err := dirs.TempDir("", "") @@ -51,7 +68,7 @@ func TestInfoFromResolved(t *testing.T) { pluginName := newPluginName() pluginFile := path.Join(tmpDir, fmt.Sprintf("com.palantir-%s-1.0.0", pluginName)) - err = ioutil.WriteFile(pluginFile, []byte(fmt.Sprintf(pluginScriptTmpl, pluginName, pluginName)), 0755) + err = ioutil.WriteFile(pluginFile, []byte(fmt.Sprintf(pluginScriptTmpl, pluginName)), 0755) require.NoError(t, err) gotInfo, err := pluginapi.InfoFromPlugin(path.Join(tmpDir, pathsinternal.PluginFileName(artifactresolver.Locator{ @@ -148,7 +165,7 @@ func createTestPlugin(t *testing.T, tmpDir string) (artifactresolver.Locator, ar require.NoError(t, err) testProductPath := path.Join(testProductDir, pluginName) - err = ioutil.WriteFile(testProductPath, []byte(fmt.Sprintf(pluginScriptTmpl, pluginName, pluginName)), 0755) + err = ioutil.WriteFile(testProductPath, []byte(fmt.Sprintf(pluginScriptTmpl, pluginName)), 0755) require.NoError(t, err) testProductTGZPath := path.Join(testProductDir, pluginName+"-darwin-amd64-1.0.0.tgz") @@ -182,10 +199,10 @@ func TestVerifyPluginCompatibility(t *testing.T) { map[artifactresolver.Locator]pluginInfoWithAssets{ { Group: "com.palantir", - Product: "foo", + Product: "foo-plugin", Version: "1.0.0", }: { - PluginInfo: pluginapi.MustNewPluginInfo("com.palantir", "foo", "1.0.0", + PluginInfo: pluginapi.MustNewPluginInfo("com.palantir", "foo-plugin", "1.0.0", pluginapi.PluginInfoUsesConfigFile(), ), }, @@ -197,29 +214,29 @@ func TestVerifyPluginCompatibility(t *testing.T) { map[artifactresolver.Locator]pluginInfoWithAssets{ { Group: "com.palantir", - Product: "foo", + Product: "foo-plugin", Version: "1.0.0", }: { - PluginInfo: pluginapi.MustNewPluginInfo("com.palantir", "foo", "1.0.0", + PluginInfo: pluginapi.MustNewPluginInfo("com.palantir", "foo-plugin", "1.0.0", pluginapi.PluginInfoUsesConfigFile(), pluginapi.PluginInfoTaskInfo("foo", ""), ), }, { Group: "com.palantir", - Product: "foo", + Product: "foo-plugin", Version: "2.0.0", }: { - PluginInfo: pluginapi.MustNewPluginInfo("com.palantir", "foo", "1.0.0", + PluginInfo: pluginapi.MustNewPluginInfo("com.palantir", "foo-plugin", "1.0.0", pluginapi.PluginInfoUsesConfigFile(), pluginapi.PluginInfoTaskInfo("foo", ""), ), }, }, `2 plugins had compatibility issues: - com.palantir:foo:1.0.0: + com.palantir:foo-plugin:1.0.0: different version of the same plugin - com.palantir:foo:2.0.0: + com.palantir:foo-plugin:2.0.0: different version of the same plugin`, }, { @@ -227,29 +244,29 @@ func TestVerifyPluginCompatibility(t *testing.T) { map[artifactresolver.Locator]pluginInfoWithAssets{ { Group: "com.palantir", - Product: "foo", + Product: "foo-plugin", Version: "1.0.0", }: { - PluginInfo: pluginapi.MustNewPluginInfo("com.palantir", "foo", "1.0.0", + PluginInfo: pluginapi.MustNewPluginInfo("com.palantir", "foo-plugin", "1.0.0", pluginapi.PluginInfoUsesConfigFile(), pluginapi.PluginInfoTaskInfo("foo", ""), ), }, { Group: "com.palantir", - Product: "bar", + Product: "bar-plugin", Version: "2.0.0", }: { - PluginInfo: pluginapi.MustNewPluginInfo("com.palantir", "bar", ".0.0", + PluginInfo: pluginapi.MustNewPluginInfo("com.palantir", "bar-plugin", ".0.0", pluginapi.PluginInfoUsesConfigFile(), pluginapi.PluginInfoTaskInfo("foo", ""), ), }, }, `2 plugins had compatibility issues: - com.palantir:bar:2.0.0: + com.palantir:bar-plugin:2.0.0: provides conflicting tasks: [foo] - com.palantir:foo:1.0.0: + com.palantir:foo-plugin:1.0.0: provides conflicting tasks: [foo]`, }, { @@ -257,29 +274,29 @@ func TestVerifyPluginCompatibility(t *testing.T) { map[artifactresolver.Locator]pluginInfoWithAssets{ { Group: "com.palantir", - Product: "foo", + Product: "foo-plugin", Version: "1.0.0", }: { - PluginInfo: pluginapi.MustNewPluginInfo("com.palantir", "foo", "1.0.0", + PluginInfo: pluginapi.MustNewPluginInfo("com.palantir", "foo-plugin", "1.0.0", pluginapi.PluginInfoUsesConfigFile(), pluginapi.PluginInfoTaskInfo("foo", ""), ), }, { Group: "com.zcorp", - Product: "foo", + Product: "foo-plugin", Version: "2.0.0", }: { - PluginInfo: pluginapi.MustNewPluginInfo("com.zcorp", "foo", "2.0.0", + PluginInfo: pluginapi.MustNewPluginInfo("com.zcorp", "foo-plugin", "2.0.0", pluginapi.PluginInfoUsesConfigFile(), pluginapi.PluginInfoTaskInfo("bar", ""), ), }, }, `2 plugins had compatibility issues: - com.palantir:foo:1.0.0: + com.palantir:foo-plugin:1.0.0: plugins have the same product name and both use configuration (this not currently supported -- if this situation is encountered, please file an issue to flag it) - com.zcorp:foo:2.0.0: + com.zcorp:foo-plugin:2.0.0: plugins have the same product name and both use configuration (this not currently supported -- if this situation is encountered, please file an issue to flag it)`, }, } { @@ -293,5 +310,5 @@ func TestVerifyPluginCompatibility(t *testing.T) { } func newPluginName() string { - return fmt.Sprintf("tester-%d", time.Now().Unix()) + return fmt.Sprintf("tester-%d-plugin", time.Now().Unix()) } diff --git a/vendor/github.com/palantir/godel/godel/config/check.yml b/vendor/github.com/palantir/godel/godel/config/check.yml index aa1fc55b..cc7e90b5 100644 --- a/vendor/github.com/palantir/godel/godel/config/check.yml +++ b/vendor/github.com/palantir/godel/godel/config/check.yml @@ -3,3 +3,5 @@ checks: filters: - value: "should have comment or be unexported" - value: "or a comment on this block" + # type actually provides configuration, so stutter is OK + - value: "type name will be used as config.ConfigProviderLocator" diff --git a/vendor/github.com/palantir/godel/godelinit/root.go b/vendor/github.com/palantir/godel/godelinit/root.go index 7e81b06e..0e09e743 100644 --- a/vendor/github.com/palantir/godel/godelinit/root.go +++ b/vendor/github.com/palantir/godel/godelinit/root.go @@ -15,9 +15,10 @@ package main import ( + "os" + "path" "time" - "github.com/nmiyake/pkg/dirs" "github.com/pkg/errors" "github.com/spf13/cobra" @@ -26,9 +27,10 @@ import ( func rootCmd() *cobra.Command { var ( - versionFlag string - checksumFlag string - cacheDurationFlag time.Duration + versionFlag string + checksumFlag string + cacheDurationFlag time.Duration + skipUpgradeConfigFlag bool ) cmd := &cobra.Command{ @@ -38,16 +40,59 @@ func rootCmd() *cobra.Command { The default behavior adds the newest release of godel on GitHub (/~https://github.com/palantir/godel/releases) to the project. If a specific version of godel is desired, it can be specified using the '--version' flag.`, RunE: func(cmd *cobra.Command, args []string) error { - wd, err := dirs.GetwdEvalSymLinks() + projectDir, err := os.Getwd() if err != nil { return errors.Wrapf(err, "failed to determine working directory") } - return installupdate.InstallVersion(wd, versionFlag, checksumFlag, cacheDurationFlag, true, cmd.OutOrStdout()) + + // if current directory does not contain "godelw" wrapper, don't bother trying to upgrade configuration + if _, err := os.Stat(path.Join(projectDir, "godelw")); err != nil { + skipUpgradeConfigFlag = true + } + + // determine version before install + var godelVersionBeforeUpdate installupdate.Version + if !skipUpgradeConfigFlag { + versionBeforeUpdateVar, err := installupdate.GodelVersion(projectDir) + if err != nil { + return errors.Wrapf(err, "failed to determine version before update") + } + godelVersionBeforeUpdate = versionBeforeUpdateVar + } + + // perform install + if err := installupdate.InstallVersion(projectDir, versionFlag, checksumFlag, cacheDurationFlag, true, cmd.OutOrStdout()); err != nil { + return err + } + + // run configuration upgrade if needed + if !skipUpgradeConfigFlag { + godelVersionAfterUpdate, err := installupdate.GodelVersion(projectDir) + if err != nil { + return errors.Wrapf(err, "failed to determine version after update") + } + + if godelVersionBeforeUpdate.MajorVersionNum() <= 1 && godelVersionAfterUpdate.MajorVersionNum() >= 2 { + // if going from <=1 to >=2, run "upgrade-config --legacy" task to upgrade configuration + if err := installupdate.RunUpgradeLegacyConfig(projectDir, cmd.OutOrStdout(), cmd.OutOrStderr()); err != nil { + return err + } + } else if godelVersionBeforeUpdate.MajorVersionNum() >= 2 { + // if previous version is >=2 and new version is >= previous version, run "upgrade-config" + if cmp, ok := godelVersionAfterUpdate.CompareTo(godelVersionBeforeUpdate); !ok || cmp >= 0 { + if err := installupdate.RunUpgradeConfig(projectDir, cmd.OutOrStdout(), cmd.OutOrStderr()); err != nil { + return err + } + } + } + } + return nil }, } cmd.Flags().StringVar(&versionFlag, "version", "", "version to install (if unspecified, latest is used)") cmd.Flags().StringVar(&checksumFlag, "checksum", "", "expected checksum for package") cmd.Flags().DurationVar(&cacheDurationFlag, "cache-duration", time.Hour, "duration for which cache entries should be considered valid") + cmd.Flags().BoolVar(&skipUpgradeConfigFlag, "skip-upgrade-config", false, "skips running configuration upgrade tasks after running update") return cmd } diff --git a/vendor/github.com/palantir/godel/integration_test/plugins_test.go b/vendor/github.com/palantir/godel/integration_test/plugins_test.go index bcfab184..c4608f45 100644 --- a/vendor/github.com/palantir/godel/integration_test/plugins_test.go +++ b/vendor/github.com/palantir/godel/integration_test/plugins_test.go @@ -32,8 +32,9 @@ import ( "gopkg.in/yaml.v2" "github.com/palantir/godel/framework/builtintasks/installupdate/layout" + "github.com/palantir/godel/framework/godel/config" "github.com/palantir/godel/framework/godellauncher" - "github.com/palantir/godel/framework/pluginapi" + "github.com/palantir/godel/framework/pluginapi/v2/pluginapi" "github.com/palantir/godel/pkg/osarch" ) @@ -47,7 +48,7 @@ echo $@ `, pluginapi.PluginInfoCommandName, `%s`) func TestPlugins(t *testing.T) { - pluginName := fmt.Sprintf("tester-integration-%d-%d", time.Now().Unix(), rand.Int()) + pluginName := fmt.Sprintf("tester-integration-%d-%d-plugin", time.Now().Unix(), rand.Int()) testProjectDir := setUpGödelTestAndDownload(t, testRootDir, gödelTGZ, version) src := `package main @@ -61,10 +62,7 @@ func main() { err := ioutil.WriteFile(path.Join(testProjectDir, "main.go"), []byte(src), 0644) require.NoError(t, err) - cfgDir, err := godellauncher.ConfigDirPath(testProjectDir) - require.NoError(t, err) - - cfg, err := godellauncher.ReadGodelConfig(cfgDir) + cfg, err := config.ReadGodelConfigFromProjectDir(testProjectDir) require.NoError(t, err) cfgContent := fmt.Sprintf(` @@ -94,9 +92,9 @@ plugins: "echo-task", "Echoes input", pluginapi.TaskInfoCommand("echo"), - pluginapi.TaskInfoVerifyOptions(pluginapi.NewVerifyOptions( + pluginapi.TaskInfoVerifyOptions( pluginapi.VerifyOptionsApplyFalseArgs("--verify"), - )), + ), ), ) pluginInfoJSON, err := json.Marshal(pluginInfo) @@ -112,6 +110,8 @@ plugins: cfgBytes, err := yaml.Marshal(cfg) require.NoError(t, err) + cfgDir, err := godellauncher.ConfigDirPath(testProjectDir) + require.NoError(t, err) err = ioutil.WriteFile(path.Join(cfgDir, godellauncher.GodelConfigYML), cfgBytes, 0644) require.NoError(t, err) @@ -140,7 +140,7 @@ Running echo-task... } func TestPluginsWithAssets(t *testing.T) { - pluginName := fmt.Sprintf("tester-integration-%d-%d", time.Now().Unix(), rand.Int()) + pluginName := fmt.Sprintf("tester-integration-%d-%d-plugin", time.Now().Unix(), rand.Int()) assetName := pluginName + "-asset" testProjectDir := setUpGödelTestAndDownload(t, testRootDir, gödelTGZ, version) @@ -155,10 +155,7 @@ func main() { err := ioutil.WriteFile(path.Join(testProjectDir, "main.go"), []byte(src), 0644) require.NoError(t, err) - cfgDir, err := godellauncher.ConfigDirPath(testProjectDir) - require.NoError(t, err) - - cfg, err := godellauncher.ReadGodelConfig(cfgDir) + cfg, err := config.ReadGodelConfigFromProjectDir(testProjectDir) require.NoError(t, err) cfgContent := fmt.Sprintf(` @@ -195,9 +192,9 @@ plugins: "echo-task", "Echoes input", pluginapi.TaskInfoCommand("echo"), - pluginapi.TaskInfoVerifyOptions(pluginapi.NewVerifyOptions( + pluginapi.TaskInfoVerifyOptions( pluginapi.VerifyOptionsApplyFalseArgs("--verify"), - )), + ), ), ) pluginInfoJSON, err := json.Marshal(pluginInfo) @@ -221,6 +218,8 @@ plugins: cfgBytes, err := yaml.Marshal(cfg) require.NoError(t, err) + cfgDir, err := godellauncher.ConfigDirPath(testProjectDir) + require.NoError(t, err) err = ioutil.WriteFile(path.Join(cfgDir, godellauncher.GodelConfigYML), cfgBytes, 0644) require.NoError(t, err) diff --git a/vendor/github.com/palantir/godel/main.go b/vendor/github.com/palantir/godel/main.go index 4bbb9dfb..d272bf23 100644 --- a/vendor/github.com/palantir/godel/main.go +++ b/vendor/github.com/palantir/godel/main.go @@ -26,7 +26,9 @@ import ( "github.com/palantir/godel/framework/builtintasks" "github.com/palantir/godel/framework/godel" + "github.com/palantir/godel/framework/godel/config" "github.com/palantir/godel/framework/godellauncher" + "github.com/palantir/godel/framework/godellauncher/defaulttasks" "github.com/palantir/godel/framework/plugins" ) @@ -41,8 +43,8 @@ func runGodelApp(osArgs []string) int { os.Args = osArgs global, err := godellauncher.ParseAppArgs(os.Args) - tasksCfgInfo := godellauncher.TasksConfigInfo{ - BuiltinPluginsConfig: godellauncher.BuiltinDefaultPluginsConfig(), + tasksCfgInfo := config.TasksConfigInfo{ + BuiltinPluginsConfig: defaulttasks.BuiltinPluginsConfig(), } if err != nil { // match invalid flag output with that provided by Cobra CLI @@ -52,12 +54,13 @@ func runGodelApp(osArgs []string) int { var allUpgradeConfigTasks []godellauncher.UpgradeConfigTask var defaultTasks, pluginTasks []godellauncher.Task if global.Wrapper != "" { - godelCfg, err := godellauncher.ReadGodelConfigFromProjectDir(path.Dir(global.Wrapper)) + godelCfg, err := config.ReadGodelConfigFromProjectDir(path.Dir(global.Wrapper)) if err != nil { printErrAndExit(err, global.Debug) } - configProvidersParam, err := godelCfg.TasksConfigProviders.ToParam() + taskCfgProviders := config.TasksConfigProvidersConfig(godelCfg.TasksConfigProviders) + configProvidersParam, err := taskCfgProviders.ToParam() if err != nil { printErrAndExit(err, global.Debug) } @@ -66,11 +69,15 @@ func runGodelApp(osArgs []string) int { printErrAndExit(err, global.Debug) } // combine base configuration with resolved configurations - godelCfg.TasksConfig.Combine(providedConfigs...) - tasksCfgInfo.TasksConfig = godelCfg.TasksConfig + tasksConfig := config.TasksConfig(godelCfg.TasksConfig) + tasksConfig.Combine(providedConfigs...) + tasksCfgInfo.TasksConfig = config.TasksConfig(godelCfg.TasksConfig) // add default tasks - defaultTasksCfg := godellauncher.DefaultTasksPluginsConfig(godelCfg.DefaultTasks) + defaultTasksCfg, err := defaulttasks.PluginsConfig(config.DefaultTasksConfig(godelCfg.DefaultTasks)) + if err != nil { + printErrAndExit(err, global.Debug) + } defaultTasksParam, err := defaultTasksCfg.ToParam() if err != nil { printErrAndExit(err, global.Debug) @@ -85,7 +92,8 @@ func runGodelApp(osArgs []string) int { } // add tasks provided by plugins - pluginsParam, err := godelCfg.Plugins.ToParam() + pluginsCfg := config.PluginsConfig(godelCfg.Plugins) + pluginsParam, err := pluginsCfg.ToParam() if err != nil { printErrAndExit(err, global.Debug) } @@ -96,7 +104,7 @@ func runGodelApp(osArgs []string) int { if len(defaultTasksCfg.Plugins) != 0 && len(godelCfg.Plugins.Plugins) != 0 { // verify that there are no conflicts - combinedCfg := godelCfg.Plugins + combinedCfg := config.PluginsConfig(godelCfg.Plugins) combinedCfg.DefaultResolvers = append(combinedCfg.DefaultResolvers, godelCfg.Plugins.DefaultResolvers...) combinedCfg.Plugins = append(combinedCfg.Plugins, godelCfg.Plugins.Plugins...) combinedParam, err := combinedCfg.ToParam() @@ -109,7 +117,7 @@ func runGodelApp(osArgs []string) int { } // add all upgrade tasks - allUpgradeConfigTasks = append(allUpgradeConfigTasks, godellauncher.BuiltinUpgradeConfigTasks()...) + allUpgradeConfigTasks = append(allUpgradeConfigTasks, defaulttasks.BuiltinUpgradeConfigTasks()...) allUpgradeConfigTasks = append(allUpgradeConfigTasks, defaultUpgradeConfigTasks...) allUpgradeConfigTasks = append(allUpgradeConfigTasks, pluginUpgradeConfigTasks...) } @@ -128,13 +136,12 @@ func runGodelApp(osArgs []string) int { return 0 } -func createTasks(defaultTasks, pluginTasks []godellauncher.Task, upgradeConfigTasks []godellauncher.UpgradeConfigTask, tasksCfgInfo godellauncher.TasksConfigInfo) []godellauncher.Task { +func createTasks(defaultTasks, pluginTasks []godellauncher.Task, upgradeConfigTasks []godellauncher.UpgradeConfigTask, tasksCfgInfo config.TasksConfigInfo) []godellauncher.Task { var allTasks []godellauncher.Task allTasks = append(allTasks, builtintasks.Tasks(tasksCfgInfo)...) allTasks = append(allTasks, defaultTasks...) allTasks = append(allTasks, builtintasks.VerifyTask(append(allTasks, pluginTasks...))) allTasks = append(allTasks, builtintasks.UpgradeConfigTask(upgradeConfigTasks)) - allTasks = append(allTasks, builtintasks.UpgradeLegacyConfigTask(upgradeConfigTasks)) allTasks = append(allTasks, pluginTasks...) return allTasks } diff --git a/vendor/github.com/palantir/godel/pkg/gocd_imports.json b/vendor/github.com/palantir/godel/pkg/gocd_imports.json index f916b6c7..b7c7d29d 100644 --- a/vendor/github.com/palantir/godel/pkg/gocd_imports.json +++ b/vendor/github.com/palantir/godel/pkg/gocd_imports.json @@ -29,7 +29,8 @@ "numGoFiles": 17, "numImportedGoFiles": 0, "importedFrom": [ - "github.com/palantir/godel/pkg/versionedconfig" + "github.com/palantir/godel/pkg/versionedconfig", + "github.com/palantir/godel/pkg/versionedconfig_test" ] } ], @@ -50,8 +51,8 @@ "importedFrom": [ "github.com/palantir/godel/pkg/dirchecksum_test", "github.com/palantir/godel/pkg/osarch_test", + "github.com/palantir/godel/pkg/products/v2/products_test", "github.com/palantir/godel/pkg/products_test", - "github.com/palantir/godel/pkg/v2/products_test", "github.com/palantir/godel/pkg/versionedconfig_test" ] }, @@ -62,8 +63,8 @@ "importedFrom": [ "github.com/palantir/godel/pkg/dirchecksum_test", "github.com/palantir/godel/pkg/osarch_test", + "github.com/palantir/godel/pkg/products/v2/products_test", "github.com/palantir/godel/pkg/products_test", - "github.com/palantir/godel/pkg/v2/products_test", "github.com/palantir/godel/pkg/versionedconfig_test" ] } diff --git a/vendor/github.com/palantir/godel/pkg/products/products.go b/vendor/github.com/palantir/godel/pkg/products/products.go index 43c1b4e8..7c0b32ed 100644 --- a/vendor/github.com/palantir/godel/pkg/products/products.go +++ b/vendor/github.com/palantir/godel/pkg/products/products.go @@ -19,12 +19,13 @@ import ( "os/exec" "path" "runtime" + "strconv" "strings" ) // List returns a slice that contains all of the products in the project. func List() ([]string, error) { - gödelw, err := newGödelwRunner() + gödelw, err := newGodelwRunner() if err != nil { return nil, err } @@ -38,21 +39,31 @@ func List() ([]string, error) { // Bin returns the path to the executable for the given product for the current OS/Architecture, building the executable // using "godelw build" if the executable does not already exist or is not up-to-date. func Bin(product string) (string, error) { - gödelw, err := newGödelwRunner() + godelw, err := newGodelwRunner() if err != nil { return "", err } + + // return error if version is too new + majorVersion, err := majorVersion(godelw) + if err != nil { + return "", err + } + if majorVersion >= 2 { + return "", fmt.Errorf("this package does not support godel with major version >=2, but was %d: use v2 of the library instead", majorVersion) + } + currOSArchFlag := fmt.Sprintf("--os-arch=%s-%s", runtime.GOOS, runtime.GOARCH) - requiresBuildOutput, err := gödelw.run("artifacts", "build", "--absolute", currOSArchFlag, "--requires-build", product) + requiresBuildOutput, err := godelw.run("artifacts", "build", "--absolute", currOSArchFlag, "--requires-build", product) if err != nil { return "", err } if requiresBuildOutput != "" { - if _, err := gödelw.run("build", currOSArchFlag, product); err != nil { + if _, err := godelw.run("build", currOSArchFlag, product); err != nil { return "", err } } - binPath, err := gödelw.run("artifacts", "build", "--absolute", currOSArchFlag, product) + binPath, err := godelw.run("artifacts", "build", "--absolute", currOSArchFlag, product) if err != nil { return "", err } @@ -65,25 +76,25 @@ func Bin(product string) (string, error) { // Dist builds the distribution for the specified product using the "godelw dist" command and returns the path to the // created distribution artifact. func Dist(product string) (string, error) { - gödelw, err := newGödelwRunner() + godelw, err := newGodelwRunner() if err != nil { return "", err } - if _, err := gödelw.run("dist", product); err != nil { + if _, err := godelw.run("dist", product); err != nil { return "", err } - return gödelw.run("artifacts", "dist", "--absolute", product) + return godelw.run("artifacts", "dist", "--absolute", product) } -type gödelwRunner interface { +type godelwRunner interface { run(args ...string) (string, error) } -type gödelwRunnerStruct struct { +type godelwRunnerStruct struct { path string } -func (g *gödelwRunnerStruct) run(args ...string) (string, error) { +func (g *godelwRunnerStruct) run(args ...string) (string, error) { cmd := exec.Command(g.path, args...) output, err := cmd.CombinedOutput() outputStr := strings.TrimSpace(string(output)) @@ -93,17 +104,37 @@ func (g *gödelwRunnerStruct) run(args ...string) (string, error) { return outputStr, err } -func newGödelwRunner() (gödelwRunner, error) { - path, err := gödelwPath() +func newGodelwRunner() (godelwRunner, error) { + path, err := godelwPath() if err != nil { return nil, err } - return &gödelwRunnerStruct{ + return &godelwRunnerStruct{ path: path, }, nil } -func gödelwPath() (string, error) { +func majorVersion(r godelwRunner) (int, error) { + versionOutput, err := r.run("version") + if err != nil { + return -1, err + } + parts := strings.Split(versionOutput, " ") + if len(parts) < 3 { + return -1, fmt.Errorf("output of version must have at least 3 ' '-separated parts, but was %q", versionOutput) + } + versionParts := strings.Split(parts[2], ".") + if len(versionParts) < 3 { + return -1, fmt.Errorf("version must have at least 3 '.'-separated parts, but was %q", parts[2]) + } + majorVersion, err := strconv.Atoi(versionParts[0]) + if err != nil { + return -1, fmt.Errorf("unable to parse %q as integer: %v", versionParts[0], err) + } + return majorVersion, nil +} + +func godelwPath() (string, error) { projectDir, err := projectDir() if err != nil { return "", err diff --git a/vendor/github.com/palantir/godel/pkg/v2/products/products.go b/vendor/github.com/palantir/godel/pkg/products/v2/products/products.go similarity index 100% rename from vendor/github.com/palantir/godel/pkg/v2/products/products.go rename to vendor/github.com/palantir/godel/pkg/products/v2/products/products.go diff --git a/vendor/github.com/palantir/godel/pkg/v2/products/products_test.go b/vendor/github.com/palantir/godel/pkg/products/v2/products/products_test.go similarity index 96% rename from vendor/github.com/palantir/godel/pkg/v2/products/products_test.go rename to vendor/github.com/palantir/godel/pkg/products/v2/products/products_test.go index d17b5229..f07fd72a 100644 --- a/vendor/github.com/palantir/godel/pkg/v2/products/products_test.go +++ b/vendor/github.com/palantir/godel/pkg/products/v2/products/products_test.go @@ -22,7 +22,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/palantir/godel/pkg/v2/products" + "github.com/palantir/godel/pkg/products/v2/products" ) func TestList(t *testing.T) { diff --git a/vendor/github.com/palantir/godel/pkg/versionedconfig/legacy.go b/vendor/github.com/palantir/godel/pkg/versionedconfig/legacy.go index b4b0d8e8..6c9eb271 100644 --- a/vendor/github.com/palantir/godel/pkg/versionedconfig/legacy.go +++ b/vendor/github.com/palantir/godel/pkg/versionedconfig/legacy.go @@ -15,6 +15,8 @@ package versionedconfig import ( + "bytes" + "gopkg.in/yaml.v2" ) @@ -31,3 +33,16 @@ func IsLegacyConfig(cfgBytes []byte) bool { } return cfg.Legacy } + +const legacyPrefix = `legacy-config: true +` + +// TrimLegacyPrefix trims the "legacy-config: true" YAML key/value if it is the first line in the provided bytes. If the +// provided bytes do not start with this line, the input is returned directly. Returns true if the prefix is trimmed, +// false otherwise. +func TrimLegacyPrefix(in []byte) ([]byte, bool) { + if bytes.HasPrefix(in, []byte(legacyPrefix)) { + return bytes.TrimPrefix(in, []byte(legacyPrefix)), true + } + return in, false +} diff --git a/vendor/github.com/palantir/godel/pkg/versionedconfig/legacy_test.go b/vendor/github.com/palantir/godel/pkg/versionedconfig/legacy_test.go new file mode 100644 index 00000000..92159eaf --- /dev/null +++ b/vendor/github.com/palantir/godel/pkg/versionedconfig/legacy_test.go @@ -0,0 +1,64 @@ +// Copyright 2016 Palantir Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package versionedconfig_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/yaml.v2" + + "github.com/palantir/godel/pkg/versionedconfig" +) + +func TestTrimLegacyPrefix(t *testing.T) { + type Foo struct { + versionedconfig.ConfigWithLegacy `yaml:",inline"` + Foo string `yaml:"foo"` + } + fooBytes, err := yaml.Marshal(Foo{ + ConfigWithLegacy: versionedconfig.ConfigWithLegacy{ + Legacy: true, + }, + Foo: "foo-value", + }) + require.NoError(t, err) + + out, trimmed := versionedconfig.TrimLegacyPrefix(fooBytes) + assert.True(t, trimmed, "expected prefix to be trimmed") + assert.Equal(t, `foo: foo-value +`, string(out)) +} + +func TestTrimLegacyPrefixDoesNotTrimSuffix(t *testing.T) { + type Foo struct { + Foo string `yaml:"foo"` + versionedconfig.ConfigWithLegacy `yaml:",inline"` + } + fooBytes, err := yaml.Marshal(Foo{ + ConfigWithLegacy: versionedconfig.ConfigWithLegacy{ + Legacy: true, + }, + Foo: "foo-value", + }) + require.NoError(t, err) + + out, trimmed := versionedconfig.TrimLegacyPrefix(fooBytes) + assert.False(t, trimmed, "expected prefix to be trimmed") + assert.Equal(t, `foo: foo-value +legacy-config: true +`, string(out)) +}