Support version relation in Provides entries

This commit is contained in:
5hir0kur0
2024-07-18 11:50:26 +09:00
committed by André Roth
parent ff8a02959c
commit ab18d4835b
2 changed files with 77 additions and 20 deletions
+14 -10
View File
@@ -145,7 +145,7 @@ func (l *PackageList) Add(p *Package) error {
l.packages[key] = p
if l.indexed {
for _, provides := range p.Provides {
for _, provides := range p.ProvidedPackages() {
l.providesIndex[provides] = append(l.providesIndex[provides], p)
}
@@ -215,7 +215,7 @@ func (l *PackageList) Append(pl *PackageList) error {
func (l *PackageList) Remove(p *Package) {
delete(l.packages, l.keyFunc(p))
if l.indexed {
for _, provides := range p.Provides {
for _, provides := range p.ProvidedPackages() {
for i, pkg := range l.providesIndex[provides] {
if pkg.Equals(p) {
// remove l.ProvidesIndex[provides][i] w/o preserving order
@@ -419,7 +419,7 @@ func (l *PackageList) PrepareIndex() {
l.packagesIndex[i] = p
i++
for _, provides := range p.Provides {
for _, provides := range p.ProvidedPackages() {
l.providesIndex[provides] = append(l.providesIndex[provides], p)
}
}
@@ -472,21 +472,25 @@ func (l *PackageList) Search(dep Dependency, allMatches bool) (searchResults []*
searchResults = append(searchResults, p)
if !allMatches {
break
return
}
}
i++
}
if dep.Relation == VersionDontCare {
for _, p := range l.providesIndex[dep.Pkg] {
if dep.Architecture == "" || p.MatchesArchitecture(dep.Architecture) {
providers, ok := l.providesIndex[dep.Pkg]
if !ok {
return
}
for _, p := range providers {
if dep.Architecture == "" || p.MatchesArchitecture(dep.Architecture) {
if p.MatchesDependency(dep) {
searchResults = append(searchResults, p)
}
if !allMatches {
break
}
if !allMatches {
return
}
}
}
+63 -10
View File
@@ -3,6 +3,7 @@ package deb
import (
gocontext "context"
"encoding/json"
"errors"
"fmt"
"path/filepath"
"strconv"
@@ -312,6 +313,23 @@ func (p *Package) GetField(name string) string {
}
}
// ProvidedPackages returns just the package names of the provided packages (without version numbers such as
// `(= 1.2.3)`).
func (p *Package) ProvidedPackages() []string {
result := make([]string, len(p.Provides))
for i, provided := range p.Provides {
providedDep, err := ParseDependency(provided)
if err != nil {
// Should never happen, but I included this, so it definitely has the old behavior in case there is no
// special syntax.
result[i] = provided
} else {
result[i] = providedDep.Pkg
}
}
return result
}
// MatchesArchitecture checks whether packages matches specified architecture
func (p *Package) MatchesArchitecture(arch string) bool {
if p.Architecture == ArchitectureAll && arch != ArchitectureSource {
@@ -321,24 +339,57 @@ func (p *Package) MatchesArchitecture(arch string) bool {
return p.Architecture == arch
}
// providesDependency checks if the package `Provide:`s the dependency, assuming that the architecture matches.
// If the `Provides:` entry includes a version number, it will be considered when checking the dependency.
func (p *Package) providesDependency(dep Dependency) (bool, error) {
var errs []error // won't cause an allocation in case of no errors
for _, provided := range p.Provides {
providedDep, err := ParseDependency(provided)
if err != nil {
errs = append(errs, err)
}
// The only relation allowed here is `=`.
// > The relations allowed are [...]. The exception is the Provides field, for which only = is allowed.
// > [...]
// > A Provides field may contain version numbers, and such a version number will be considered when
// > considering a dependency on or conflict with the virtual package name.
// -- https://www.debian.org/doc/debian-policy/ch-relationships.html
switch providedDep.Relation {
case VersionDontCare:
if providedDep.Pkg == dep.Pkg {
return true, nil
}
case VersionEqual:
providedVersion := providedDep.Version
if providedDep.Pkg == dep.Pkg && versionSatisfiesDependency(providedVersion, dep) {
return true, nil
}
default:
errs = append(errs, fmt.Errorf("unsupported relation in Provides: %s", providedDep.String()))
}
}
return false, errors.Join(errs...)
}
// MatchesDependency checks whether package matches specified dependency
func (p *Package) MatchesDependency(dep Dependency) bool {
if dep.Architecture != "" && !p.MatchesArchitecture(dep.Architecture) {
return false
}
if dep.Relation == VersionDontCare {
if utils.StrSliceHasItem(p.Provides, dep.Pkg) {
return true
}
return dep.Pkg == p.Name
if providesDep, _ := p.providesDependency(dep); providesDep { // Is ignoring errors the right thing to do here?
return true
}
if dep.Pkg != p.Name {
return false
}
r := CompareVersions(p.Version, dep.Version)
return versionSatisfiesDependency(p.Version, dep)
}
func versionSatisfiesDependency(version string, dep Dependency) bool {
r := CompareVersions(version, dep.Version)
switch dep.Relation {
case VersionEqual:
@@ -352,13 +403,15 @@ func (p *Package) MatchesDependency(dep Dependency) bool {
case VersionGreaterOrEqual:
return r >= 0
case VersionPatternMatch:
matched, err := filepath.Match(dep.Version, p.Version)
matched, err := filepath.Match(dep.Version, version)
return err == nil && matched
case VersionRegexp:
return dep.Regexp.FindStringIndex(p.Version) != nil
return dep.Regexp.FindStringIndex(version) != nil
case VersionDontCare:
return true
default:
panic(fmt.Sprintf("unknown relation: %d", dep.Relation))
}
panic("unknown relation")
}
// GetName returns package name