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`.
This commit is contained in:
Ettore Di Giacinto 2021-02-28 18:42:54 +01:00
parent d84f6b31fd
commit 233429bbeb
7 changed files with 312 additions and 142 deletions

View File

@ -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 <term>",
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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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 {

View File

@ -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() {

View File

@ -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
}

View File

@ -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)
}