Unverified Commit 152312bf authored by bryanl's avatar bryanl
Browse files

Deprecate metdata registry



Functionality has been moved to more appropriate packages. Also add
actions for tasks that relied on metadata registry.
Signed-off-by: default avatarbryanl <bryanliles@gmail.com>
parent 86df256a
......@@ -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
//