// Copyright © 2019 Ettore Di Giacinto // // 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 . package cmd import ( "fmt" "strings" "github.com/ghodss/yaml" "github.com/jedib0t/go-pretty/table" "github.com/jedib0t/go-pretty/v6/list" "github.com/mudler/luet/cmd/util" . "github.com/mudler/luet/pkg/config" installer "github.com/mudler/luet/pkg/installer" . "github.com/mudler/luet/pkg/logger" pkg "github.com/mudler/luet/pkg/package" "github.com/spf13/cobra" ) type PackageResult struct { Name string `json:"name"` Category string `json:"category"` Version string `json:"version"` Repository string `json:"repository"` Target string `json:"target"` Hidden bool `json:"hidden"` Files []string `json:"files"` } type Results struct { Packages []PackageResult `json:"packages"` } func (r PackageResult) String() string { return fmt.Sprintf("%s/%s-%s required for %s", r.Category, r.Name, r.Version, r.Target) } var rows table.Row = table.Row{"Package", "Category", "Name", "Version", "Repository", "Description", "License", "URI"} func packageToRow(repo string, p pkg.Package) table.Row { return table.Row{p.HumanReadableString(), p.GetCategory(), p.GetName(), p.GetVersion(), repo, p.GetDescription(), p.GetLicense(), strings.Join(p.GetURI(), "\n")} } func packageToList(l list.Writer, repo string, p pkg.Package) { l.AppendItem(p.HumanReadableString()) l.Indent() l.AppendItem(fmt.Sprintf("Category: %s", p.GetCategory())) l.AppendItem(fmt.Sprintf("Name: %s", p.GetName())) l.AppendItem(fmt.Sprintf("Version: %s", p.GetVersion())) l.AppendItem(fmt.Sprintf("Description: %s", p.GetDescription())) l.AppendItem(fmt.Sprintf("Repository: %s ", repo)) l.AppendItem(fmt.Sprintf("Uri: %s ", strings.Join(p.GetURI(), "\n"))) l.UnIndent() } func searchLocally(term string, l list.Writer, t table.Writer, label, labelMatch, revdeps, hidden bool) Results { var results Results system := &installer.System{Database: LuetCfg.GetSystemDB(), Target: LuetCfg.GetSystem().Rootfs} var err error iMatches := pkg.Packages{} if label { iMatches, err = system.Database.FindPackageLabel(term) } else if labelMatch { iMatches, err = system.Database.FindPackageLabelMatch(term) } else { iMatches, err = system.Database.FindPackageMatch(term) } if err != nil { Fatal("Error: " + err.Error()) } for _, pack := range iMatches { if !revdeps { if !pack.IsHidden() || pack.IsHidden() && hidden { t.AppendRow(packageToRow("system", pack)) packageToList(l, "system", pack) f, _ := system.Database.GetPackageFiles(pack) results.Packages = append(results.Packages, PackageResult{ Name: pack.GetName(), Version: pack.GetVersion(), Category: pack.GetCategory(), Repository: "system", Hidden: pack.IsHidden(), Files: f, }) } } else { packs, _ := system.Database.GetRevdeps(pack) for _, revdep := range packs { if !revdep.IsHidden() || revdep.IsHidden() && hidden { t.AppendRow(packageToRow("system", pack)) packageToList(l, "system", pack) f, _ := system.Database.GetPackageFiles(revdep) results.Packages = append(results.Packages, PackageResult{ Name: revdep.GetName(), Version: revdep.GetVersion(), Category: revdep.GetCategory(), Repository: "system", Hidden: revdep.IsHidden(), Files: f, }) } } } } return results } func searchOnline(term string, l list.Writer, t table.Writer, label, labelMatch, revdeps, hidden bool) Results { var results Results inst := installer.NewLuetInstaller( installer.LuetInstallerOptions{ Concurrency: LuetCfg.GetGeneral().Concurrency, SolverOptions: *LuetCfg.GetSolverOptions(), PackageRepositories: LuetCfg.SystemRepositories, }, ) synced, err := inst.SyncRepositories() if err != nil { Fatal("Error: " + err.Error()) } Info("--- Search results (" + term + "): ---") matches := []installer.PackageMatch{} if label { matches = synced.SearchLabel(term) } else if labelMatch { matches = synced.SearchLabelMatch(term) } else { matches = synced.Search(term) } for _, m := range matches { if !revdeps { if !m.Package.IsHidden() || m.Package.IsHidden() && hidden { t.AppendRow(packageToRow(m.Repo.GetName(), m.Package)) packageToList(l, m.Repo.GetName(), m.Package) r := &PackageResult{ Name: m.Package.GetName(), Version: m.Package.GetVersion(), Category: m.Package.GetCategory(), Repository: m.Repo.GetName(), Hidden: m.Package.IsHidden(), } if m.Artifact != nil { r.Files = m.Artifact.Files } results.Packages = append(results.Packages, *r) } } else { packs, _ := m.Repo.GetTree().GetDatabase().GetRevdeps(m.Package) for _, revdep := range packs { if !revdep.IsHidden() || revdep.IsHidden() && hidden { t.AppendRow(packageToRow(m.Repo.GetName(), revdep)) packageToList(l, m.Repo.GetName(), revdep) r := &PackageResult{ Name: revdep.GetName(), Version: revdep.GetVersion(), Category: revdep.GetCategory(), Repository: m.Repo.GetName(), Hidden: revdep.IsHidden(), } if m.Artifact != nil { r.Files = m.Artifact.Files } results.Packages = append(results.Packages, *r) } } } } return results } func searchLocalFiles(term string, l list.Writer, t table.Writer) Results { var results Results Info("--- Search results (" + term + "): ---") matches, _ := LuetCfg.GetSystemDB().FindPackageByFile(term) for _, pack := range matches { t.AppendRow(packageToRow("system", pack)) packageToList(l, "system", pack) f, _ := LuetCfg.GetSystemDB().GetPackageFiles(pack) results.Packages = append(results.Packages, PackageResult{ Name: pack.GetName(), Version: pack.GetVersion(), Category: pack.GetCategory(), Repository: "system", Hidden: pack.IsHidden(), Files: f, }) } return results } func searchFiles(term string, l list.Writer, t table.Writer) Results { var results Results inst := installer.NewLuetInstaller( installer.LuetInstallerOptions{ Concurrency: LuetCfg.GetGeneral().Concurrency, SolverOptions: *LuetCfg.GetSolverOptions(), PackageRepositories: LuetCfg.SystemRepositories, }, ) synced, err := inst.SyncRepositories() if err != nil { Fatal("Error: " + err.Error()) } Info("--- Search results (" + term + "): ---") matches := []installer.PackageMatch{} matches = synced.SearchPackages(term, installer.FileSearch) for _, m := range matches { t.AppendRow(packageToRow(m.Repo.GetName(), m.Package)) packageToList(l, m.Repo.GetName(), m.Package) results.Packages = append(results.Packages, PackageResult{ Name: m.Package.GetName(), Version: m.Package.GetVersion(), Category: m.Package.GetCategory(), Repository: m.Repo.GetName(), Hidden: m.Package.IsHidden(), Files: m.Artifact.Files, }) } return results } var searchCmd = &cobra.Command{ Use: "search ", Short: "Search packages", Long: `Search for installed and available packages To search a package in the repositories: $ luet search To search a package and display results in a table (wide screens): $ luet search --table To look into the installed packages: $ luet search --installed Note: the regex argument is optional, if omitted implies "all" To search a package by label: $ luet search --by-label