Skip to content

Commit

Permalink
Merge pull request #85 from kellyma2/reducer-refactor
Browse files Browse the repository at this point in the history
Refactor reducer to enable testing
  • Loading branch information
kellyma2 authored Jan 17, 2025
2 parents b5efd4c + 3d25093 commit 3225b58
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 120 deletions.
9 changes: 1 addition & 8 deletions cmd/reduce.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ type reduceOpts struct {
in []string
repofiles []string
out string
lang string
nobest bool
arch string
baseSystem string
Expand All @@ -43,13 +42,7 @@ which allow reducing huge rpm repos to a smaller problem set for debugging, remo
return err
}
}
repo := reducer.NewRepoReducer(repos, reduceopts.in, reduceopts.lang, reduceopts.baseSystem, reduceopts.arch, ".bazeldnf")
logrus.Info("Loading packages.")
if err := repo.Load(); err != nil {
return err
}
logrus.Info("Reduction of involved packages.")
_, involved, err := repo.Resolve(required)
_, involved, err := reducer.Resolve(repos, reduceopts.in, reduceopts.baseSystem, reduceopts.arch, required)
if err != nil {
return err
}
Expand Down
9 changes: 1 addition & 8 deletions cmd/resolve.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (

type resolveOpts struct {
in []string
lang string
nobest bool
arch string
baseSystem string
Expand All @@ -40,13 +39,7 @@ func NewResolveCmd() *cobra.Command {
return err
}
}
repo := reducer.NewRepoReducer(repos, resolveopts.in, resolveopts.lang, resolveopts.baseSystem, resolveopts.arch, ".bazeldnf")
logrus.Info("Loading packages.")
if err := repo.Load(); err != nil {
return err
}
logrus.Info("Initial reduction of involved packages.")
matched, involved, err := repo.Resolve(required)
matched, involved, err := reducer.Resolve(repos, resolveopts.in, resolveopts.baseSystem, resolveopts.arch, required)
if err != nil {
return err
}
Expand Down
9 changes: 1 addition & 8 deletions cmd/rpmtree.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
)

