Skip to content

Commit

Permalink
refactor: Clean up kraft pkg info by using native Catalog
Browse files Browse the repository at this point in the history
This commit effectively reverses #536 in favour of using the
existing package manager's `Catalog` method.  Since packages
already expose a `Columns` method, this information can be used
to "show" information about a specific named package.
Simultaneously, the `Catalog` method and the information returned
by the implementing `pack.Package` works for all current package
managers.

Secondly, wrap the invocations of `Catalog` with `tui.processtree`
which is useful when used with the `-u|--update` flag for very
long wait times and to help indicate to the user the longevity
of the invocation.

Finally, utilize the newly introduced `PrintPackages` method
which was previously ripped from `kraft pkg ls`.

Signed-off-by: Alexander Jung <[email protected]>
  • Loading branch information
nderjung committed Dec 19, 2023
1 parent b51bd22 commit a7c267d
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 152 deletions.
132 changes: 54 additions & 78 deletions internal/cli/kraft/pkg/info/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,23 @@ package info

import (
"context"
"encoding/json"
"fmt"
"os"
"path"
"reflect"
"strings"

"github.com/MakeNowJust/heredoc"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
"kraftkit.sh/cmdfactory"
"kraftkit.sh/config"
pkgutils "kraftkit.sh/internal/cli/kraft/pkg/utils"
"kraftkit.sh/iostreams"
"kraftkit.sh/manifest"
"kraftkit.sh/log"
"kraftkit.sh/pack"
"kraftkit.sh/packmanager"
"kraftkit.sh/tui/processtree"
)

type InfoOptions struct {
Output string `long:"output" short:"o" usage:"Set output format" default:"yaml"`
Output string `long:"output" short:"o" usage:"Set output format" default:"table"`
Update bool `long:"update" short:"u" usage:"Get latest information about components before listing results"`
}

