luet/cmd/tree/pkglist.go

288 lines
7.6 KiB
Go
Raw Normal View History

2020-03-06 16:51:04 +00:00
// Copyright © 2020 Ettore Di Giacinto <mudler@gentoo.org>
// Daniele Rondina <geaaru@sabayonlinux.org>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, see <http://www.gnu.org/licenses/>.
package cmd_tree
import (
"fmt"
"os"
2020-03-06 16:51:04 +00:00
"sort"
2020-04-19 09:24:41 +00:00
"github.com/ghodss/yaml"
2020-05-23 06:51:33 +00:00
helpers "github.com/mudler/luet/cmd/helpers"
"github.com/mudler/luet/cmd/util"
2020-03-06 16:51:04 +00:00
pkg "github.com/mudler/luet/pkg/package"
"github.com/mudler/luet/pkg/solver"
2020-03-06 16:51:04 +00:00
tree "github.com/mudler/luet/pkg/tree"
"github.com/spf13/cobra"
)
type TreePackageResult struct {
2020-04-19 09:24:41 +00:00
Name string `json:"name"`
Category string `json:"category"`
Version string `json:"version"`
Path string `json:"path"`
Image string `json:"image"`
2020-04-19 09:24:41 +00:00
}
type TreeResults struct {
Packages []TreePackageResult `json:"packages"`
2020-04-19 09:24:41 +00:00
}
2020-03-06 16:51:04 +00:00
func pkgDetail(pkg pkg.Package) string {
ans := fmt.Sprintf(`
@@ Package: %s/%s-%s
Description: %s
License: %s`,
pkg.GetCategory(), pkg.GetName(), pkg.GetVersion(),
pkg.GetDescription(), pkg.GetLicense())
for idx, u := range pkg.GetURI() {
if idx == 0 {
ans += fmt.Sprintf(" URLs: %s", u)
} else {
ans += fmt.Sprintf(" %s", u)
}
}
return ans
}
func NewTreePkglistCommand() *cobra.Command {
var excludes []string
var matches []string
2020-03-06 16:51:04 +00:00
var ans = &cobra.Command{
Use: "pkglist [OPTIONS]",
Short: "List of the packages found in tree.",
Args: cobra.NoArgs,
2020-03-06 16:51:04 +00:00
PreRun: func(cmd *cobra.Command, args []string) {
t, _ := cmd.Flags().GetStringArray("tree")
if len(t) == 0 {
util.DefaultContext.Fatal("Mandatory tree param missing.")
2020-03-06 16:51:04 +00:00
}
revdeps, _ := cmd.Flags().GetBool("revdeps")
deps, _ := cmd.Flags().GetBool("deps")
if revdeps && deps {
util.DefaultContext.Fatal("Both revdeps and deps option used. Choice only one.")
}
2020-03-06 16:51:04 +00:00
},
Run: func(cmd *cobra.Command, args []string) {
var results TreeResults
var depSolver solver.PackageSolver
2020-03-06 16:51:04 +00:00
treePath, _ := cmd.Flags().GetStringArray("tree")
2020-03-06 16:51:04 +00:00
verbose, _ := cmd.Flags().GetBool("verbose")
2020-04-19 08:53:05 +00:00
buildtime, _ := cmd.Flags().GetBool("buildtime")
2020-03-06 16:51:04 +00:00
full, _ := cmd.Flags().GetBool("full")
revdeps, _ := cmd.Flags().GetBool("revdeps")
deps, _ := cmd.Flags().GetBool("deps")
2020-04-19 09:24:41 +00:00
out, _ := cmd.Flags().GetString("output")
if out != "terminal" {
util.DefaultContext.Config.GetLogging().SetLogLevel("error")
2020-04-19 09:24:41 +00:00
}
2020-04-19 08:53:05 +00:00
var reciper tree.Builder
if buildtime {
reciper = tree.NewCompilerRecipe(pkg.NewInMemoryDatabase(false))
} else {
reciper = tree.NewInstallerRecipe(pkg.NewInMemoryDatabase(false))
}
for _, t := range treePath {
err := reciper.Load(t)
if err != nil {
util.DefaultContext.Fatal("Error on load tree ", err)
}
2020-03-06 16:51:04 +00:00
}
if deps {
emptyInstallationDb := pkg.NewInMemoryDatabase(false)
2020-10-25 17:43:35 +00:00
depSolver = solver.NewSolver(solver.Options{Type: solver.SingleCoreSimple}, pkg.NewInMemoryDatabase(false),
reciper.GetDatabase(),
emptyInstallationDb)
}
2020-03-14 10:13:09 +00:00
regExcludes, err := helpers.CreateRegexArray(excludes)
if err != nil {
util.DefaultContext.Fatal(err.Error())
2020-03-06 16:51:04 +00:00
}
2020-03-14 10:13:09 +00:00
regMatches, err := helpers.CreateRegexArray(matches)
if err != nil {
util.DefaultContext.Fatal(err.Error())
}
2020-03-06 16:51:04 +00:00
plist := make([]string, 0)
for _, p := range reciper.GetDatabase().World() {
pkgstr := ""
addPkg := true
if full {
pkgstr = pkgDetail(p)
} else if verbose {
pkgstr = p.HumanReadableString()
2020-03-06 16:51:04 +00:00
} else {
pkgstr = fmt.Sprintf("%s/%s", p.GetCategory(), p.GetName())
}
if len(matches) > 0 {
matched := false
for _, rgx := range regMatches {
if rgx.MatchString(pkgstr) {
matched = true
break
}
}
if !matched {
addPkg = false
}
}
if len(excludes) > 0 && addPkg {
2020-03-06 16:51:04 +00:00
for _, rgx := range regExcludes {
if rgx.MatchString(pkgstr) {
addPkg = false
break
}
}
}
if !addPkg {
continue
}
if revdeps {
packs, _ := reciper.GetDatabase().GetRevdeps(p)
for i := range packs {
revdep := packs[i]
if full {
pkgstr = pkgDetail(revdep)
} else if verbose {
pkgstr = revdep.HumanReadableString()
} else {
pkgstr = fmt.Sprintf("%s/%s", revdep.GetCategory(), revdep.GetName())
}
plist = append(plist, pkgstr)
results.Packages = append(results.Packages, TreePackageResult{
Name: revdep.GetName(),
Version: revdep.GetVersion(),
Category: revdep.GetCategory(),
Path: revdep.GetPath(),
})
}
} else if deps {
solution, err := depSolver.Install(pkg.Packages{p})
if err != nil {
util.DefaultContext.Fatal(err.Error())
}
ass := solution.SearchByName(p.GetPackageName())
solution, err = solution.Order(reciper.GetDatabase(), ass.Package.GetFingerPrint())
if err != nil {
util.DefaultContext.Fatal(err.Error())
}
for _, pa := range solution {
if pa.Value {
// Exclude itself
if pa.Package.GetName() == p.GetName() && pa.Package.GetCategory() == p.GetCategory() {
continue
}
if full {
pkgstr = pkgDetail(pa.Package)
} else if verbose {
pkgstr = pa.Package.HumanReadableString()
} else {
pkgstr = fmt.Sprintf("%s/%s", pa.Package.GetCategory(), pa.Package.GetName())
}
plist = append(plist, pkgstr)
results.Packages = append(results.Packages, TreePackageResult{
Name: pa.Package.GetName(),
Version: pa.Package.GetVersion(),
Category: pa.Package.GetCategory(),
Path: pa.Package.GetPath(),
})
}
}
} else {
plist = append(plist, pkgstr)
results.Packages = append(results.Packages, TreePackageResult{
Name: p.GetName(),
Version: p.GetVersion(),
Category: p.GetCategory(),
Path: p.GetPath(),
})
2020-03-06 16:51:04 +00:00
}
2020-03-06 16:51:04 +00:00
}
2020-04-19 09:24:41 +00:00
y, err := yaml.Marshal(results)
if err != nil {
fmt.Printf("err: %v\n", err)
return
2020-03-06 16:51:04 +00:00
}
2020-04-19 09:24:41 +00:00
switch out {
case "yaml":
fmt.Println(string(y))
case "json":
j2, err := yaml.YAMLToJSON(y)
if err != nil {
fmt.Printf("err: %v\n", err)
return
}
fmt.Println(string(j2))
default:
if !deps {
sort.Strings(plist)
}
2020-04-19 09:24:41 +00:00
for _, p := range plist {
fmt.Println(p)
}
}
2020-03-06 16:51:04 +00:00
},
}
path, err := os.Getwd()
if err != nil {
util.DefaultContext.Fatal(err)
}
2020-04-19 08:53:05 +00:00
ans.Flags().BoolP("buildtime", "b", false, "Build time match")
2020-04-19 09:24:41 +00:00
ans.Flags().StringP("output", "o", "terminal", "Output format ( Defaults: terminal, available: json,yaml )")
ans.Flags().Bool("revdeps", false, "Search package reverse dependencies")
ans.Flags().Bool("deps", false, "Search package dependencies")
2020-04-19 08:53:05 +00:00
2020-03-06 16:51:04 +00:00
ans.Flags().BoolP("verbose", "v", false, "Add package version")
ans.Flags().BoolP("full", "f", false, "Show package detail")
ans.Flags().StringArrayP("tree", "t", []string{path}, "Path of the tree to use.")
ans.Flags().StringSliceVarP(&matches, "matches", "m", []string{},
"Include only matched packages from list. (Use string as regex).")
2020-03-06 16:51:04 +00:00
ans.Flags().StringSliceVarP(&excludes, "exclude", "e", []string{},
"Exclude matched packages from list. (Use string as regex).")
return ans
}