type rpmtreeOpts struct {
lang string
nobest bool
arch string
baseSystem string
Expand Down Expand Up @@ -42,13 +41,7 @@ func NewRpmTreeCmd() *cobra.Command {
if err != nil {
return err
}
repoReducer := reducer.NewRepoReducer(repos, nil, rpmtreeopts.lang, rpmtreeopts.baseSystem, rpmtreeopts.arch, ".bazeldnf")
logrus.Info("Loading packages.")
if err := repoReducer.Load(); err != nil {
return err
}
logrus.Info("Initial reduction of involved packages.")
matched, involved, err := repoReducer.Resolve(required)
matched, involved, err := reducer.Resolve(repos, nil, rpmtreeopts.baseSystem, rpmtreeopts.arch, required)
if err != nil {
return err
}
Expand Down
1 change: 1 addition & 0 deletions pkg/reducer/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go_library(
name = "reducer",
srcs = [
"doc.go",
"loader.go",
"reducer.go",
],
importpath = "github.com/rmohr/bazeldnf/pkg/reducer",
Expand Down
126 changes: 126 additions & 0 deletions pkg/reducer/loader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package reducer

import (
"encoding/xml"
"os"
"strings"

"github.com/rmohr/bazeldnf/pkg/api"
"github.com/rmohr/bazeldnf/pkg/api/bazeldnf"
)

type RepoCache interface {
CurrentPrimaries(repos *bazeldnf.Repositories, arch string) (primaries []*api.Repository, err error)
}

type ReducerPackageLoader interface {
Load() (*packageInfo, error)
}

// packageInfo captures the package information required by the reducer
type packageInfo struct {
// the list of available packages
packages []api.Package

// mapping of provisions to a list of associated packages
provides map[string][]*api.Package
}

type RepoLoader struct {
repoFiles []string
arch string
architectures []string
repos *bazeldnf.Repositories
cacheHelper RepoCache
}

func (r RepoLoader) Load() (*packageInfo, error) {
packageInfo := &packageInfo{
packages: []api.Package{},
provides: map[string][]*api.Package{},
}

for _, rpmrepo := range r.repoFiles {
repoFile := &api.Repository{}
f, err := os.Open(rpmrepo)
if err != nil {
return packageInfo, err
}
defer f.Close()
err = xml.NewDecoder(f).Decode(repoFile)
if err != nil {
return packageInfo, err
}
for i, p := range repoFile.Packages {
if skip(p.Arch, r.architectures) {
continue
}
packageInfo.packages = append(packageInfo.packages, repoFile.Packages[i])
}
}

cachedRepos, err := r.cacheHelper.CurrentPrimaries(r.repos, r.arch)
if err != nil {
return packageInfo, err
}
for _, rpmrepo := range cachedRepos {
for i, p := range rpmrepo.Packages {
if skip(p.Arch, r.architectures) {
continue
}
packageInfo.packages = append(packageInfo.packages, rpmrepo.Packages[i])
}
}

for i, _ := range packageInfo.packages {
FixPackages(&packageInfo.packages[i])
}

for i, p := range packageInfo.packages {
requires := []api.Entry{}
for _, requirement := range p.Format.Requires.Entries {
if !strings.HasPrefix(requirement.Name, "(") {
requires = append(requires, requirement)
}
}
packageInfo.packages[i].Format.Requires.Entries = requires

for _, p := range p.Format.Provides.Entries {
packageInfo.provides[p.Name] = append(packageInfo.provides[p.Name], &packageInfo.packages[i])
}
for _, file := range p.Format.Files {
packageInfo.provides[file.Text] = append(packageInfo.provides[file.Text], &packageInfo.packages[i])
}
}

return packageInfo, nil
}

// FixPackages contains hacks which should probably not have to exist
func FixPackages(p *api.Package) {
// FIXME: This is not a proper modules support for python. We should properly resolve `alternative(python)` and
// not have to add such a hack. On the other hand this seems to have been reverted in fedora and only exists in centos stream.
if p.Name == "platform-python" {
p.Format.Provides.Entries = append(p.Format.Provides.Entries, api.Entry{
Name: "/usr/libexec/platform-python",
})
var requires []api.Entry
for _, entry := range p.Format.Requires.Entries {
if entry.Name != "/usr/libexec/platform-python" {
requires = append(requires, entry)
}
}
p.Format.Requires.Entries = requires
}
}

func skip(arch string, arches []string) bool {
skip := true
for _, a := range arches {
if a == arch {
skip = false
break
}
}
return skip
}
120 changes: 24 additions & 96 deletions pkg/reducer/reducer.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package reducer

import (
"encoding/xml"
"fmt"
"os"
"strings"

"github.com/rmohr/bazeldnf/pkg/api"
Expand All @@ -13,68 +11,17 @@ import (
)

type RepoReducer struct {
packages []api.Package
lang string
repoFiles []string
provides map[string][]*api.Package
packageInfo *packageInfo
implicitRequires []string
arch string
architectures []string
repos *bazeldnf.Repositories
cacheHelper *repo.CacheHelper
loader ReducerPackageLoader
}

func (r *RepoReducer) Load() error {
for _, rpmrepo := range r.repoFiles {
repoFile := &api.Repository{}
f, err := os.Open(rpmrepo)
if err != nil {
return err
}
defer f.Close()
err = xml.NewDecoder(f).Decode(repoFile)
if err != nil {
return err
}
for i, p := range repoFile.Packages {
if skip(p.Arch, r.architectures) {
continue
}
r.packages = append(r.packages, repoFile.Packages[i])
}
}
repos, err := r.cacheHelper.CurrentPrimaries(r.repos, r.arch)
packageInfo, err := r.loader.Load()
if err != nil {
return err
}
for _, rpmrepo := range repos {
for i, p := range rpmrepo.Packages {
if skip(p.Arch, r.architectures) {
continue
}
r.packages = append(r.packages, rpmrepo.Packages[i])
}
}
for i, _ := range r.packages {
FixPackages(&r.packages[i])
}

for i, p := range r.packages {
requires := []api.Entry{}
for _, requirement := range p.Format.Requires.Entries {
if !strings.HasPrefix(requirement.Name, "(") {
requires = append(requires, requirement)
}
}
r.packages[i].Format.Requires.Entries = requires

for _, provides := range p.Format.Provides.Entries {
r.provides[provides.Name] = append(r.provides[provides.Name], &r.packages[i])
}
for _, file := range p.Format.Files {
r.provides[file.Text] = append(r.provides[file.Text], &r.packages[i])
}
}
r.packageInfo = packageInfo
return nil
}

Expand All @@ -86,15 +33,15 @@ func (r *RepoReducer) Resolve(packages []string) (matched []string, involved []*
found := false
name := ""
var candidates []*api.Package
for i, p := range r.packages {
for i, p := range r.packageInfo.packages {
if strings.HasPrefix(p.String(), req) {
if strings.HasPrefix(req, p.Name) {
if !found || len(p.Name) < len(name) {
candidates = []*api.Package{&r.packages[i]}
candidates = []*api.Package{&r.packageInfo.packages[i]}
name = p.Name
found = true
} else if p.Name == name {
candidates = append(candidates, &r.packages[i])
candidates = append(candidates, &r.packageInfo.packages[i])
}
}
}
Expand Down Expand Up @@ -159,7 +106,7 @@ func (r *RepoReducer) Resolve(packages []string) (matched []string, involved []*

func (r *RepoReducer) requires(p *api.Package) (wants []*api.Package) {
for _, requires := range p.Format.Requires.Entries {
if val, exists := r.provides[requires.Name]; exists {
if val, exists := r.packageInfo.provides[requires.Name]; exists {

var packages []string
for _, p := range val {
Expand All @@ -174,45 +121,26 @@ func (r *RepoReducer) requires(p *api.Package) (wants []*api.Package) {
return wants
}

func NewRepoReducer(repos *bazeldnf.Repositories, repoFiles []string, lang string, baseSystem string, arch string, cachDir string) *RepoReducer {
func NewRepoReducer(repos *bazeldnf.Repositories, repoFiles []string, baseSystem string, arch string, cachDir string) *RepoReducer {
return &RepoReducer{
packages: nil,
lang: lang,
packageInfo: nil,
implicitRequires: []string{baseSystem},
repoFiles: repoFiles,
provides: map[string][]*api.Package{},
architectures: []string{"noarch", arch},
arch: arch,
repos: repos,
cacheHelper: &repo.CacheHelper{CacheDir: cachDir},
loader: RepoLoader{
repoFiles: repoFiles,
architectures: []string{"noarch", arch},
arch: arch,
repos: repos,
cacheHelper: &repo.CacheHelper{CacheDir: cachDir},
},
}
}

func skip(arch string, arches []string) bool {
skip := true
for _, a := range arches {
if a == arch {
skip = false
break
}
}
return skip
}

// FixPackages contains hacks which should probably not have to exist
func FixPackages(p *api.Package) {
// FIXME: This is not a proper modules support for python. We should properly resolve `alternative(python)` and
// not have to add such a hack. On the other hand this seems to have been reverted in fedora and only exists in centos stream.
if p.Name == "platform-python" {
p.Format.Provides.Entries = append(p.Format.Provides.Entries, api.Entry{
Name: "/usr/libexec/platform-python",
})
var requires []api.Entry
for _, entry := range p.Format.Requires.Entries {
if entry.Name != "/usr/libexec/platform-python" {
requires = append(requires, entry)
}
}
p.Format.Requires.Entries = requires
func Resolve(repos *bazeldnf.Repositories, repoFiles []string, baseSystem, arch string, packages []string) (matched []string, involved []*api.Package, err error) {
repoReducer := NewRepoReducer(repos, repoFiles, baseSystem, arch, ".bazeldnf")
logrus.Info("Loading packages.")
if err := repoReducer.Load(); err != nil {
return nil, nil, err
}
logrus.Info("Initial reduction of involved packages.")
return repoReducer.Resolve(packages)
}

0 comments on commit 3225b58

Please sign in to comment.