// Info shows package information.
Expand All @@ -45,7 +43,7 @@ func New() *cobra.Command {
Long: heredoc.Doc(`
Shows a Unikraft package like library, core etc details
`),
Args: cmdfactory.MinimumArgs(1, "package name is not specified to show information"),
Args: cmdfactory.MinimumArgs(1, "package name(s) not specified"),
Example: heredoc.Doc(`
# Shows details for the library nginx
$ kraft pkg info nginx`),
Expand All @@ -60,86 +58,64 @@ func New() *cobra.Command {
return cmd
}

func (opts *InfoOptions) Pre(cmd *cobra.Command, _ []string) error {
ctx, err := packmanager.WithDefaultUmbrellaManagerInContext(cmd.Context())
func (opts *InfoOptions) Run(ctx context.Context, args []string) error {
ctx, err := packmanager.WithDefaultUmbrellaManagerInContext(ctx)
if err != nil {
return err
}

cmd.SetContext(ctx)
return nil
}
parallel := !config.G[config.KraftKit](ctx).NoParallel
norender := log.LoggerTypeFromString(config.G[config.KraftKit](ctx).Log.Type) != log.FANCY

var searches []*processtree.ProcessTreeItem
var packs []pack.Package

for _, arg := range args {
search := processtree.NewProcessTreeItem(
fmt.Sprintf("finding %s", arg), "",
func(ctx context.Context) error {
more, err := packmanager.G(ctx).Catalog(ctx,
packmanager.WithName(arg),
packmanager.WithUpdate(opts.Update),
)
if err != nil {
return err
}

func (opts *InfoOptions) Run(ctx context.Context, args []string) error {
if len(args) == 0 {
return fmt.Errorf("package name is not specified to show information")
} else if opts.Output != "json" && opts.Output != "yaml" {
return fmt.Errorf("specified output format is not supported")
if len(more) == 0 {
return fmt.Errorf("could not find: %s", arg)
}

packs = append(packs, more...)

return nil
},
)

searches = append(searches, search)
}

metadata, err := packmanager.G(ctx).Catalog(ctx,
packmanager.WithName(args[0]),
treemodel, err := processtree.NewProcessTree(
ctx,
[]processtree.ProcessTreeOption{
processtree.IsParallel(parallel),
processtree.WithRenderer(norender),
processtree.WithFailFast(false),
processtree.WithHideOnSuccess(true),
},
searches...,
)
if err != nil {
return err
}

if metadata != nil {
var byteCode []byte
var manifestStruct *manifest.Manifest
var origin string
value := reflect.ValueOf(metadata).Elem()
numFields := value.NumField()
structType := value.Type()

for i := 0; i < numFields; i++ {
if structType.Field(i).Name == "Origin" {
origin = value.Field(i).String()
}
}

if len(origin) > 0 && !strings.HasPrefix(origin, "http") {
var indexYaml manifest.ManifestIndex
manifestIndexYamlPath := path.Join(config.G[config.KraftKit](ctx).Paths.Manifests, "index.yaml")
indexbyteCode, err := os.ReadFile(manifestIndexYamlPath)
if err != nil {
return err
}
if err = yaml.Unmarshal(indexbyteCode, &indexYaml); err != nil {
return err
}
for _, manifestObj := range indexYaml.Manifests {
if args[0] == manifestObj.Name {
manifestYamlPath := path.Join(config.G[config.KraftKit](ctx).Paths.Manifests, manifestObj.Manifest)
byteCode, err = os.ReadFile(manifestYamlPath)
if err != nil {
return err
}
manifestStruct, err = manifest.NewManifestFromBytes(ctx, byteCode)
if err != nil {
return err
}
break
}
}
} else if len(origin) > 0 {
manifestStruct, err = manifest.NewManifestFromURL(ctx, origin)
if err != nil {
return err
}
}

if opts.Output == "json" {
byteCode, err = json.Marshal(manifestStruct)
} else {
byteCode, err = yaml.Marshal(manifestStruct)
}

if err != nil {
return err
}

fmt.Fprint(iostreams.G(ctx).Out, string(byteCode)+"\n")
if err := treemodel.Start(); err != nil {
return fmt.Errorf("could not complete search: %v", err)
}
return nil

if len(packs) == 0 {
return fmt.Errorf("could not find package(s): %v", args)
}

return pkgutils.PrintPackages(ctx, iostreams.G(ctx).Out, opts.Output, packs...)
}
42 changes: 0 additions & 42 deletions manifest/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -499,45 +499,3 @@ func (m *manifestManager) LocalManifestIndex(ctx context.Context) string {
func (m *manifestManager) Format() pack.PackageFormat {
return ManifestFormat
}

func (m *manifestManager) Show(ctx context.Context, outputFormat string, qopts ...packmanager.QueryOption) (any, error) {
var query packmanager.Query
var metadata any

for _, qopt := range qopts {
qopt(&query)
}

packages, err := m.Catalog(ctx, packmanager.WithUpdate(query.Update()))
if err != nil {
return nil, err
}

// Sort packages by type, name, version, format
sort.Slice(packages, func(i, j int) bool {
if packages[i].Type() != packages[j].Type() {
return packages[i].Type() < packages[j].Type()
}

if packages[i].Name() != packages[j].Name() {
return packages[i].Name() < packages[j].Name()
}

if packages[i].Version() != packages[j].Version() {
return packages[i].Version() < packages[j].Version()
}

return packages[i].Format() < packages[j].Format()
})

for _, pack := range packages {
if query.Name() == pack.Name() {
metadata = pack.Metadata()
}
}

if metadata == nil {
return nil, fmt.Errorf("%s package information not found", query.Name())
}
return metadata, nil
}
4 changes: 0 additions & 4 deletions oci/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,3 @@ func (manager *ociManager) From(pack.PackageFormat) (packmanager.PackageManager,
func (manager *ociManager) Format() pack.PackageFormat {
return OCIFormat
}

func (manager *ociManager) Show(ctx context.Context, outputFormat string, qopts ...packmanager.QueryOption) (any, error) {
return nil, fmt.Errorf("show is not implemented for ociManager")
}
3 changes: 0 additions & 3 deletions packmanager/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,4 @@ type PackageManager interface {

// Format returns the name of the implementation.
Format() pack.PackageFormat

// Show package information.
Show(context.Context, string, ...QueryOption) (any, error)
}
25 changes: 0 additions & 25 deletions packmanager/umbrella.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,28 +296,3 @@ func NewUmbrellaManager(ctx context.Context, constructors []func(*UmbrellaManage

return u, nil
}

func (u UmbrellaManager) Show(ctx context.Context, outputFormat string, qopts ...QueryOption) (any, error) {
var metadatas []any

for _, manager := range u.packageManagers {
log.G(ctx).WithFields(logrus.Fields{
"format": manager.Format(),
}).Tracef("showing package information")

metadata, err := manager.Show(ctx, outputFormat, qopts...)
if err != nil {
log.G(ctx).
WithField("format", manager.Format()).
Debugf("could not show package: %v", err)
continue
}

metadatas = append(metadatas, metadata)
}
if len(metadatas) == 0 {
return nil, fmt.Errorf("no information found about requested package")
}

return metadatas[0], nil
}

0 comments on commit a7c267d

Please sign in to comment.