dnfjson: use repo config hash as repo ID
Defined a Hash() method on rpmmd.RepoConfig that calculates a SHA-256 ID
for a repository based on its configuration. Identical configurations
should produce the same ID. The Name and ImageTypeTags of a repository
aren't taken into account. These attributes affect a repository's
functional configuration.
This ID lets us change the way we handle repository configurations in a
few places:
- Preparing the depsolve job arguments is simpler since we have
predictable IDs for the repository configurations. We don't need to
rely on the index of a RepoConfig in a list to identify or access it,
which prevented us from building a list of all repository
configurations, since we needed them to be placed in the list in a
certain order.
- Associating packages from the depsolve result with the repository
configuration (in depsToRPMMD) no longer relies on an ID string
converted from and back to an integer index. Repositories define
their own IDs.
- Tests are a bit messier now but the changes simplify the main code, so
it's an acceptable trade-off.
- Fixtures need to change based on the repository configuration for
the test.
- We need to calculate the ID for the repository configuration for
the temporary file server URL.
This commit is contained in:
parent
46e4f0cf5e
commit
1c4d8f9988
6 changed files with 139 additions and 247 deletions
|
|
@ -16,13 +16,11 @@ package dnfjson
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"github.com/osbuild/osbuild-composer/internal/rhsm"
|
||||
"github.com/osbuild/osbuild-composer/internal/rpmmd"
|
||||
|
|
@ -98,7 +96,7 @@ func Depsolve(pkgSets []rpmmd.PackageSet, repos []rpmmd.RepoConfig, psRepos [][]
|
|||
// transactions in a chain. It returns a list of all packages (with solved
|
||||
// dependencies) that will be installed into the system.
|
||||
func (s *Solver) Depsolve(pkgSets []rpmmd.PackageSet, repos []rpmmd.RepoConfig, psRepos [][]rpmmd.RepoConfig) (*DepsolveResult, error) {
|
||||
req, err := s.makeDepsolveRequest(pkgSets, repos, psRepos)
|
||||
req, repoMap, err := s.makeDepsolveRequest(pkgSets, repos, psRepos)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -112,7 +110,7 @@ func (s *Solver) Depsolve(pkgSets []rpmmd.PackageSet, repos []rpmmd.RepoConfig,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return resultToPublic(result, repos), nil
|
||||
return resultToPublic(result, repoMap), nil
|
||||
}
|
||||
|
||||
func FetchMetadata(repos []rpmmd.RepoConfig, modulePlatformID string, releaseVer string, arch string, cacheDir string) (*FetchMetadataResult, error) {
|
||||
|
|
@ -143,8 +141,8 @@ func (s *Solver) FetchMetadata(repos []rpmmd.RepoConfig) (*FetchMetadataResult,
|
|||
})
|
||||
metadata.Packages = pkgs
|
||||
namedChecksums := make(map[string]string)
|
||||
for i, repo := range repos {
|
||||
namedChecksums[repo.Name] = metadata.Checksums[strconv.Itoa(i)]
|
||||
for _, repo := range repos {
|
||||
namedChecksums[repo.Name] = metadata.Checksums[repo.Hash()]
|
||||
}
|
||||
metadata.Checksums = namedChecksums
|
||||
return metadata, nil
|
||||
|
|
@ -153,9 +151,8 @@ func (s *Solver) FetchMetadata(repos []rpmmd.RepoConfig) (*FetchMetadataResult,
|
|||
func (s *Solver) reposFromRPMMD(rpmRepos []rpmmd.RepoConfig) ([]repoConfig, error) {
|
||||
dnfRepos := make([]repoConfig, len(rpmRepos))
|
||||
for idx, rr := range rpmRepos {
|
||||
id := strconv.Itoa(idx)
|
||||
dr := repoConfig{
|
||||
ID: id,
|
||||
ID: rr.Hash(),
|
||||
Name: rr.Name,
|
||||
BaseURL: rr.BaseURL,
|
||||
Metalink: rr.Metalink,
|
||||
|
|
@ -175,7 +172,6 @@ func (s *Solver) reposFromRPMMD(rpmRepos []rpmmd.RepoConfig) ([]repoConfig, erro
|
|||
dr.SSLCACert = secrets.SSLCACert
|
||||
dr.SSLClientKey = secrets.SSLClientKey
|
||||
dr.SSLClientCert = secrets.SSLClientCert
|
||||
|
||||
}
|
||||
dnfRepos[idx] = dr
|
||||
}
|
||||
|
|
@ -198,12 +194,6 @@ type repoConfig struct {
|
|||
MetadataExpire string `json:"metadata_expire,omitempty"`
|
||||
}
|
||||
|
||||
// Calculate a hash that uniquely represents this repository configuration.
|
||||
// The ID and Name fields are not considered in the calculation.
|
||||
func (r *repoConfig) hash() string {
|
||||
return fmt.Sprintf("%x", sha1.Sum([]byte(r.BaseURL+r.Metalink+r.MirrorList+r.GPGKey+fmt.Sprintf("%T", r.IgnoreSSL)+r.SSLCACert+r.SSLClientKey+r.SSLClientCert+r.MetadataExpire)))
|
||||
}
|
||||
|
||||
// Helper function for creating a depsolve request payload.
|
||||
// The request defines a sequence of transactions, each depsolving one of the
|
||||
// elements of `pkgSets` in the order they appear. The `repoConfigs` are used
|
||||
|
|
@ -215,30 +205,36 @@ func (r *repoConfig) hash() string {
|
|||
// NOTE: Due to implementation limitations of DNF and dnf-json, each package set
|
||||
// in the chain must use all of the repositories used by its predecessor.
|
||||
// An error is returned if this requirement is not met.
|
||||
func (s *Solver) makeDepsolveRequest(pkgSets []rpmmd.PackageSet, repoConfigs []rpmmd.RepoConfig, pkgsetsRepos [][]rpmmd.RepoConfig) (*Request, error) {
|
||||
func (s *Solver) makeDepsolveRequest(pkgSets []rpmmd.PackageSet, repoConfigs []rpmmd.RepoConfig, pkgsetsRepos [][]rpmmd.RepoConfig) (*Request, map[string]rpmmd.RepoConfig, error) {
|
||||
// pkgsetsRepos must either be nil (empty) or the same length as the pkgSets array
|
||||
if len(pkgsetsRepos) > 0 && len(pkgSets) != len(pkgsetsRepos) {
|
||||
return nil, fmt.Errorf("depsolve: the number of package set repository configurations (%d) does not match the number of package sets (%d)", len(pkgsetsRepos), len(pkgSets))
|
||||
return nil, nil, fmt.Errorf("depsolve: the number of package set repository configurations (%d) does not match the number of package sets (%d)", len(pkgsetsRepos), len(pkgSets))
|
||||
}
|
||||
|
||||
// TODO: collect and arrange repositories into jobs before converting to
|
||||
// avoid unnecessary multiple conversion of the same struct
|
||||
baseRepos, err := s.reposFromRPMMD(repoConfigs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
allRepos := make([]repoConfig, len(baseRepos))
|
||||
copy(allRepos, baseRepos)
|
||||
// keep a map of repos to IDs (indices) for quick lookups
|
||||
// (basically, the inverse of the allRepos slice)
|
||||
reposIDMap := make(map[string]int)
|
||||
// dedupe repository configurations but maintain order
|
||||
// the order in which repositories are added to the request affects the
|
||||
// order of the dependencies in the result
|
||||
repos := make([]rpmmd.RepoConfig, 0)
|
||||
rpmRepoMap := make(map[string]rpmmd.RepoConfig)
|
||||
|
||||
// These repo IDs will be used for all transactions in the chain
|
||||
baseRepoIDs := make([]int, len(repoConfigs))
|
||||
for idx, baseRepo := range baseRepos {
|
||||
baseRepoIDs[idx] = idx
|
||||
reposIDMap[baseRepo.hash()] = idx
|
||||
baseRepoIDs := make([]string, len(repoConfigs))
|
||||
for idx, repo := range repoConfigs {
|
||||
id := repo.Hash()
|
||||
rpmRepoMap[id] = repo
|
||||
baseRepoIDs[idx] = id
|
||||
repos = append(repos, repo)
|
||||
}
|
||||
|
||||
// extra repositories defined for specific package sets
|
||||
for _, jobRepos := range pkgsetsRepos {
|
||||
for _, repo := range jobRepos {
|
||||
id := repo.Hash()
|
||||
if _, ok := rpmRepoMap[id]; !ok {
|
||||
rpmRepoMap[id] = repo
|
||||
repos = append(repos, repo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
transactions := make([]transactionArgs, len(pkgSets))
|
||||
|
|
@ -254,48 +250,32 @@ func (s *Solver) makeDepsolveRequest(pkgSets []rpmmd.PackageSet, repoConfigs []r
|
|||
continue
|
||||
}
|
||||
|
||||
// collect repositories specific to the depsolve job
|
||||
dsRepos, err := s.reposFromRPMMD(pkgsetsRepos[dsIdx])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
for _, jobRepo := range pkgsetsRepos[dsIdx] {
|
||||
transactions[dsIdx].RepoIDs = append(transactions[dsIdx].RepoIDs, jobRepo.Hash())
|
||||
}
|
||||
|
||||
for _, dsRepo := range dsRepos {
|
||||
if repoIdx, ok := reposIDMap[dsRepo.hash()]; ok {
|
||||
// repo config already in in allRepos: append index
|
||||
transactions[dsIdx].RepoIDs = append(transactions[dsIdx].RepoIDs, repoIdx)
|
||||
} else {
|
||||
// new repo config: add to allRepos and append new index
|
||||
newIdx := len(reposIDMap)
|
||||
// fix repo ID
|
||||
dsRepo.ID = strconv.Itoa(newIdx)
|
||||
reposIDMap[dsRepo.hash()] = newIdx
|
||||
allRepos = append(allRepos, dsRepo)
|
||||
transactions[dsIdx].RepoIDs = append(transactions[dsIdx].RepoIDs, newIdx)
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the slice of repo IDs to make it easier to compare
|
||||
sort.Ints(transactions[dsIdx].RepoIDs)
|
||||
|
||||
// If more than one transaction, ensure that the transaction uses
|
||||
// all of the repos from its predecessor
|
||||
if dsIdx > 0 {
|
||||
prevRepoIDs := transactions[dsIdx-1].RepoIDs
|
||||
if len(transactions[dsIdx].RepoIDs) < len(prevRepoIDs) {
|
||||
return nil, fmt.Errorf("chained packageSet %d does not use all of the repos used by its predecessor", dsIdx)
|
||||
return nil, nil, fmt.Errorf("chained packageSet %d does not use all of the repos used by its predecessor", dsIdx)
|
||||
}
|
||||
|
||||
for idx, repoID := range prevRepoIDs {
|
||||
if repoID != transactions[dsIdx].RepoIDs[idx] {
|
||||
return nil, fmt.Errorf("chained packageSet %d does not use all of the repos used by its predecessor", dsIdx)
|
||||
return nil, nil, fmt.Errorf("chained packageSet %d does not use all of the repos used by its predecessor", dsIdx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dnfRepoMap, err := s.reposFromRPMMD(repos)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
args := arguments{
|
||||
Repos: allRepos,
|
||||
Repos: dnfRepoMap,
|
||||
Transactions: transactions,
|
||||
}
|
||||
|
||||
|
|
@ -307,7 +287,7 @@ func (s *Solver) makeDepsolveRequest(pkgSets []rpmmd.PackageSet, repoConfigs []r
|
|||
Arguments: args,
|
||||
}
|
||||
|
||||
return &req, nil
|
||||
return &req, rpmRepoMap, nil
|
||||
}
|
||||
|
||||
// Helper function for creating a dump request payload
|
||||
|
|
@ -329,7 +309,7 @@ func (s *Solver) makeDumpRequest(repos []rpmmd.RepoConfig) (*Request, error) {
|
|||
}
|
||||
|
||||
// convert an internal depsolveResult to a public DepsolveResult.
|
||||
func resultToPublic(result *depsolveResult, repos []rpmmd.RepoConfig) *DepsolveResult {
|
||||
func resultToPublic(result *depsolveResult, repos map[string]rpmmd.RepoConfig) *DepsolveResult {
|
||||
return &DepsolveResult{
|
||||
Checksums: result.Checksums,
|
||||
Dependencies: depsToRPMMD(result.Dependencies, repos),
|
||||
|
|
@ -338,14 +318,13 @@ func resultToPublic(result *depsolveResult, repos []rpmmd.RepoConfig) *DepsolveR
|
|||
|
||||
// convert internal a list of PackageSpecs to the rpmmd equivalent and attach
|
||||
// key and subscription information based on the repository configs.
|
||||
func depsToRPMMD(dependencies []PackageSpec, repos []rpmmd.RepoConfig) []rpmmd.PackageSpec {
|
||||
func depsToRPMMD(dependencies []PackageSpec, repos map[string]rpmmd.RepoConfig) []rpmmd.PackageSpec {
|
||||
rpmDependencies := make([]rpmmd.PackageSpec, len(dependencies))
|
||||
for i, dep := range dependencies {
|
||||
id, err := strconv.Atoi(dep.RepoID)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
repo, ok := repos[dep.RepoID]
|
||||
if !ok {
|
||||
panic("dependency repo ID not found in repositories")
|
||||
}
|
||||
repo := repos[id]
|
||||
dep := dependencies[i]
|
||||
rpmDependencies[i].Name = dep.Name
|
||||
rpmDependencies[i].Epoch = dep.Epoch
|
||||
|
|
@ -397,7 +376,7 @@ type transactionArgs struct {
|
|||
ExcludeSpecs []string `json:"exclude-specs"`
|
||||
|
||||
// IDs of repositories to use for this depsolve
|
||||
RepoIDs []int `json:"repo-ids"`
|
||||
RepoIDs []string `json:"repo-ids"`
|
||||
}
|
||||
|
||||
// Private version of the depsolve result. Uses a slightly different
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ func TestDepsolver(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
exp := expectedResult(s.Server.URL)
|
||||
exp := expectedResult(s.RepoConfig)
|
||||
assert.Equal(deps, exp)
|
||||
}
|
||||
|
||||
|
|
@ -39,7 +39,7 @@ func TestDepsolver(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
exp := expectedResult(s.Server.URL)
|
||||
exp := expectedResult(s.RepoConfig)
|
||||
assert.Equal(deps, exp)
|
||||
}
|
||||
|
||||
|
|
@ -52,12 +52,29 @@ func TestDepsolver(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
exp := expectedResult(s.Server.URL)
|
||||
exp := expectedResult(s.RepoConfig)
|
||||
assert.Equal(deps, exp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMakeDepsolveRequest(t *testing.T) {
|
||||
|
||||
baseOS := rpmmd.RepoConfig{
|
||||
Name: "baseos",
|
||||
BaseURL: "https://example.org/baseos",
|
||||
}
|
||||
appstream := rpmmd.RepoConfig{
|
||||
Name: "appstream",
|
||||
BaseURL: "https://example.org/appstream",
|
||||
}
|
||||
userRepo := rpmmd.RepoConfig{
|
||||
Name: "user-repo",
|
||||
BaseURL: "https://example.org/user-repo",
|
||||
}
|
||||
userRepo2 := rpmmd.RepoConfig{
|
||||
Name: "user-repo-2",
|
||||
BaseURL: "https://example.org/user-repo-2",
|
||||
}
|
||||
tests := []struct {
|
||||
packageSets []rpmmd.PackageSet
|
||||
repos []rpmmd.RepoConfig
|
||||
|
|
@ -75,30 +92,24 @@ func TestMakeDepsolveRequest(t *testing.T) {
|
|||
},
|
||||
},
|
||||
repos: []rpmmd.RepoConfig{
|
||||
{
|
||||
Name: "baseos",
|
||||
BaseURL: "https://example.org/baseos",
|
||||
},
|
||||
{
|
||||
Name: "appstream",
|
||||
BaseURL: "https://example.org/appstream",
|
||||
},
|
||||
baseOS,
|
||||
appstream,
|
||||
},
|
||||
args: []transactionArgs{
|
||||
{
|
||||
PackageSpecs: []string{"pkg1"},
|
||||
ExcludeSpecs: []string{"pkg2"},
|
||||
RepoIDs: []int{0, 1},
|
||||
RepoIDs: []string{baseOS.Hash(), appstream.Hash()},
|
||||
},
|
||||
},
|
||||
wantRepos: []repoConfig{
|
||||
{
|
||||
ID: "0",
|
||||
ID: baseOS.Hash(),
|
||||
Name: "baseos",
|
||||
BaseURL: "https://example.org/baseos",
|
||||
},
|
||||
{
|
||||
ID: "1",
|
||||
ID: appstream.Hash(),
|
||||
Name: "appstream",
|
||||
BaseURL: "https://example.org/appstream",
|
||||
},
|
||||
|
|
@ -115,49 +126,32 @@ func TestMakeDepsolveRequest(t *testing.T) {
|
|||
Include: []string{"pkg3"},
|
||||
},
|
||||
},
|
||||
repos: []rpmmd.RepoConfig{
|
||||
{
|
||||
Name: "baseos",
|
||||
BaseURL: "https://example.org/baseos",
|
||||
},
|
||||
{
|
||||
Name: "appstream",
|
||||
BaseURL: "https://example.org/appstream",
|
||||
},
|
||||
},
|
||||
packageSetsRepos: [][]rpmmd.RepoConfig{
|
||||
nil,
|
||||
{
|
||||
{
|
||||
Name: "user-repo",
|
||||
BaseURL: "https://example.org/user-repo",
|
||||
},
|
||||
},
|
||||
},
|
||||
repos: []rpmmd.RepoConfig{baseOS, appstream},
|
||||
packageSetsRepos: [][]rpmmd.RepoConfig{nil, {userRepo}},
|
||||
args: []transactionArgs{
|
||||
{
|
||||
PackageSpecs: []string{"pkg1"},
|
||||
ExcludeSpecs: []string{"pkg2"},
|
||||
RepoIDs: []int{0, 1},
|
||||
RepoIDs: []string{baseOS.Hash(), appstream.Hash()},
|
||||
},
|
||||
{
|
||||
PackageSpecs: []string{"pkg3"},
|
||||
RepoIDs: []int{0, 1, 2},
|
||||
RepoIDs: []string{baseOS.Hash(), appstream.Hash(), userRepo.Hash()},
|
||||
},
|
||||
},
|
||||
wantRepos: []repoConfig{
|
||||
{
|
||||
ID: "0",
|
||||
ID: baseOS.Hash(),
|
||||
Name: "baseos",
|
||||
BaseURL: "https://example.org/baseos",
|
||||
},
|
||||
{
|
||||
ID: "1",
|
||||
ID: appstream.Hash(),
|
||||
Name: "appstream",
|
||||
BaseURL: "https://example.org/appstream",
|
||||
},
|
||||
{
|
||||
ID: "2",
|
||||
ID: userRepo.Hash(),
|
||||
Name: "user-repo",
|
||||
BaseURL: "https://example.org/user-repo",
|
||||
},
|
||||
|
|
@ -174,35 +168,26 @@ func TestMakeDepsolveRequest(t *testing.T) {
|
|||
Include: []string{"pkg3"},
|
||||
},
|
||||
},
|
||||
repos: []rpmmd.RepoConfig{
|
||||
{
|
||||
Name: "baseos",
|
||||
BaseURL: "https://example.org/baseos",
|
||||
},
|
||||
{
|
||||
Name: "appstream",
|
||||
BaseURL: "https://example.org/appstream",
|
||||
},
|
||||
},
|
||||
repos: []rpmmd.RepoConfig{baseOS, appstream},
|
||||
args: []transactionArgs{
|
||||
{
|
||||
PackageSpecs: []string{"pkg1"},
|
||||
ExcludeSpecs: []string{"pkg2"},
|
||||
RepoIDs: []int{0, 1},
|
||||
RepoIDs: []string{baseOS.Hash(), appstream.Hash()},
|
||||
},
|
||||
{
|
||||
PackageSpecs: []string{"pkg3"},
|
||||
RepoIDs: []int{0, 1},
|
||||
RepoIDs: []string{baseOS.Hash(), appstream.Hash()},
|
||||
},
|
||||
},
|
||||
wantRepos: []repoConfig{
|
||||
{
|
||||
ID: "0",
|
||||
ID: baseOS.Hash(),
|
||||
Name: "baseos",
|
||||
BaseURL: "https://example.org/baseos",
|
||||
},
|
||||
{
|
||||
ID: "1",
|
||||
ID: appstream.Hash(),
|
||||
Name: "appstream",
|
||||
BaseURL: "https://example.org/appstream",
|
||||
},
|
||||
|
|
@ -222,59 +207,36 @@ func TestMakeDepsolveRequest(t *testing.T) {
|
|||
Include: []string{"pkg4"},
|
||||
},
|
||||
},
|
||||
repos: []rpmmd.RepoConfig{
|
||||
{
|
||||
Name: "baseos",
|
||||
BaseURL: "https://example.org/baseos",
|
||||
},
|
||||
{
|
||||
Name: "appstream",
|
||||
BaseURL: "https://example.org/appstream",
|
||||
},
|
||||
},
|
||||
packageSetsRepos: [][]rpmmd.RepoConfig{
|
||||
nil,
|
||||
{
|
||||
{
|
||||
Name: "user-repo",
|
||||
BaseURL: "https://example.org/user-repo",
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
Name: "user-repo",
|
||||
BaseURL: "https://example.org/user-repo",
|
||||
},
|
||||
},
|
||||
},
|
||||
repos: []rpmmd.RepoConfig{baseOS, appstream},
|
||||
packageSetsRepos: [][]rpmmd.RepoConfig{nil, {userRepo}, {userRepo}},
|
||||
args: []transactionArgs{
|
||||
{
|
||||
PackageSpecs: []string{"pkg1"},
|
||||
ExcludeSpecs: []string{"pkg2"},
|
||||
RepoIDs: []int{0, 1},
|
||||
RepoIDs: []string{baseOS.Hash(), appstream.Hash()},
|
||||
},
|
||||
{
|
||||
PackageSpecs: []string{"pkg3"},
|
||||
RepoIDs: []int{0, 1, 2},
|
||||
RepoIDs: []string{baseOS.Hash(), appstream.Hash(), userRepo.Hash()},
|
||||
},
|
||||
{
|
||||
PackageSpecs: []string{"pkg4"},
|
||||
RepoIDs: []int{0, 1, 2},
|
||||
RepoIDs: []string{baseOS.Hash(), appstream.Hash(), userRepo.Hash()},
|
||||
},
|
||||
},
|
||||
wantRepos: []repoConfig{
|
||||
{
|
||||
ID: "0",
|
||||
ID: baseOS.Hash(),
|
||||
Name: "baseos",
|
||||
BaseURL: "https://example.org/baseos",
|
||||
},
|
||||
{
|
||||
ID: "1",
|
||||
ID: appstream.Hash(),
|
||||
Name: "appstream",
|
||||
BaseURL: "https://example.org/appstream",
|
||||
},
|
||||
{
|
||||
ID: "2",
|
||||
ID: userRepo.Hash(),
|
||||
Name: "user-repo",
|
||||
BaseURL: "https://example.org/user-repo",
|
||||
},
|
||||
|
|
@ -295,68 +257,41 @@ func TestMakeDepsolveRequest(t *testing.T) {
|
|||
Include: []string{"pkg4"},
|
||||
},
|
||||
},
|
||||
repos: []rpmmd.RepoConfig{
|
||||
{
|
||||
Name: "baseos",
|
||||
BaseURL: "https://example.org/baseos",
|
||||
},
|
||||
{
|
||||
Name: "appstream",
|
||||
BaseURL: "https://example.org/appstream",
|
||||
},
|
||||
},
|
||||
packageSetsRepos: [][]rpmmd.RepoConfig{
|
||||
nil,
|
||||
{
|
||||
{
|
||||
Name: "user-repo",
|
||||
BaseURL: "https://example.org/user-repo",
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
Name: "user-repo",
|
||||
BaseURL: "https://example.org/user-repo",
|
||||
},
|
||||
{
|
||||
Name: "user-repo-2",
|
||||
BaseURL: "https://example.org/user-repo-2",
|
||||
},
|
||||
},
|
||||
},
|
||||
repos: []rpmmd.RepoConfig{baseOS, appstream},
|
||||
packageSetsRepos: [][]rpmmd.RepoConfig{nil, {userRepo}, {userRepo, userRepo2}},
|
||||
args: []transactionArgs{
|
||||
{
|
||||
PackageSpecs: []string{"pkg1"},
|
||||
ExcludeSpecs: []string{"pkg2"},
|
||||
RepoIDs: []int{0, 1},
|
||||
RepoIDs: []string{baseOS.Hash(), appstream.Hash()},
|
||||
},
|
||||
{
|
||||
PackageSpecs: []string{"pkg3"},
|
||||
RepoIDs: []int{0, 1, 2},
|
||||
RepoIDs: []string{baseOS.Hash(), appstream.Hash(), userRepo.Hash()},
|
||||
},
|
||||
{
|
||||
PackageSpecs: []string{"pkg4"},
|
||||
RepoIDs: []int{0, 1, 2, 3},
|
||||
RepoIDs: []string{baseOS.Hash(), appstream.Hash(), userRepo.Hash(), userRepo2.Hash()},
|
||||
},
|
||||
},
|
||||
wantRepos: []repoConfig{
|
||||
{
|
||||
ID: "0",
|
||||
ID: baseOS.Hash(),
|
||||
Name: "baseos",
|
||||
BaseURL: "https://example.org/baseos",
|
||||
},
|
||||
{
|
||||
ID: "1",
|
||||
ID: appstream.Hash(),
|
||||
Name: "appstream",
|
||||
BaseURL: "https://example.org/appstream",
|
||||
},
|
||||
{
|
||||
ID: "2",
|
||||
ID: userRepo.Hash(),
|
||||
Name: "user-repo",
|
||||
BaseURL: "https://example.org/user-repo",
|
||||
},
|
||||
{
|
||||
ID: "3",
|
||||
ID: userRepo2.Hash(),
|
||||
Name: "user-repo-2",
|
||||
BaseURL: "https://example.org/user-repo-2",
|
||||
},
|
||||
|
|
@ -376,32 +311,9 @@ func TestMakeDepsolveRequest(t *testing.T) {
|
|||
Include: []string{"pkg4"},
|
||||
},
|
||||
},
|
||||
repos: []rpmmd.RepoConfig{
|
||||
{
|
||||
Name: "baseos",
|
||||
BaseURL: "https://example.org/baseos",
|
||||
},
|
||||
{
|
||||
Name: "appstream",
|
||||
BaseURL: "https://example.org/appstream",
|
||||
},
|
||||
},
|
||||
packageSetsRepos: [][]rpmmd.RepoConfig{
|
||||
nil,
|
||||
{
|
||||
{
|
||||
Name: "user-repo",
|
||||
BaseURL: "https://example.org/user-repo",
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
Name: "user-repo2",
|
||||
BaseURL: "https://example.org/user-repo2",
|
||||
},
|
||||
},
|
||||
},
|
||||
err: true,
|
||||
repos: []rpmmd.RepoConfig{baseOS, appstream},
|
||||
packageSetsRepos: [][]rpmmd.RepoConfig{nil, {userRepo}, {userRepo2}},
|
||||
err: true,
|
||||
},
|
||||
// Error: 3 transactions but only 1 packageSetsRepos
|
||||
{
|
||||
|
|
@ -417,35 +329,15 @@ func TestMakeDepsolveRequest(t *testing.T) {
|
|||
Include: []string{"pkg4"},
|
||||
},
|
||||
},
|
||||
repos: []rpmmd.RepoConfig{
|
||||
{
|
||||
Name: "baseos",
|
||||
BaseURL: "https://example.org/baseos",
|
||||
},
|
||||
{
|
||||
Name: "appstream",
|
||||
BaseURL: "https://example.org/appstream",
|
||||
},
|
||||
},
|
||||
packageSetsRepos: [][]rpmmd.RepoConfig{
|
||||
{
|
||||
{
|
||||
Name: "user-repo",
|
||||
BaseURL: "https://example.org/user-repo",
|
||||
},
|
||||
{
|
||||
Name: "user-repo2",
|
||||
BaseURL: "https://example.org/user-repo2",
|
||||
},
|
||||
},
|
||||
},
|
||||
err: true,
|
||||
repos: []rpmmd.RepoConfig{baseOS, appstream},
|
||||
packageSetsRepos: [][]rpmmd.RepoConfig{{userRepo, userRepo2}},
|
||||
err: true,
|
||||
},
|
||||
}
|
||||
solver := NewSolver("", "", "", "")
|
||||
for idx, tt := range tests {
|
||||
t.Run(fmt.Sprintf("%d", idx), func(t *testing.T) {
|
||||
req, err := solver.makeDepsolveRequest(tt.packageSets, tt.repos, tt.packageSetsRepos)
|
||||
req, _, err := solver.makeDepsolveRequest(tt.packageSets, tt.repos, tt.packageSetsRepos)
|
||||
if tt.err {
|
||||
assert.NotNilf(t, err, "expected an error, but got 'nil' instead")
|
||||
assert.Nilf(t, req, "got non-nill request, but expected an error")
|
||||
|
|
@ -460,10 +352,9 @@ func TestMakeDepsolveRequest(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func expectedResult(url string) *DepsolveResult {
|
||||
// need to change the url for the RemoteLocation since the port is different each time and we don't want to have a fixed one
|
||||
func expectedResult(repo rpmmd.RepoConfig) *DepsolveResult {
|
||||
// need to change the url for the RemoteLocation and the repo ID since the port is different each time and we don't want to have a fixed one
|
||||
expectedTemplate := DepsolveResult{
|
||||
Checksums: map[string]string{"0": "sha256:0cbe8e69f4c634b7e7ec43a8e165ec92d43767a28f8d16a046026a679d3f8442"},
|
||||
Dependencies: []rpmmd.PackageSpec{
|
||||
{Name: "acl", Epoch: 0, Version: "2.3.1", Release: "3.el9", Arch: "x86_64", RemoteLocation: "%s/Packages/acl-2.3.1-3.el9.x86_64.rpm", Checksum: "sha256:986044c3837eddbc9231d7be5e5fc517e245296978b988a803bc9f9172fe84ea", Secrets: "", CheckGPG: false},
|
||||
{Name: "alternatives", Epoch: 0, Version: "1.20", Release: "2.el9", Arch: "x86_64", RemoteLocation: "%s/Packages/alternatives-1.20-2.el9.x86_64.rpm", Checksum: "sha256:1851d5f64ebaeac67c5c2d9e4adc1e73aa6433b44a167268a3510c3d056062db", Secrets: "", CheckGPG: false},
|
||||
|
|
@ -578,7 +469,8 @@ func expectedResult(url string) *DepsolveResult {
|
|||
exp := DepsolveResult(expectedTemplate)
|
||||
for idx := range exp.Dependencies {
|
||||
urlTemplate := exp.Dependencies[idx].RemoteLocation
|
||||
exp.Dependencies[idx].RemoteLocation = fmt.Sprintf(urlTemplate, url)
|
||||
exp.Dependencies[idx].RemoteLocation = fmt.Sprintf(urlTemplate, repo.BaseURL)
|
||||
}
|
||||
exp.Checksums = map[string]string{repo.Hash(): "sha256:0cbe8e69f4c634b7e7ec43a8e165ec92d43767a28f8d16a046026a679d3f8442"}
|
||||
return &exp
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ func createBaseDepsolveFixture() []dnfjson.PackageSpec {
|
|||
Version: "3.0.3",
|
||||
Release: "1.fc30",
|
||||
Arch: "x86_64",
|
||||
RepoID: "0",
|
||||
RepoID: "REPOID", // added by mock-dnf-json
|
||||
},
|
||||
{
|
||||
Name: "dep-package1",
|
||||
|
|
@ -62,7 +62,7 @@ func createBaseDepsolveFixture() []dnfjson.PackageSpec {
|
|||
Version: "1.33",
|
||||
Release: "2.fc30",
|
||||
Arch: "x86_64",
|
||||
RepoID: "0",
|
||||
RepoID: "REPOID", // added by mock-dnf-json
|
||||
},
|
||||
{
|
||||
Name: "dep-package2",
|
||||
|
|
@ -70,7 +70,7 @@ func createBaseDepsolveFixture() []dnfjson.PackageSpec {
|
|||
Version: "2.9",
|
||||
Release: "1.fc30",
|
||||
Arch: "x86_64",
|
||||
RepoID: "0",
|
||||
RepoID: "REPOID", // added by mock-dnf-json
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -111,14 +111,14 @@ type ResponseGenerator func(string) string
|
|||
func Base(tmpdir string) string {
|
||||
deps := map[string]interface{}{
|
||||
"checksums": map[string]string{
|
||||
"0": "test:responsechecksum",
|
||||
"REPOID": "test:responsechecksum",
|
||||
},
|
||||
"dependencies": createBaseDepsolveFixture(),
|
||||
}
|
||||
|
||||
pkgs := map[string]interface{}{
|
||||
"checksums": map[string]string{
|
||||
"0": "test:responsechecksum",
|
||||
"REPOID": "test:responsechecksum",
|
||||
},
|
||||
"packages": generatePackageList(),
|
||||
}
|
||||
|
|
@ -152,7 +152,7 @@ func BadDepsolve(tmpdir string) string {
|
|||
}
|
||||
pkgs := map[string]interface{}{
|
||||
"checksums": map[string]string{
|
||||
"0": "test:responsechecksum",
|
||||
"REPOID": "test:responsechecksum",
|
||||
},
|
||||
"packages": generatePackageList(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package rpmmd
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
|
@ -39,6 +40,16 @@ type RepoConfig struct {
|
|||
ImageTypeTags []string
|
||||
}
|
||||
|
||||
// Hash calculates an ID string that uniquely represents a repository
|
||||
// configuration. The Name and ImageTypeTags fields are not considered in the
|
||||
// calculation.
|
||||
func (r *RepoConfig) Hash() string {
|
||||
bts := func(b bool) string {
|
||||
return fmt.Sprintf("%T", b)
|
||||
}
|
||||
return fmt.Sprintf("%x", sha256.Sum256([]byte(r.BaseURL+r.Metalink+r.MirrorList+r.GPGKey+bts(r.CheckGPG)+bts(r.IgnoreSSL)+r.MetadataExpire+bts(r.RHSM))))
|
||||
}
|
||||
|
||||
type DistrosRepoConfigs map[string]map[string][]RepoConfig
|
||||
|
||||
type PackageList []Package
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue