dnfjson: remove single Depsolve function and command

Remove the single Depsolve function from the dnfjson package and the
depsolve command from the dnf-json tool.  The new ChainDepsolve
functions and chain-depsolve command can handle single depsolves in the
same way so there's no need to keep (and have to maintain) two versions
of very similar code.

The ChainDepsolve function (in Go) and chain-depsolve command (in
Python) have been renamed to plain Depsolve and depsolve respectively,
since they are now general purpose depsolve functions.
This commit is contained in:
Achilleas Koutsou 2022-05-04 13:01:32 +02:00 committed by Tom Gundersen
parent d09176893b
commit 61d7c465af
11 changed files with 35 additions and 149 deletions

View file

@ -53,10 +53,6 @@ func parseResponse(resp []byte, command string) json.RawMessage {
parsedResponse := make(map[string]json.RawMessage)
err := json.Unmarshal(resp, &parsedResponse)
maybeFail(err)
if command == "chain-depsolve" {
// treat chain-depsolve and depsolve the same
command = "depsolve"
}
return parsedResponse[command]
}

View file

@ -83,10 +83,10 @@ func TestCrossArchDepsolve(t *testing.T) {
packages := imgType.PackageSets(blueprint.Blueprint{})
_, err = solver.Depsolve(packages["build"], repos[archStr])
_, err = solver.Depsolve([]rpmmd.PackageSet{packages["build"]}, repos[archStr], nil)
assert.NoError(t, err)
_, err = solver.Depsolve(packages["packages"], repos[archStr])
_, err = solver.Depsolve([]rpmmd.PackageSet{packages["packages"]}, repos[archStr], nil)
assert.NoError(t, err)
})
}
@ -155,7 +155,7 @@ func TestDepsolvePackageSets(t *testing.T) {
pkgSets[idx] = imagePkgSets[pkgSetName]
delete(imagePkgSets, pkgSetName) // will be depsolved here: remove from map
}
res, err := solver.ChainDepsolve(pkgSets, x86Repos, nil)
res, err := solver.Depsolve(pkgSets, x86Repos, nil)
if err != nil {
require.Nil(t, err)
}
@ -164,7 +164,7 @@ func TestDepsolvePackageSets(t *testing.T) {
// depsolve the rest of the package sets
for name, pkgSet := range imagePkgSets {
res, err := solver.ChainDepsolve([]rpmmd.PackageSet{pkgSet}, x86Repos, nil)
res, err := solver.Depsolve([]rpmmd.PackageSet{pkgSet}, x86Repos, nil)
if err != nil {
require.Nil(t, err)
}

View file

@ -152,7 +152,7 @@ func main() {
pkgSets[idx] = packageSets[pkgSetName]
delete(packageSets, pkgSetName) // will be depsolved here: remove from map
}
res, err := solver.ChainDepsolve(pkgSets, repos, nil)
res, err := solver.Depsolve(pkgSets, repos, nil)
if err != nil {
panic("Could not depsolve: " + err.Error())
}
@ -161,7 +161,7 @@ func main() {
// depsolve the rest of the package sets
for name, pkgSet := range packageSets {
res, err := solver.ChainDepsolve([]rpmmd.PackageSet{pkgSet}, repos, nil)
res, err := solver.Depsolve([]rpmmd.PackageSet{pkgSet}, repos, nil)
if err != nil {
panic("Could not depsolve: " + err.Error())
}

View file

@ -23,7 +23,7 @@ func getManifest(bp blueprint.Blueprint, t distro.ImageType, a distro.Arch, d di
pkgSpecSets := make(map[string][]rpmmd.PackageSpec)
solver := dnfjson.NewSolver(d.ModulePlatformID(), d.Releasever(), a.Name(), cacheDir)
for name, packages := range packageSets {
res, err := solver.Depsolve(packages, repos)
res, err := solver.Depsolve([]rpmmd.PackageSet{packages}, repos, nil)
if err != nil {
panic(err)
}

View file

@ -32,7 +32,7 @@ func (impl *DepsolveJobImpl) depsolve(packageSetsChains map[string][]string, pac
psRepos = append(psRepos, packageSetsRepos[pkgSetName]) // will be nil if it doesn't exist
delete(packageSets, pkgSetName) // will be depsolved here: remove from map
}
res, err := solver.ChainDepsolve(pkgSets, repos, psRepos)
res, err := solver.Depsolve(pkgSets, repos, psRepos)
if err != nil {
return nil, err
}
@ -41,7 +41,7 @@ func (impl *DepsolveJobImpl) depsolve(packageSetsChains map[string][]string, pac
// depsolve the rest of the package sets
for name, pkgSet := range packageSets {
res, err := solver.ChainDepsolve([]rpmmd.PackageSet{pkgSet}, repos, [][]rpmmd.RepoConfig{packageSetsRepos[name]})
res, err := solver.Depsolve([]rpmmd.PackageSet{pkgSet}, repos, [][]rpmmd.RepoConfig{packageSetsRepos[name]})
if err != nil {
return nil, err
}

View file

@ -147,37 +147,7 @@ class Solver():
"packages": packages
}
def depsolve(self, package_spec, exclude_spec):
self.base.install_specs(package_spec, exclude_spec)
self.base.resolve()
dependencies = []
for tsi in self.base.transaction:
# Avoid using the install_set() helper, as it does not guarantee
# a stable order
if tsi.action not in dnf.transaction.FORWARD_ACTIONS:
continue
package = tsi.pkg
dependencies.append({
"name": package.name,
"epoch": package.epoch,
"version": package.version,
"release": package.release,
"arch": package.arch,
"repo_id": package.repoid,
"path": package.relativepath,
"remote_location": package.remote_location(),
"checksum": (
f"{hawkey.chksum_name(package.chksum[0])}:"
f"{package.chksum[1].hex()}"
)
})
return {
"checksums": self._repo_checksums(),
"dependencies": dependencies
}
def chain_depsolve(self, transactions):
def depsolve(self, transactions):
last_transaction = []
for idx, transaction in enumerate(transactions):
@ -266,15 +236,8 @@ def solve(request, cache_dir):
result = solver.dump()
printe("dump success")
elif command == "depsolve":
job = transactions[0]
result = solver.depsolve(
job["package-specs"],
job.get("exclude-specs", [])
)
result = solver.depsolve(transactions)
printe("depsolve success")
elif command == "chain-depsolve":
result = solver.chain_depsolve(transactions)
printe("chain-depsolve success")
except dnf.exceptions.MarkingErrors as e:
printe("error install_specs")
@ -318,7 +281,7 @@ def respond(result):
def validate_request(request):
command = request.get("command")
valid_cmds = ("depsolve", "dump", "chain-depsolve")
valid_cmds = ("depsolve", "dump")
if command not in valid_cmds:
return {
"kind": "InvalidRequest",

View file

@ -143,7 +143,7 @@ func getImageTypePkgSpecSets(imageType distro.ImageType, bp blueprint.Blueprint,
solver := dnfjson.NewSolver(imageType.Arch().Distro().ModulePlatformID(), imageType.Arch().Distro().Releasever(), imageType.Arch().Name(), cacheDir)
imgPackageSpecSets := make(map[string][]rpmmd.PackageSpec)
for name, packages := range imgPackageSets {
res, err := solver.Depsolve(packages, repos)
res, err := solver.Depsolve([]rpmmd.PackageSet{packages}, repos, nil)
if err != nil {
panic("Could not depsolve: " + err.Error())
}

View file

@ -88,41 +88,17 @@ func NewSolver(modulePlatformID string, releaseVer string, arch string, cacheDir
return s.NewWithConfig(modulePlatformID, releaseVer, arch)
}
// ChainDepsolve the given packages with explicit excludes using the given configuration and repos
func ChainDepsolve(pkgSets []rpmmd.PackageSet, repos []rpmmd.RepoConfig, psRepos [][]rpmmd.RepoConfig, modulePlatformID string, releaseVer string, arch string, cacheDir string) (*DepsolveResult, error) {
return NewSolver(modulePlatformID, releaseVer, arch, cacheDir).ChainDepsolve(pkgSets, repos, psRepos)
// Depsolve the given packages with explicit excludes using the given configuration and repos
func Depsolve(pkgSets []rpmmd.PackageSet, repos []rpmmd.RepoConfig, psRepos [][]rpmmd.RepoConfig, modulePlatformID string, releaseVer string, arch string, cacheDir string) (*DepsolveResult, error) {
return NewSolver(modulePlatformID, releaseVer, arch, cacheDir).Depsolve(pkgSets, repos, psRepos)
}
// ChainDepsolve the list of required package sets with explicit excludes using
// Depsolve the list of required package sets with explicit excludes using
// the given repositories. Each package set is depsolved as a separate
// transactions in a chain. It returns a list of all packages (with solved
// dependencies) that will be installed into the system.
func (s *Solver) ChainDepsolve(pkgSets []rpmmd.PackageSet, repos []rpmmd.RepoConfig, psRepos [][]rpmmd.RepoConfig) (*DepsolveResult, error) {
req, err := s.makeChainDepsolveRequest(pkgSets, repos, psRepos)
if err != nil {
return nil, err
}
output, err := run(s.dnfJsonCmd, req)
if err != nil {
return nil, err
}
var result *depsolveResult
if err := json.Unmarshal(output, &result); err != nil {
return nil, err
}
return resultToPublic(result, repos), nil
}
// Depsolve the given packages with explicit excludes using the given configuration and repos
func Depsolve(pkgSets rpmmd.PackageSet, repos []rpmmd.RepoConfig, modulePlatformID string, releaseVer string, arch string, cacheDir string) (*DepsolveResult, error) {
return NewSolver(modulePlatformID, releaseVer, arch, cacheDir).Depsolve(pkgSets, repos)
}
// Depsolve the given packages with explicit excludes using the solver configuration and provided repos
func (s *Solver) Depsolve(pkgSets rpmmd.PackageSet, repos []rpmmd.RepoConfig) (*DepsolveResult, error) {
req, err := s.makeDepsolveRequest(pkgSets, repos)
func (s *Solver) Depsolve(pkgSets []rpmmd.PackageSet, repos []rpmmd.RepoConfig, psRepos [][]rpmmd.RepoConfig) (*DepsolveResult, error) {
req, err := s.makeDepsolveRequest(pkgSets, repos, psRepos)
if err != nil {
return nil, err
}
@ -228,7 +204,7 @@ 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)))
}
// makeChainDepsolveRequest constructs an Request for a chain-depsolve job.
// 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
// as the base repositories for all transactions. The extra repository configs
@ -239,8 +215,7 @@ 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) makeChainDepsolveRequest(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, 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))
@ -324,37 +299,6 @@ func (s *Solver) makeChainDepsolveRequest(pkgSets []rpmmd.PackageSet, repoConfig
Transactions: transactions,
}
req := Request{
Command: "chain-depsolve",
ModulePlatformID: s.modulePlatformID,
Arch: s.arch,
CacheDir: s.cacheDir,
Arguments: args,
}
return &req, nil
}
// Helper function for creating a depsolve request payload
func (s *Solver) makeDepsolveRequest(pkgSets rpmmd.PackageSet, repoConfigs []rpmmd.RepoConfig) (*Request, error) {
repos, err := s.reposFromRPMMD(repoConfigs)
if err != nil {
return nil, err
}
allRepoIDs := make([]int, len(repoConfigs))
for idx := range allRepoIDs {
allRepoIDs[idx] = idx
}
args := arguments{
Repos: repos,
Transactions: []transactionArgs{
{
PackageSpecs: pkgSets.Include,
ExcludeSpecs: pkgSets.Exclude,
RepoIDs: allRepoIDs,
},
},
}
req := Request{
Command: "depsolve",
ModulePlatformID: s.modulePlatformID,
@ -362,6 +306,7 @@ func (s *Solver) makeDepsolveRequest(pkgSets rpmmd.PackageSet, repoConfigs []rpm
CacheDir: s.cacheDir,
Arguments: args,
}
return &req, nil
}

View file

@ -19,29 +19,10 @@ func TestDepsolver(t *testing.T) {
solver := NewSolver("platform:el9", "9", "x86_64", tmpdir)
solver.SetDNFJSONPath("../../dnf-json")
pkgset := rpmmd.PackageSet{Include: []string{"kernel", "vim-minimal", "tmux", "zsh"}} // everything you'll ever need
deps, err := solver.Depsolve(pkgset, []rpmmd.RepoConfig{s.RepoConfig})
if err != nil {
t.Fatal(err)
}
exp := expectedResult(s.Server.URL)
assert.Equal(deps, exp)
}
func TestChainDepsolver(t *testing.T) {
s := rpmrepo.NewTestServer()
defer s.Close()
assert := assert.New(t)
tmpdir := t.TempDir()
solver := NewSolver("platform:el9", "9", "x86_64", tmpdir)
solver.SetDNFJSONPath("../../dnf-json")
{ // single depsolve, but using chain function, should behave the same way as plain Depsolve
{ // single depsolve
pkgsets := []rpmmd.PackageSet{{Include: []string{"kernel", "vim-minimal", "tmux", "zsh"}}} // everything you'll ever need
deps, err := solver.ChainDepsolve(pkgsets, []rpmmd.RepoConfig{s.RepoConfig}, nil)
deps, err := solver.Depsolve(pkgsets, []rpmmd.RepoConfig{s.RepoConfig}, nil)
if err != nil {
t.Fatal(err)
}
@ -54,7 +35,7 @@ func TestChainDepsolver(t *testing.T) {
{Include: []string{"kernel"}},
{Include: []string{"vim-minimal", "tmux", "zsh"}},
}
deps, err := solver.ChainDepsolve(pkgsets, []rpmmd.RepoConfig{s.RepoConfig}, nil)
deps, err := solver.Depsolve(pkgsets, []rpmmd.RepoConfig{s.RepoConfig}, nil)
if err != nil {
t.Fatal(err)
}
@ -67,7 +48,7 @@ func TestChainDepsolver(t *testing.T) {
{Include: []string{"kernel"}},
{Include: []string{"vim-minimal", "tmux", "zsh"}},
}
deps, err := solver.ChainDepsolve(pkgsets, []rpmmd.RepoConfig{s.RepoConfig}, [][]rpmmd.RepoConfig{nil, {s.RepoConfig}})
deps, err := solver.Depsolve(pkgsets, []rpmmd.RepoConfig{s.RepoConfig}, [][]rpmmd.RepoConfig{nil, {s.RepoConfig}})
if err != nil {
t.Fatal(err)
}
@ -76,7 +57,7 @@ func TestChainDepsolver(t *testing.T) {
}
}
func TestMakeChainDepsolveRequest(t *testing.T) {
func TestMakeDepsolveRequest(t *testing.T) {
tests := []struct {
packageSets []rpmmd.PackageSet
repos []rpmmd.RepoConfig
@ -464,7 +445,7 @@ func TestMakeChainDepsolveRequest(t *testing.T) {
solver := NewSolver("", "", "", "")
for idx, tt := range tests {
t.Run(fmt.Sprintf("%d", idx), func(t *testing.T) {
req, err := solver.makeChainDepsolveRequest(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")

View file

@ -131,7 +131,7 @@ func (h *apiHandlers) PostCompose(ctx echo.Context) error {
for idx, pkgSetName := range setNames {
chain[idx] = packageSets[pkgSetName]
}
res, err := solver.ChainDepsolve(chain, repositories, nil)
res, err := solver.Depsolve(chain, repositories, nil)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Failed to depsolve base packages for %s/%s/%s: %s", ir.ImageType, ir.Architecture, request.Distribution, err))
}

View file

@ -1261,7 +1261,7 @@ func (api *API) modulesInfoHandler(writer http.ResponseWriter, request *http.Req
solver := api.solver.NewWithConfig(d.ModulePlatformID(), d.Releasever(), api.archName)
for i := range packageInfos {
pkgName := packageInfos[i].Name
solved, err := solver.Depsolve(rpmmd.PackageSet{Include: []string{pkgName}}, repos)
solved, err := solver.Depsolve([]rpmmd.PackageSet{{Include: []string{pkgName}}}, repos, nil)
if err != nil {
errors := responseError{
ID: errorId,
@ -1340,8 +1340,9 @@ func (api *API) projectsDepsolveHandler(writer http.ResponseWriter, request *htt
solver := api.solver.NewWithConfig(d.ModulePlatformID(), d.Releasever(), api.archName)
deps, err := solver.Depsolve(
rpmmd.PackageSet{Include: names},
[]rpmmd.PackageSet{{Include: names}},
repos,
nil,
)
if err != nil {
errors := responseError{
@ -2160,7 +2161,7 @@ func (api *API) depsolveBlueprintForImageType(bp blueprint.Blueprint, imageType
psRepos = append(psRepos, packageSetsRepos[pkgSetName]) // will be nil if it doesn't exist
delete(packageSets, pkgSetName) // will be depsolved here: remove from map
}
res, err := solver.ChainDepsolve(pkgSets, imageTypeRepos, psRepos)
res, err := solver.Depsolve(pkgSets, imageTypeRepos, psRepos)
if err != nil {
return nil, err
}
@ -2169,7 +2170,7 @@ func (api *API) depsolveBlueprintForImageType(bp blueprint.Blueprint, imageType
// depsolve the rest of the package sets
for name, pkgSet := range packageSets {
res, err := solver.ChainDepsolve([]rpmmd.PackageSet{pkgSet}, imageTypeRepos, [][]rpmmd.RepoConfig{packageSetsRepos[name]})
res, err := solver.Depsolve([]rpmmd.PackageSet{pkgSet}, imageTypeRepos, [][]rpmmd.RepoConfig{packageSetsRepos[name]})
if err != nil {
return nil, err
}
@ -3208,7 +3209,7 @@ func (api *API) depsolveBlueprint(bp blueprint.Blueprint) ([]rpmmd.PackageSpec,
}
solver := api.solver.NewWithConfig(d.ModulePlatformID(), d.Releasever(), api.archName)
solved, err := solver.Depsolve(rpmmd.PackageSet{Include: bp.GetPackages()}, repos)
solved, err := solver.Depsolve([]rpmmd.PackageSet{{Include: bp.GetPackages()}}, repos, nil)
if err != nil {
return nil, err
}