From 233429bbeb298e14cf5bccd7fc08a48d2dce65b5 Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Sun, 28 Feb 2021 18:42:54 +0100 Subject: [PATCH] Allow to search by file Also make possible to retrieve the artifact when searching for matches between repositories list. This made possible to show the package list when calling `luet search`. --- cmd/search.go | 338 +++++++++++++++++++++------------ pkg/installer/interface.go | 2 + pkg/installer/repository.go | 62 ++++-- pkg/package/database.go | 1 + pkg/package/database_boltdb.go | 15 +- pkg/package/database_common.go | 32 +++- pkg/package/database_mem.go | 4 + 7 files changed, 312 insertions(+), 142 deletions(-) diff --git a/cmd/search.go b/cmd/search.go index c8c23755..c0cd6af3 100644 --- a/cmd/search.go +++ b/cmd/search.go @@ -30,12 +30,13 @@ import ( ) 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"` + 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 { @@ -64,6 +65,205 @@ func packageToList(l list.Writer, repo string, p pkg.Package) { 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 + + repos := installer.Repositories{} + for _, repo := range LuetCfg.SystemRepositories { + if !repo.Enable { + continue + } + r := installer.NewSystemRepository(repo) + repos = append(repos, r) + } + + inst := installer.NewLuetInstaller( + installer.LuetInstallerOptions{ + Concurrency: LuetCfg.GetGeneral().Concurrency, + SolverOptions: *LuetCfg.GetSolverOptions(), + }, + ) + inst.Repositories(repos) + synced, err := inst.SyncRepositories(false) + 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) + 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.GetFiles(), + }) + } + } 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) + results.Packages = append(results.Packages, + PackageResult{ + Name: revdep.GetName(), + Version: revdep.GetVersion(), + Category: revdep.GetCategory(), + Repository: m.Repo.GetName(), + Hidden: revdep.IsHidden(), + Files: m.Artifact.GetFiles(), + }) + } + } + } + } + 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 + + repos := installer.Repositories{} + for _, repo := range LuetCfg.SystemRepositories { + if !repo.Enable { + continue + } + r := installer.NewSystemRepository(repo) + repos = append(repos, r) + } + + inst := installer.NewLuetInstaller( + installer.LuetInstallerOptions{ + Concurrency: LuetCfg.GetGeneral().Concurrency, + SolverOptions: *LuetCfg.GetSolverOptions(), + }, + ) + inst.Repositories(repos) + synced, err := inst.SyncRepositories(false) + 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.GetFiles(), + }) + } + return results +} + var searchCmd = &cobra.Command{ Use: "search ", Short: "Search packages", @@ -128,6 +328,7 @@ Search can also return results in the terminal in different ways: as terminal ou searchWithLabelMatch, _ := cmd.Flags().GetBool("by-label-regex") revdeps, _ := cmd.Flags().GetBool("revdeps") tableMode, _ := cmd.Flags().GetBool("table") + files, _ := cmd.Flags().GetBool("files") out, _ := cmd.Flags().GetString("output") if out != "terminal" { @@ -144,121 +345,15 @@ Search can also return results in the terminal in different ways: as terminal ou t.AppendHeader(rows) Debug("Solver", LuetCfg.GetSolverOptions().CompactString()) - if !installed { - - repos := installer.Repositories{} - for _, repo := range LuetCfg.SystemRepositories { - if !repo.Enable { - continue - } - r := installer.NewSystemRepository(repo) - repos = append(repos, r) - } - - inst := installer.NewLuetInstaller( - installer.LuetInstallerOptions{ - Concurrency: LuetCfg.GetGeneral().Concurrency, - SolverOptions: *LuetCfg.GetSolverOptions(), - }, - ) - inst.Repositories(repos) - synced, err := inst.SyncRepositories(false) - if err != nil { - Fatal("Error: " + err.Error()) - } - - Info("--- Search results (" + args[0] + "): ---") - - matches := []installer.PackageMatch{} - if searchWithLabel { - matches = synced.SearchLabel(args[0]) - } else if searchWithLabelMatch { - matches = synced.SearchLabelMatch(args[0]) - } else { - matches = synced.Search(args[0]) - } - 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) - 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(), - }) - } - } 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) - results.Packages = append(results.Packages, - PackageResult{ - Name: revdep.GetName(), - Version: revdep.GetVersion(), - Category: revdep.GetCategory(), - Repository: m.Repo.GetName(), - Hidden: revdep.IsHidden(), - }) - } - } - } - } - } else { - - system := &installer.System{Database: LuetCfg.GetSystemDB(), Target: LuetCfg.GetSystem().Rootfs} - - var err error - iMatches := pkg.Packages{} - if searchWithLabel { - iMatches, err = system.Database.FindPackageLabel(args[0]) - } else if searchWithLabelMatch { - iMatches, err = system.Database.FindPackageLabelMatch(args[0]) - } else { - iMatches, err = system.Database.FindPackageMatch(args[0]) - } - - 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) - results.Packages = append(results.Packages, - PackageResult{ - Name: pack.GetName(), - Version: pack.GetVersion(), - Category: pack.GetCategory(), - Repository: "system", - Hidden: pack.IsHidden(), - }) - } - } 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) - results.Packages = append(results.Packages, - PackageResult{ - Name: revdep.GetName(), - Version: revdep.GetVersion(), - Category: revdep.GetCategory(), - Repository: "system", - Hidden: revdep.IsHidden(), - }) - } - } - } - } + switch { + case files && installed: + results = searchLocalFiles(args[0], l, t) + case files && !installed: + results = searchFiles(args[0], l, t) + case !installed: + results = searchOnline(args[0], l, t, searchWithLabel, searchWithLabelMatch, revdeps, hidden) + default: + results = searchLocally(args[0], l, t, searchWithLabel, searchWithLabelMatch, revdeps, hidden) } t.AppendFooter(rows) @@ -309,6 +404,7 @@ func init() { searchCmd.Flags().Bool("revdeps", false, "Search package reverse dependencies") searchCmd.Flags().Bool("hidden", false, "Include hidden packages") searchCmd.Flags().Bool("table", false, "show output in a table (wider screens)") + searchCmd.Flags().Bool("files", false, "Search between packages files") RootCmd.AddCommand(searchCmd) } diff --git a/pkg/installer/interface.go b/pkg/installer/interface.go index 49c48304..1c46aab8 100644 --- a/pkg/installer/interface.go +++ b/pkg/installer/interface.go @@ -74,4 +74,6 @@ type Repository interface { Serialize() (*LuetSystemRepositoryMetadata, LuetSystemRepositorySerialized) GetBackend() compiler.CompilerBackend SetBackend(b compiler.CompilerBackend) + FileSearch(pattern string) (pkg.Packages, error) + SearchArtefact(p pkg.Package) (compiler.Artifact, error) } diff --git a/pkg/installer/repository.go b/pkg/installer/repository.go index 9e29719e..07924734 100644 --- a/pkg/installer/repository.go +++ b/pkg/installer/repository.go @@ -21,6 +21,7 @@ import ( "os" "path" "path/filepath" + "regexp" "sort" "strconv" "strings" @@ -86,17 +87,17 @@ type LuetSystemRepositoryMetadata struct { Index []*compiler.PackageArtifact `json:"index,omitempty"` } -type LuetSearchModeType string +type LuetSearchModeType int const ( - SLabel LuetSearchModeType = "label" - SRegexPkg LuetSearchModeType = "regexPkg" - SRegexLabel LuetSearchModeType = "regexLabel" + SLabel = iota + SRegexPkg = iota + SRegexLabel = iota + FileSearch = iota ) type LuetSearchOpts struct { - Pattern string - Mode LuetSearchModeType + Mode LuetSearchModeType } func NewLuetSystemRepositoryMetadata(file string, removeFile bool) (*LuetSystemRepositoryMetadata, error) { @@ -406,6 +407,25 @@ func (r *LuetSystemRepository) SetPriority(n int) { r.LuetRepository.Priority = n } +// FileSearch search a pattern among the artifacts in a repository +func (r *LuetSystemRepository) FileSearch(pattern string) (pkg.Packages, error) { + var matches pkg.Packages + reg, err := regexp.Compile(pattern) + if err != nil { + return matches, err + } +ARTIFACT: + for _, a := range r.GetIndex() { + for _, f := range a.GetFiles() { + if reg.MatchString(f) { + matches = append(matches, a.GetCompileSpec().GetPackage()) + continue ARTIFACT + } + } + } + return matches, nil +} + func (r *LuetSystemRepository) GetName() string { return r.LuetRepository.Name } @@ -881,6 +901,16 @@ func (r *LuetSystemRepository) Client() Client { return nil } +func (r *LuetSystemRepository) SearchArtefact(p pkg.Package) (compiler.Artifact, error) { + for _, a := range r.GetIndex() { + if a.GetCompileSpec().GetPackage().Matches(p) { + return a, nil + } + } + + return nil, errors.New("Not found") +} + func (r *LuetSystemRepository) Sync(force bool) (Repository, error) { var repoUpdated bool = false var treefs, metafs string @@ -1129,8 +1159,9 @@ func (r Repositories) SyncDatabase(d pkg.PackageDatabase) { } type PackageMatch struct { - Repo Repository - Package pkg.Package + Repo Repository + Artifact compiler.Artifact + Package pkg.Package } func (re Repositories) PackageMatches(p pkg.Packages) []PackageMatch { @@ -1182,7 +1213,7 @@ PACKAGE: } -func (re Repositories) SearchPackages(p string, o LuetSearchOpts) []PackageMatch { +func (re Repositories) SearchPackages(p string, t LuetSearchModeType) []PackageMatch { sort.Sort(re) var matches []PackageMatch var err error @@ -1190,18 +1221,21 @@ func (re Repositories) SearchPackages(p string, o LuetSearchOpts) []PackageMatch for _, r := range re { var repoMatches pkg.Packages - switch o.Mode { + switch t { case SRegexPkg: repoMatches, err = r.GetTree().GetDatabase().FindPackageMatch(p) case SLabel: repoMatches, err = r.GetTree().GetDatabase().FindPackageLabel(p) case SRegexLabel: repoMatches, err = r.GetTree().GetDatabase().FindPackageLabelMatch(p) + case FileSearch: + repoMatches, err = r.FileSearch(p) } if err == nil && len(repoMatches) > 0 { for _, pack := range repoMatches { - matches = append(matches, PackageMatch{Package: pack, Repo: r}) + a, _ := r.SearchArtefact(pack) + matches = append(matches, PackageMatch{Package: pack, Repo: r, Artifact: a}) } } } @@ -1210,13 +1244,13 @@ func (re Repositories) SearchPackages(p string, o LuetSearchOpts) []PackageMatch } func (re Repositories) SearchLabelMatch(s string) []PackageMatch { - return re.SearchPackages(s, LuetSearchOpts{Pattern: s, Mode: SRegexLabel}) + return re.SearchPackages(s, SRegexLabel) } func (re Repositories) SearchLabel(s string) []PackageMatch { - return re.SearchPackages(s, LuetSearchOpts{Pattern: s, Mode: SLabel}) + return re.SearchPackages(s, SLabel) } func (re Repositories) Search(s string) []PackageMatch { - return re.SearchPackages(s, LuetSearchOpts{Pattern: s, Mode: SRegexPkg}) + return re.SearchPackages(s, SRegexPkg) } diff --git a/pkg/package/database.go b/pkg/package/database.go index b42b4dbc..882ecde5 100644 --- a/pkg/package/database.go +++ b/pkg/package/database.go @@ -52,6 +52,7 @@ type PackageSet interface { FindPackageLabel(labelKey string) (Packages, error) FindPackageLabelMatch(pattern string) (Packages, error) FindPackageMatch(pattern string) (Packages, error) + FindPackageByFile(pattern string) (Packages, error) } type PackageFile struct { diff --git a/pkg/package/database_boltdb.go b/pkg/package/database_boltdb.go index 3e096296..a5ed5d4c 100644 --- a/pkg/package/database_boltdb.go +++ b/pkg/package/database_boltdb.go @@ -436,9 +436,9 @@ func (db *BoltDatabase) FindPackageLabel(labelKey string) (Packages, error) { func (db *BoltDatabase) FindPackageLabelMatch(pattern string) (Packages, error) { var ans []Package - re := regexp.MustCompile(pattern) - if re == nil { - return nil, errors.New("Invalid regex " + pattern + "!") + re, err := regexp.Compile(pattern) + if err != nil { + return nil, errors.Wrap(err, "Invalid regex "+pattern+"!") } for _, pack := range db.World() { @@ -450,12 +450,15 @@ func (db *BoltDatabase) FindPackageLabelMatch(pattern string) (Packages, error) return Packages(ans), nil } +func (db *BoltDatabase) FindPackageByFile(pattern string) (Packages, error) { + return findPackageByFile(db, pattern) +} func (db *BoltDatabase) FindPackageMatch(pattern string) (Packages, error) { var ans []Package - re := regexp.MustCompile(pattern) - if re == nil { - return nil, errors.New("Invalid regex " + pattern + "!") + re, err := regexp.Compile(pattern) + if err != nil { + return nil, errors.Wrap(err, "Invalid regex "+pattern+"!") } for _, pack := range db.World() { diff --git a/pkg/package/database_common.go b/pkg/package/database_common.go index 0810257d..33dde553 100644 --- a/pkg/package/database_common.go +++ b/pkg/package/database_common.go @@ -15,7 +15,11 @@ package pkg -import "github.com/pkg/errors" +import ( + "regexp" + + "github.com/pkg/errors" +) func clone(src, dst PackageDatabase) error { for _, i := range src.World() { @@ -36,3 +40,29 @@ func copy(src PackageDatabase) (PackageDatabase, error) { return dst, nil } + +func findPackageByFile(db PackageDatabase, pattern string) (Packages, error) { + + var ans []Package + + re, err := regexp.Compile(pattern) + if err != nil { + return nil, errors.Wrap(err, "Invalid regex "+pattern+"!") + } + +PACKAGE: + for _, pack := range db.World() { + files, err := db.GetPackageFiles(pack) + if err == nil { + for _, f := range files { + if re.MatchString(f) { + ans = append(ans, pack) + continue PACKAGE + } + } + } + } + + return Packages(ans), nil + +} diff --git a/pkg/package/database_mem.go b/pkg/package/database_mem.go index a0d85ce4..01fc2aa8 100644 --- a/pkg/package/database_mem.go +++ b/pkg/package/database_mem.go @@ -560,3 +560,7 @@ func (db *InMemoryDatabase) FindPackageMatch(pattern string) (Packages, error) { return Packages(ans), nil } + +func (db *InMemoryDatabase) FindPackageByFile(pattern string) (Packages, error) { + return findPackageByFile(db, pattern) +}