mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-06-04 05:10:40 +00:00
Support version relation in Provides entries
This commit is contained in:
+14
-10
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user