Unverified Commit 9a0985f3 authored by bryanl's avatar bryanl
Browse files

create package install checker

Signed-off-by: bryanl bryanliles@gmail.com
parent 6221d1ec
/kubecfg
/ks
/ks.exe
/cmd/ks/debug
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
debug.test
# Folders
_obj
_test
_output
dist
/_output
/dist
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
# gotags
tags
.DS_Store
......@@ -16,12 +16,11 @@
package actions
import (
"fmt"
"io"
"os"
"text/template"
"github.com/ksonnet/ksonnet/pkg/app"
"github.com/ksonnet/ksonnet/pkg/pkg"
"github.com/ksonnet/ksonnet/pkg/registry"
)
......@@ -37,24 +36,26 @@ func RunPkgDescribe(m map[string]interface{}) error {
// PkgDescribe describes a package.
type PkgDescribe struct {
app app.App
pkgName string
app app.App
pkgName string
templateSrc string
out io.Writer
libPartFn func(app.App, string) (*pkg.Package, error)
registryPartFn func(app.App, string) (*pkg.Package, error)
packageManager registry.PackageManager
}
// NewPkgDescribe creates an instance of PkgDescribe.
func NewPkgDescribe(m map[string]interface{}) (*PkgDescribe, error) {
ol := newOptionLoader(m)
app := ol.LoadApp()
pd := &PkgDescribe{
app: ol.LoadApp(),
app: app,
pkgName: ol.LoadString(OptionPackageName),
templateSrc: pkgDescribeTemplate,
out: os.Stdout,
libPartFn: pkg.Find,
registryPartFn: registry.Package,
packageManager: registry.NewPackageManager(app),
}
if ol.err != nil {
......@@ -66,35 +67,53 @@ func NewPkgDescribe(m map[string]interface{}) (*PkgDescribe, error) {
// Run describes a package.
func (pd *PkgDescribe) Run() error {
d, err := pkg.ParseName(pd.pkgName)
p, err := pd.packageManager.Find(pd.pkgName)
if err != nil {
return err
}
var p *pkg.Package
if d.Registry == "" {
p, err = pd.libPartFn(pd.app, pd.pkgName)
if err != nil {
return err
}
} else {
p, err = pd.registryPartFn(pd.app, pd.pkgName)
data := map[string]interface{}{
"Name": pd.pkgName,
"Description": p.Description(),
}
isInstalled, err := p.IsInstalled()
if err != nil {
return err
}
data["IsInstalled"] = isInstalled
if isInstalled {
prototypes, err := p.Prototypes()
if err != nil {
return err
}
data["Prototypes"] = prototypes
}
fmt.Fprintln(pd.out, `LIBRARY NAME:`)
fmt.Fprintln(pd.out, p.Name)
fmt.Fprintln(pd.out)
fmt.Fprintln(pd.out, `DESCRIPTION:`)
fmt.Fprintln(pd.out, p.Description)
fmt.Fprintln(pd.out)
fmt.Fprintln(pd.out, `PROTOTYPES:`)
t, err := template.New("pkg-describe").Parse(pd.templateSrc)
if err != nil {
return err
}
for _, proto := range p.Prototypes {
fmt.Fprintf(pd.out, " %s\n", proto.Name)
if err = t.Execute(pd.out, data); err != nil {
return err
}
return nil
}
const pkgDescribeTemplate = `LIBRARY NAME:
{{.Name}}
DESCRIPTION:
{{.Description}}
{{- if .IsInstalled}}
PROTOTYPES:{{- range .Prototypes}}
{{.Name}} - {{.Template.ShortDescription}}
{{- end}}{{- end}}
`
......@@ -17,80 +17,174 @@ package actions
import (
"bytes"
"io"
"testing"
"github.com/ksonnet/ksonnet/pkg/app"
"github.com/ksonnet/ksonnet/pkg/prototype"
"github.com/pkg/errors"
amocks "github.com/ksonnet/ksonnet/pkg/app/mocks"
"github.com/ksonnet/ksonnet/pkg/pkg"
pkgmocks "github.com/ksonnet/ksonnet/pkg/pkg/mocks"
"github.com/ksonnet/ksonnet/pkg/registry"
regmocks "github.com/ksonnet/ksonnet/pkg/registry/mocks"
"github.com/ksonnet/ksonnet/pkg/util/test"
"github.com/spf13/afero"
"github.com/stretchr/testify/require"
)
func TestPkgDescribe_library(t *testing.T) {
withApp(t, func(appMock *amocks.App) {
libaries := app.LibraryConfigs{
"apache": &app.LibraryConfig{},
}
appMock.On("Libraries").Return(libaries, nil)
in := map[string]interface{}{
OptionApp: appMock,
OptionPackageName: "apache",
}
a, err := NewPkgDescribe(in)
require.NoError(t, err)
var buf bytes.Buffer
a.out = &buf
a.libPartFn = func(a app.App, name string) (*pkg.Package, error) {
p := &pkg.Package{
Name: "apache",
Description: "description",
}
return p, nil
}
err = a.Run()
require.NoError(t, err)
assertOutput(t, "pkg/describe/output.txt", buf.String())
})
}
func TestPkgDescribe(t *testing.T) {
cases := []struct {
name string
output string
pkgManager func() registry.PackageManager
isErr bool
templateSrc string
out io.Writer
}{
{
name: "with no prototypes",
output: "pkg/describe/output.txt",
pkgManager: func() registry.PackageManager {
p := &pkgmocks.Package{}
p.On("Description").Return("description")
p.On("IsInstalled").Return(false, nil)
pkgManager := &regmocks.PackageManager{}
pkgManager.On("Find", "apache").Return(p, nil)
return pkgManager
},
},
{
name: "with prototypes",
output: "pkg/describe/with-prototypes.txt",
pkgManager: func() registry.PackageManager {
prototypes := prototype.Prototypes{
{
Name: "proto1",
Template: prototype.SnippetSchema{
ShortDescription: "short description",
},
},
}
p := &pkgmocks.Package{}
p.On("Description").Return("description")
p.On("IsInstalled").Return(true, nil)
p.On("Prototypes").Return(prototypes, nil)
pkgManager := &regmocks.PackageManager{}
pkgManager.On("Find", "apache").Return(p, nil)
return pkgManager
},
},
{
name: "package manager find error",
isErr: true,
pkgManager: func() registry.PackageManager {
pkgManager := &regmocks.PackageManager{}
pkgManager.On("Find", "apache").Return(nil, errors.New("failed"))
return pkgManager
},
},
{
name: "check installed returns error",
isErr: true,
pkgManager: func() registry.PackageManager {
p := &pkgmocks.Package{}
p.On("Description").Return("description")
p.On("IsInstalled").Return(false, errors.New("failed"))
pkgManager := &regmocks.PackageManager{}
pkgManager.On("Find", "apache").Return(p, nil)
return pkgManager
},
},
{
name: "gather prototypes returns error",
isErr: true,
pkgManager: func() registry.PackageManager {
p := &pkgmocks.Package{}
p.On("Prototypes").Return(nil, errors.New("failed"))
p.On("Description").Return("description")
p.On("IsInstalled").Return(true, nil)
pkgManager := &regmocks.PackageManager{}
pkgManager.On("Find", "apache").Return(p, nil)
return pkgManager
},
},
{
name: "template is invalid",
isErr: true,
pkgManager: func() registry.PackageManager {
p := &pkgmocks.Package{}
p.On("Description").Return("description")
p.On("IsInstalled").Return(false, nil)
pkgManager := &regmocks.PackageManager{}
pkgManager.On("Find", "apache").Return(p, nil)
return pkgManager
},
templateSrc: "{{-abc}}",
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Fatal(r)
}
}()
test.WithApp(t, "/app", func(a *amocks.App, fs afero.Fs) {
libraries := app.LibraryRefSpecs{
"apache": &app.LibraryRefSpec{},
}
func TestPkgDescribe_registry(t *testing.T) {
withApp(t, func(appMock *amocks.App) {
registries := app.RegistryConfigs{
"incubator": &app.RegistryConfig{},
}
appMock.On("Registries").Return(registries, nil)
a.On("Libraries").Return(libraries, nil)
in := map[string]interface{}{
OptionApp: appMock,
OptionPackageName: "incubator/apache",
}
in := map[string]interface{}{
OptionApp: a,
OptionPackageName: "apache",
}
a, err := NewPkgDescribe(in)
require.NoError(t, err)
pd, err := NewPkgDescribe(in)
require.NoError(t, err)
var buf bytes.Buffer
a.out = &buf
if tc.templateSrc != "" {
pd.templateSrc = tc.templateSrc
}
a.registryPartFn = func(a app.App, name string) (*pkg.Package, error) {
p := &pkg.Package{
Name: "apache",
Description: "description",
}
pd.packageManager = tc.pkgManager()
return p, nil
}
var buf bytes.Buffer
pd.out = &buf
err = a.Run()
require.NoError(t, err)
err = pd.Run()
if tc.isErr {
require.Error(t, err)
return
}
require.NoError(t, err)
assertOutput(t, "pkg/describe/output.txt", buf.String())
})
assertOutput(t, tc.output, buf.String())
})
})
}
}
func TestPkgDescribe_requires_app(t *testing.T) {
......
......@@ -24,6 +24,7 @@ import (
"github.com/ksonnet/ksonnet/pkg/app"
"github.com/ksonnet/ksonnet/pkg/pkg"
"github.com/ksonnet/ksonnet/pkg/prototype"
"github.com/ksonnet/ksonnet/pkg/registry"
"github.com/pkg/errors"
)
......@@ -39,22 +40,23 @@ func RunPrototypeDescribe(m map[string]interface{}) error {
// PrototypeDescribe describes a prototype.
type PrototypeDescribe struct {
app app.App
out io.Writer
query string
appPrototypesFn func(app.App, pkg.Descriptor) (prototype.Prototypes, error)
app app.App
out io.Writer
query string
packageManager registry.PackageManager
}
// NewPrototypeDescribe creates an instance of PrototypeDescribe
func NewPrototypeDescribe(m map[string]interface{}) (*PrototypeDescribe, error) {
ol := newOptionLoader(m)
app := ol.LoadApp()
pd := &PrototypeDescribe{
app: ol.LoadApp(),
app: app,
query: ol.LoadString(OptionQuery),
out: os.Stdout,
appPrototypesFn: pkg.LoadPrototypes,
out: os.Stdout,
packageManager: registry.NewPackageManager(app),
}
if ol.err != nil {
......@@ -66,7 +68,7 @@ func NewPrototypeDescribe(m map[string]interface{}) (*PrototypeDescribe, error)
// Run runs the env list action.
func (pd *PrototypeDescribe) Run() error {
prototypes, err := allPrototypes(pd.app, pd.appPrototypesFn)
prototypes, err := pd.packageManager.Prototypes()
if err != nil {
return err
}
......@@ -106,35 +108,6 @@ func (pd *PrototypeDescribe) Run() error {
type prototypeFn func(app.App, pkg.Descriptor) (prototype.Prototypes, error)
func allPrototypes(a app.App, appPrototypes prototypeFn) (prototype.Prototypes, error) {
if a == nil {
return nil, errors.New("app is required")
}
libraries, err := a.Libraries()
if err != nil {
return nil, err
}
var prototypes prototype.Prototypes
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.Prototypes) (*prototype.Prototype, error) {
index, err := prototype.NewIndex(prototypes, prototype.DefaultBuilder)
if err != nil {
......
......@@ -19,16 +19,18 @@ import (
"bytes"
"testing"
"github.com/ksonnet/ksonnet/pkg/app"
amocks "github.com/ksonnet/ksonnet/pkg/app/mocks"
"github.com/ksonnet/ksonnet/pkg/prototype"
registrymocks "github.com/ksonnet/ksonnet/pkg/registry/mocks"
"github.com/stretchr/testify/require"
)
func TestPrototypeDescribe(t *testing.T) {
withApp(t, func(appMock *amocks.App) {
libaries := app.LibraryConfigs{}
prototypes := prototype.Prototypes{}
appMock.On("Libraries").Return(libaries, nil)
manager := &registrymocks.PackageManager{}
manager.On("Prototypes").Return(prototypes, nil)
in := map[string]interface{}{
OptionApp: appMock,
......@@ -38,6 +40,8 @@ func TestPrototypeDescribe(t *testing.T) {
a, err := NewPrototypeDescribe(in)
require.NoError(t, err)
a.packageManager = manager
var buf bytes.Buffer
a.out = &buf
......
......@@ -21,8 +21,8 @@ import (
"sort"
"github.com/ksonnet/ksonnet/pkg/app"
"github.com/ksonnet/ksonnet/pkg/pkg"
"github.com/ksonnet/ksonnet/pkg/prototype"
"github.com/ksonnet/ksonnet/pkg/registry"
"github.com/ksonnet/ksonnet/pkg/util/table"
)
......@@ -38,20 +38,20 @@ func RunPrototypeList(m map[string]interface{}) error {
// PrototypeList lists available prototypes.
type PrototypeList struct {
app app.App
out io.Writer
prototypesFn func(app.App, pkg.Descriptor) (prototype.Prototypes, error)
app app.App
out io.Writer
packageManager registry.PackageManager
}
// NewPrototypeList creates an instance of PrototypeList
func NewPrototypeList(m map[string]interface{}) (*PrototypeList, error) {
ol := newOptionLoader(m)
app := ol.LoadApp()
pl := &PrototypeList{
app: ol.LoadApp(),
out: os.Stdout,
prototypesFn: pkg.LoadPrototypes,
app: app,
out: os.Stdout,
packageManager: registry.NewPackageManager(app),
}
if ol.err != nil {
......@@ -63,7 +63,7 @@ func NewPrototypeList(m map[string]interface{}) (*PrototypeList, error) {
// Run runs the env list action.
func (pl *PrototypeList) Run() error {
prototypes, err := allPrototypes(pl.app, pl.prototypesFn)
prototypes, err := pl.packageManager.Prototypes()
if err != nil {
return err
}
......
......@@ -19,16 +19,18 @@ import (
"bytes"
"testing"
"github.com/ksonnet/ksonnet/pkg/app"
amocks "github.com/ksonnet/ksonnet/pkg/app/mocks"
"github.com/ksonnet/ksonnet/pkg/prototype"
registrymocks "github.com/ksonnet/ksonnet/pkg/registry/mocks"
"github.com/stretchr/testify/require"
)
func TestPrototypeList(t *testing.T) {
withApp(t, func(appMock *amocks.App) {
libaries := app.LibraryConfigs{}
prototypes := prototype.Prototypes{}
appMock.On("Libraries").Return(libaries, nil)
manager := &registrymocks.PackageManager{}
manager.On("Prototypes").Return(prototypes, nil)
in := map[string]interface{}{
OptionApp: appMock,
......@@ -37,6 +39,8 @@ func TestPrototypeList(t *testing.T) {
a, err := NewPrototypeList(in)
require.NoError(t, err)
a.packageManager = manager
var buf bytes.Buffer
a.out = &buf
......
......@@ -27,6 +27,7 @@ import (
"github.com/ksonnet/ksonnet/pkg/prototype"
"github.com/ksonnet/ksonnet/pkg/prototype/snippet"
"github.com/ksonnet/ksonnet/pkg/prototype/snippet/jsonnet"
"github.com/ksonnet/ksonnet/pkg/registry"
strutil "github.com/ksonnet/ksonnet/pkg/util/strings"
"github.com/pkg/errors"
"github.com/spf13/pflag"
......@@ -51,20 +52,22 @@ type PrototypePreview struct {
appPrototypesFn func(app.App, pkg.Descriptor) (prototype.Prototypes, error)
bindFlagsFn func(p *prototype.Prototype) (*pflag.FlagSet, error)
packageManager registry.PackageManager
}
// NewPrototypePreview creates an instance of PrototypePreview
func NewPrototypePreview(m map[string]interface{}) (*PrototypePreview, error) {
ol := newOptionLoader(m)
app := ol.LoadApp()
pp := &PrototypePreview{
app: ol.LoadApp(),
app: app,
query: ol.LoadString(OptionQuery),
args: ol.LoadStringSlice(OptionArguments),
out: os.Stdout,
appPrototypesFn: pkg.LoadPrototypes,
bindFlagsFn: prototype.BindFlags,