Unverified Commit a24f4a59 authored by Bryan Liles's avatar Bryan Liles Committed by GitHub
Browse files

Merge pull request #385 from bryanl/deprecate-metadata-registry

Deprecate metdata registry
parents 86df256a 152312bf
......@@ -16,7 +16,6 @@
package actions
import (
"github.com/davecgh/go-spew/spew"
"github.com/ksonnet/ksonnet/metadata/app"
"github.com/ksonnet/ksonnet/pkg/pkg"
"github.com/ksonnet/ksonnet/pkg/registry"
......@@ -76,8 +75,6 @@ func (pi *PkgInstall) Run() error {
return err
}
spew.Dump(d)
return pi.depCacher(pi.app, d, customName)
}
......
// Copyright 2018 The ksonnet authors
//
//
// 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 actions
import (
"fmt"
"io"
"os"
"strings"
"github.com/ksonnet/ksonnet/metadata/app"
"github.com/ksonnet/ksonnet/pkg/pkg"
"github.com/ksonnet/ksonnet/prototype"
"github.com/pkg/errors"
)
// RunPrototypeDescribe runs `prototype describe`
func RunPrototypeDescribe(ksApp app.App, query string) error {
pd, err := NewPrototypeDescribe(ksApp, query)
if err != nil {
return err
}
return pd.Run()
}
// PrototypeDescribe lists available namespaces
type PrototypeDescribe struct {
app app.App
out io.Writer
query string
appPrototypes func(app.App, pkg.Descriptor) (prototype.SpecificationSchemas, error)
}
// NewPrototypeDescribe creates an instance of PrototypeDescribe
func NewPrototypeDescribe(ksApp app.App, query string) (*PrototypeDescribe, error) {
pd := &PrototypeDescribe{
app: ksApp,
out: os.Stdout,
query: query,
appPrototypes: pkg.LoadPrototypes,
}
return pd, nil
}
// Run runs the env list action.
func (pd *PrototypeDescribe) Run() error {
prototypes, err := allPrototypes(pd.app, pd.appPrototypes)
if err != nil {
return err
}
index := prototype.NewIndex(prototypes)
prototypes, err = index.List()
if err != nil {
return err
}
p, err := findUniquePrototype(pd.query, prototypes)
if err != nil {
return err
}
fmt.Fprintln(pd.out, `PROTOTYPE NAME:`)
fmt.Fprintln(pd.out, p.Name)
fmt.Fprintln(pd.out)
fmt.Fprintln(pd.out, `DESCRIPTION:`)
fmt.Fprintln(pd.out, p.Template.Description)
fmt.Fprintln(pd.out)
fmt.Fprintln(pd.out, `REQUIRED PARAMETERS:`)
fmt.Fprintln(pd.out, p.RequiredParams().PrettyString(" "))
fmt.Fprintln(pd.out)
fmt.Fprintln(pd.out, `OPTIONAL PARAMETERS:`)
fmt.Fprintln(pd.out, p.OptionalParams().PrettyString(" "))
fmt.Fprintln(pd.out)
fmt.Fprintln(pd.out, `TEMPLATE TYPES AVAILABLE:`)
fmt.Fprintf(pd.out, " %s\n", p.Template.AvailableTemplates())
return nil
}
type prototypeFn func(app.App, pkg.Descriptor) (prototype.SpecificationSchemas, error)
func allPrototypes(a app.App, appPrototypes prototypeFn) (prototype.SpecificationSchemas, error) {
libraries, err := a.Libraries()
if err != nil {
return nil, err
}
var prototypes prototype.SpecificationSchemas
for _, library := range libraries {
d := pkg.Descriptor{
Registry: library.Registry,
Part: library.Name,
}
p, err := appPrototypes(a, d)
if err != nil {
return nil, err
}
prototypes = append(prototypes, p...)
}
return prototypes, nil
}
func findUniquePrototype(query string, prototypes prototype.SpecificationSchemas) (*prototype.SpecificationSchema, error) {
index := prototype.NewIndex(prototypes)
sameSuffix, err := index.SearchNames(query, prototype.Suffix)
if err != nil {
return nil, err
}
if len(sameSuffix) == 1 {
// Success.
return sameSuffix[0], nil
} else if len(sameSuffix) > 1 {
// Ambiguous match.
names := specNames(sameSuffix)
return nil, errors.Errorf("ambiguous match for '%s': %s", query, strings.Join(names, ", "))
} else {
// No matches.
substring, err := index.SearchNames(query, prototype.Substring)
if err != nil || len(substring) == 0 {
return nil, errors.Errorf("no prototype names matched '%s'", query)
}
partialMatches := specNames(substring)
partials := strings.Join(partialMatches, "\n")
return nil, errors.Errorf("no prototype names matched '%s'; a list of partial matches: %s", query, partials)
}
}
func specNames(prototypes []*prototype.SpecificationSchema) []string {
partialMatches := []string{}
for _, proto := range prototypes {
partialMatches = append(partialMatches, proto.Name)
}
return partialMatches
}
// Copyright 2018 The ksonnet authors
//
//
// 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 actions
import (
"bytes"
"testing"
"github.com/ksonnet/ksonnet/metadata/app"
amocks "github.com/ksonnet/ksonnet/metadata/app/mocks"
"github.com/stretchr/testify/require"
)
func TestPrototypeDescribe(t *testing.T) {
withApp(t, func(appMock *amocks.App) {
libaries := app.LibraryRefSpecs{}
appMock.On("Libraries").Return(libaries, nil)
a, err := NewPrototypeDescribe(appMock, "namespace")
require.NoError(t, err)
var buf bytes.Buffer
a.out = &buf
err = a.Run()
require.NoError(t, err)
assertOutput(t, "prototype/describe/output.txt", buf.String())
})
}
......@@ -7,7 +7,7 @@
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Upless required by applicable law or agreed to in writing, software
// 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
......@@ -56,31 +56,16 @@ func NewPrototypeList(ksApp app.App) (*PrototypeList, error) {
// Run runs the env list action.
func (pl *PrototypeList) Run() error {
libraries, err := pl.app.Libraries()
prototypes, err := allPrototypes(pl.app, pl.prototypes)
if err != nil {
return err
}
var prototypes prototype.SpecificationSchemas
for _, library := range libraries {
d := pkg.Descriptor{
Registry: library.Registry,
Part: library.Name,
}
p, err := pl.prototypes(pl.app, d)
if err != nil {
return err
}
prototypes = append(prototypes, p...)
}
index := prototype.NewIndex(prototypes)
prototypes, err = index.List()
if err != nil {
return nil
return err
}
var rows [][]string
......
// Copyright 2018 The ksonnet authors
//
//
// 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 actions
import (
"fmt"
"io"
"os"
"strings"
"github.com/ksonnet/ksonnet/metadata"
"github.com/ksonnet/ksonnet/metadata/app"
"github.com/ksonnet/ksonnet/pkg/pkg"
"github.com/ksonnet/ksonnet/prototype"
"github.com/ksonnet/ksonnet/prototype/snippet"
"github.com/ksonnet/ksonnet/prototype/snippet/jsonnet"
strutil "github.com/ksonnet/ksonnet/strings"
"github.com/pkg/errors"
"github.com/spf13/pflag"
)
// RunPrototypePreview runs `prototype describe`
func RunPrototypePreview(ksApp app.App, query string, args []string) error {
pp, err := NewPrototypePreview(ksApp, query, args)
if err != nil {
return err
}
return pp.Run()
}
// PrototypePreview lists available namespaces
type PrototypePreview struct {
app app.App
out io.Writer
query string
args []string
appPrototypes func(app.App, pkg.Descriptor) (prototype.SpecificationSchemas, error)
}
// NewPrototypePreview creates an instance of PrototypePreview
func NewPrototypePreview(ksApp app.App, query string, args []string) (*PrototypePreview, error) {
pp := &PrototypePreview{
app: ksApp,
out: os.Stdout,
query: query,
args: args,
appPrototypes: pkg.LoadPrototypes,
}
return pp, nil
}
// Run runs the env list action.
func (pp *PrototypePreview) Run() error {
prototypes, err := allPrototypes(pp.app, pp.appPrototypes)
if err != nil {
return err
}
index := prototype.NewIndex(prototypes)
prototypes, err = index.List()
if err != nil {
return err
}
p, err := findUniquePrototype(pp.query, prototypes)
if err != nil {
return err
}
flags := bindPrototypeParams(p)
if err = flags.Parse(pp.args); err != nil {
return errors.Wrap(err, "parse preview args")
}
// NOTE: only supporting jsonnet templates
templateType := prototype.Jsonnet
params, err := getParameters(p, flags)
if err != nil {
return err
}
text, err := expandPrototype(p, templateType, params, "preview")
if err != nil {
return err
}
fmt.Fprintln(pp.out, text)
return nil
}
func bindPrototypeParams(p *prototype.SpecificationSchema) *pflag.FlagSet {
fs := pflag.NewFlagSet("preview", pflag.ContinueOnError)
for _, param := range p.RequiredParams() {
fs.String(param.Name, "", param.Description)
}
for _, param := range p.OptionalParams() {
fs.String(param.Name, *param.Default, param.Description)
}
return fs
}
func getParameters(proto *prototype.SpecificationSchema, flags *pflag.FlagSet) (map[string]string, error) {
missingRequired := prototype.ParamSchemas{}
values := map[string]string{}
for _, param := range proto.RequiredParams() {
val, err := flags.GetString(param.Name)
if err != nil {
return nil, err
} else if val == "" {
missingRequired = append(missingRequired, param)
} else if _, ok := values[param.Name]; ok {
return nil, errors.Errorf("Prototype '%s' has multiple parameters with name '%s'", proto.Name, param.Name)
}
quoted, err := param.Quote(val)
if err != nil {
return nil, err
}
values[param.Name] = quoted
}
if len(missingRequired) > 0 {
return nil, errors.Errorf("failed to instantiate prototype '%s'. The following required parameters are missing:\n%s", proto.Name, missingRequired.PrettyString(""))
}
for _, param := range proto.OptionalParams() {
val, err := flags.GetString(param.Name)
if err != nil {
return nil, err
} else if _, ok := values[param.Name]; ok {
return nil, errors.Errorf("prototype '%s' has multiple parameters with name '%s'", proto.Name, param.Name)
}
quoted, err := param.Quote(val)
if err != nil {
return nil, err
}
values[param.Name] = quoted
}
return values, nil
}
// TODO: this doesn't belong here. Needs to be closer to where other jsonnet processing happens.
func expandPrototype(proto *prototype.SpecificationSchema, templateType prototype.TemplateType, params map[string]string, componentName string) (string, error) {
template, err := proto.Template.Body(templateType)
if err != nil {
return "", err
}
if templateType == prototype.Jsonnet {
componentsText := "components." + componentName
if !strutil.IsASCIIIdentifier(componentName) {
componentsText = fmt.Sprintf(`components["%s"]`, componentName)
}
template = append([]string{
`local env = std.extVar("` + metadata.EnvExtCodeKey + `");`,
`local params = std.extVar("` + metadata.ParamsExtCodeKey + `").` + componentsText + ";"},
template...)
return jsonnet.Parse(componentName, strings.Join(template, "\n"))
}
tm := snippet.Parse(strings.Join(template, "\n"))
return tm.Evaluate(params)
}
// Copyright 2018 The ksonnet authors
//
//
// 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 actions
import (
"bytes"
"testing"
"github.com/ksonnet/ksonnet/metadata/app"
amocks "github.com/ksonnet/ksonnet/metadata/app/mocks"
"github.com/stretchr/testify/require"
)
func TestPrototypePreview(t *testing.T) {
withApp(t, func(appMock *amocks.App) {
libaries := app.LibraryRefSpecs{}
appMock.On("Libraries").Return(libaries, nil)
args := []string{
"--name", "myDeployment",
"--image", "nginx",
"--port", "80",
}
a, err := NewPrototypePreview(appMock, "single-port-deployment", args)
require.NoError(t, err)
var buf bytes.Buffer
a.out = &buf
err = a.Run()
require.NoError(t, err)
assertOutput(t, "prototype/preview/output.txt", buf.String())
})
}
// Copyright 2018 The ksonnet authors
//
//
// 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 actions
import (
"fmt"
"io"
"os"
"sort"
"github.com/ksonnet/ksonnet/metadata/app"
"github.com/ksonnet/ksonnet/pkg/pkg"
"github.com/ksonnet/ksonnet/pkg/util/table"
"github.com/ksonnet/ksonnet/prototype"
)
// RunPrototypeSearch runs `prototype search`
func RunPrototypeSearch(ksApp app.App, query string) error {
ps, err := NewPrototypeSearch(ksApp, query)
if err != nil {
return err
}
return ps.Run()
}
// PrototypeSearch lists available namespaces
type PrototypeSearch struct {
app app.App
query string
out io.Writer
prototypes func(app.App, pkg.Descriptor) (prototype.SpecificationSchemas, error)
protoSearch func(string, prototype.SpecificationSchemas) (prototype.SpecificationSchemas, error)
}
// NewPrototypeSearch creates an instance of PrototypeSearch
func NewPrototypeSearch(ksApp app.App, query string) (*PrototypeSearch, error) {
ps := &PrototypeSearch{
app: ksApp,
query: query,
out: os.Stdout,
prototypes: pkg.LoadPrototypes,
protoSearch: protoSearch,
}
return ps, nil
}
// Run runs the env list action.
func (ps *PrototypeSearch) Run() error {
prototypes, err := allPrototypes(ps.app, ps.prototypes)
if err != nil {
return err
}
results, err := ps.protoSearch(ps.query, prototypes)
if err != nil {
return err
}
if len(results) == 1 {
return fmt.Errorf("failed to find any search results for query %q", ps.query)
}
var rows [][]string
for _, p := range results {
rows = append(rows, []string{p.Name, p.Template.ShortDescription})
}
t := table.New(ps.out)
t.SetHeader([]string{"name", "description"})
sort.Slice(rows, func(i, j int) bool {
return rows[i][0] < rows[j][0]
})
t.AppendBulk(rows)
return t.Render()
}
func protoSearch(query string, prototypes prototype.SpecificationSchemas) (prototype.SpecificationSchemas, error) {
index := prototype.NewIndex(prototypes)
return index.SearchNames(query, prototype.Substring)
}
// Copyright 2018 The ksonnet authors
//
//
// 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
//