mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-06-11 06:24:04 +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
|
l.packages[key] = p
|
||||||
|
|
||||||
if l.indexed {
|
if l.indexed {
|
||||||
for _, provides := range p.Provides {
|
for _, provides := range p.ProvidedPackages() {
|
||||||
l.providesIndex[provides] = append(l.providesIndex[provides], p)
|
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) {
|
func (l *PackageList) Remove(p *Package) {
|
||||||
delete(l.packages, l.keyFunc(p))
|
delete(l.packages, l.keyFunc(p))
|
||||||
if l.indexed {
|
if l.indexed {
|
||||||
for _, provides := range p.Provides {
|
for _, provides := range p.ProvidedPackages() {
|
||||||
for i, pkg := range l.providesIndex[provides] {
|
for i, pkg := range l.providesIndex[provides] {
|
||||||
if pkg.Equals(p) {
|
if pkg.Equals(p) {
|
||||||
// remove l.ProvidesIndex[provides][i] w/o preserving order
|
// remove l.ProvidesIndex[provides][i] w/o preserving order
|
||||||
@@ -419,7 +419,7 @@ func (l *PackageList) PrepareIndex() {
|
|||||||
l.packagesIndex[i] = p
|
l.packagesIndex[i] = p
|
||||||
i++
|
i++
|
||||||
|
|
||||||
for _, provides := range p.Provides {
|
for _, provides := range p.ProvidedPackages() {
|
||||||
l.providesIndex[provides] = append(l.providesIndex[provides], p)
|
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)
|
searchResults = append(searchResults, p)
|
||||||
|
|
||||||
if !allMatches {
|
if !allMatches {
|
||||||
break
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
if dep.Relation == VersionDontCare {
|
providers, ok := l.providesIndex[dep.Pkg]
|
||||||
for _, p := range l.providesIndex[dep.Pkg] {
|
if !ok {
|
||||||
if dep.Architecture == "" || p.MatchesArchitecture(dep.Architecture) {
|
return
|
||||||
|
}
|
||||||
|
for _, p := range providers {
|
||||||
|
if dep.Architecture == "" || p.MatchesArchitecture(dep.Architecture) {
|
||||||
|
if p.MatchesDependency(dep) {
|
||||||
searchResults = append(searchResults, p)
|
searchResults = append(searchResults, p)
|
||||||
|
}
|
||||||
|
|
||||||
if !allMatches {
|
if !allMatches {
|
||||||
break
|
return
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+63
-10
@@ -3,6 +3,7 @@ package deb
|
|||||||
import (
|
import (
|
||||||
gocontext "context"
|
gocontext "context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"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
|
// MatchesArchitecture checks whether packages matches specified architecture
|
||||||
func (p *Package) MatchesArchitecture(arch string) bool {
|
func (p *Package) MatchesArchitecture(arch string) bool {
|
||||||
if p.Architecture == ArchitectureAll && arch != ArchitectureSource {
|
if p.Architecture == ArchitectureAll && arch != ArchitectureSource {
|
||||||
@@ -321,24 +339,57 @@ func (p *Package) MatchesArchitecture(arch string) bool {
|
|||||||
return p.Architecture == arch
|
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
|
// MatchesDependency checks whether package matches specified dependency
|
||||||
func (p *Package) MatchesDependency(dep Dependency) bool {
|
func (p *Package) MatchesDependency(dep Dependency) bool {
|
||||||
if dep.Architecture != "" && !p.MatchesArchitecture(dep.Architecture) {
|
if dep.Architecture != "" && !p.MatchesArchitecture(dep.Architecture) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if dep.Relation == VersionDontCare {
|
if providesDep, _ := p.providesDependency(dep); providesDep { // Is ignoring errors the right thing to do here?
|
||||||
if utils.StrSliceHasItem(p.Provides, dep.Pkg) {
|
return true
|
||||||
return true
|
|
||||||
}
|
|
||||||
return dep.Pkg == p.Name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if dep.Pkg != p.Name {
|
if dep.Pkg != p.Name {
|
||||||
return false
|
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 {
|
switch dep.Relation {
|
||||||
case VersionEqual:
|
case VersionEqual:
|
||||||
@@ -352,13 +403,15 @@ func (p *Package) MatchesDependency(dep Dependency) bool {
|
|||||||
case VersionGreaterOrEqual:
|
case VersionGreaterOrEqual:
|
||||||
return r >= 0
|
return r >= 0
|
||||||
case VersionPatternMatch:
|
case VersionPatternMatch:
|
||||||
matched, err := filepath.Match(dep.Version, p.Version)
|
matched, err := filepath.Match(dep.Version, version)
|
||||||
return err == nil && matched
|
return err == nil && matched
|
||||||
case VersionRegexp:
|
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
|
// GetName returns package name
|
||||||
|
|||||||
Reference in New Issue
Block a user