Commit 64d9e8ce by Sébastien Eustace

Improve resolver

parent 658590c5
...@@ -191,14 +191,10 @@ class Installer: ...@@ -191,14 +191,10 @@ class Installer:
pool.add_repository(local_repo) pool.add_repository(local_repo)
solver = Solver( solver = Solver(
self._package, self._package, pool, self._installed_repository, Repository(), NullIO()
pool,
self._installed_repository,
locked_repository,
NullIO(),
) )
ops = solver.solve() ops = solver.solve() + [o for o in ops if o.job_type == "uninstall"]
# We need to filter operations so that packages # We need to filter operations so that packages
# not compatible with the current system, # not compatible with the current system,
...@@ -360,12 +356,7 @@ class Installer: ...@@ -360,12 +356,7 @@ class Installer:
self._installer.remove(operation.package) self._installer.remove(operation.package)
def _populate_local_repo(self, local_repo, ops, locked_repository): def _populate_local_repo(self, local_repo, ops, locked_repository):
# Add all locked packages from the lock and go from there # We walk through all operations and add/remove/update accordingly
for package in locked_repository.packages:
if not local_repo.has_package(package):
local_repo.add_package(package)
# Now, walk through all operations and add/remove/update accordingly
for op in ops: for op in ops:
if isinstance(op, Update): if isinstance(op, Update):
package = op.target_package package = op.target_package
...@@ -373,7 +364,7 @@ class Installer: ...@@ -373,7 +364,7 @@ class Installer:
package = op.package package = op.package
acted_on = False acted_on = False
for pkg in local_repo.packages: for pkg in locked_repository.packages:
if pkg.name == package.name: if pkg.name == package.name:
# The package we operate on is in the local repo # The package we operate on is in the local repo
if op.job_type == "update": if op.job_type == "update":
...@@ -383,17 +374,13 @@ class Installer: ...@@ -383,17 +374,13 @@ class Installer:
local_repo.remove_package(pkg) local_repo.remove_package(pkg)
local_repo.add_package(op.target_package) local_repo.add_package(op.target_package)
elif op.job_type == "uninstall": elif op.job_type == "uninstall":
if pkg.version == package.version: local_repo.remove_package(op.package)
local_repo.remove_package(op.package)
else: else:
# Even though the package already exists # Even though the package already exists
# in the lock file we will prefer the new one # in the lock file we will prefer the new one
# to force updates # to force updates
if pkg.version == package.version: local_repo.remove_package(pkg)
local_repo.remove_package(pkg) local_repo.add_package(package)
local_repo.add_package(package)
else:
local_repo.add_package(package)
acted_on = True acted_on = True
......
...@@ -85,6 +85,12 @@ class Locker: ...@@ -85,6 +85,12 @@ class Locker:
package.python_versions = info["python-versions"] package.python_versions = info["python-versions"]
for dep_name, constraint in info.get("dependencies", {}).items(): for dep_name, constraint in info.get("dependencies", {}).items():
if isinstance(constraint, list):
for c in constraint:
package.add_dependency(dep_name, c)
continue
package.add_dependency(dep_name, constraint) package.add_dependency(dep_name, constraint)
if "requirements" in info: if "requirements" in info:
......
...@@ -27,7 +27,7 @@ class Repository(BaseRepository): ...@@ -27,7 +27,7 @@ class Repository(BaseRepository):
if extra in package.extras: if extra in package.extras:
for extra_dep in package.extras[extra]: for extra_dep in package.extras[extra]:
for dep in package.requires: for dep in package.requires:
if dep.name == extra_dep.lower(): if dep.name == extra_dep.name:
dep.activate() dep.activate()
return package.clone() return package.clone()
......
[[package]]
name = "A"
version = "1.1"
description = ""
category = "main"
optional = false
python-versions = "*"
platform = "*"
[package.dependencies]
B = "^2.0"
[[package]]
name = "B"
version = "2.0"
description = ""
category = "main"
optional = false
python-versions = "*"
platform = "*"
[package.dependencies]
C = "1.5"
[[package]]
name = "C"
version = "1.5"
description = ""
category = "main"
optional = false
python-versions = "*"
platform = "*"
[metadata]
python-versions = "*"
platform = "*"
content-hash = "123456789"
[metadata.hashes]
A = []
B = []
C = []
...@@ -717,7 +717,7 @@ def test_run_update_with_locked_extras(installer, locker, repo, package): ...@@ -717,7 +717,7 @@ def test_run_update_with_locked_extras(installer, locker, repo, package):
} }
) )
package_a = get_package("A", "1.0") package_a = get_package("A", "1.0")
package_a.extras["foo"] = ["B"] package_a.extras["foo"] = [get_dependency("B")]
b_dependency = get_dependency("B", "^1.0", optional=True) b_dependency = get_dependency("B", "^1.0", optional=True)
b_dependency.in_extras.append("foo") b_dependency.in_extras.append("foo")
c_dependency = get_dependency("C", "^1.0") c_dependency = get_dependency("C", "^1.0")
...@@ -776,3 +776,222 @@ def test_run_install_duplicate_dependencies_different_constraints( ...@@ -776,3 +776,222 @@ def test_run_install_duplicate_dependencies_different_constraints(
assert installs[0] == package_b10 assert installs[0] == package_b10
assert installs[1] == package_c12 assert installs[1] == package_c12
assert installs[2] == package_a assert installs[2] == package_a
updates = installer.installer.updates
assert len(updates) == 0
removals = installer.installer.removals
assert len(removals) == 0
def test_run_install_duplicate_dependencies_different_constraints_with_lock(
installer, locker, repo, package
):
locker.locked(True)
locker.mock_lock_data(
{
"package": [
{
"name": "A",
"version": "1.0",
"category": "main",
"optional": False,
"platform": "*",
"python-versions": "*",
"checksum": [],
"dependencies": {
"B": [
{"version": "^1.0", "python": "<4.0"},
{"version": "^2.0", "python": ">=4.0"},
]
},
},
{
"name": "B",
"version": "1.0",
"category": "dev",
"optional": False,
"platform": "*",
"python-versions": "*",
"checksum": [],
"dependencies": {"C": "1.2"},
"requirements": {"python": "<4.0"},
},
{
"name": "B",
"version": "2.0",
"category": "dev",
"optional": False,
"platform": "*",
"python-versions": "*",
"checksum": [],
"dependencies": {"C": "1.5"},
"requirements": {"python": ">=4.0"},
},
{
"name": "C",
"version": "1.2",
"category": "dev",
"optional": False,
"platform": "*",
"python-versions": "*",
"checksum": [],
},
{
"name": "C",
"version": "1.5",
"category": "dev",
"optional": False,
"platform": "*",
"python-versions": "*",
"checksum": [],
},
],
"metadata": {
"python-versions": "*",
"platform": "*",
"content-hash": "123456789",
"hashes": {"A": [], "B": [], "C": []},
},
}
)
package.add_dependency("A")
package_a = get_package("A", "1.0")
package_a.add_dependency("B", {"version": "^1.0", "python": "<4.0"})
package_a.add_dependency("B", {"version": "^2.0", "python": ">=4.0"})
package_b10 = get_package("B", "1.0")
package_b20 = get_package("B", "2.0")
package_b10.add_dependency("C", "1.2")
package_b20.add_dependency("C", "1.5")
package_c12 = get_package("C", "1.2")
package_c15 = get_package("C", "1.5")
repo.add_package(package_a)
repo.add_package(package_b10)
repo.add_package(package_b20)
repo.add_package(package_c12)
repo.add_package(package_c15)
installer.update(True)
installer.run()
expected = fixture("with-duplicate-dependencies")
assert locker.written_data == expected
installs = installer.installer.installs
assert len(installs) == 3
updates = installer.installer.updates
assert len(updates) == 0
removals = installer.installer.removals
assert len(removals) == 0
def test_run_install_duplicate_dependencies_different_constraints_with_lock_update(
installer, locker, repo, package, installed
):
locker.locked(True)
locker.mock_lock_data(
{
"package": [
{
"name": "A",
"version": "1.0",
"category": "main",
"optional": False,
"platform": "*",
"python-versions": "*",
"checksum": [],
"dependencies": {
"B": [
{"version": "^1.0", "python": "<4.0"},
{"version": "^2.0", "python": ">=4.0"},
]
},
},
{
"name": "B",
"version": "1.0",
"category": "dev",
"optional": False,
"platform": "*",
"python-versions": "*",
"checksum": [],
"dependencies": {"C": "1.2"},
"requirements": {"python": "<4.0"},
},
{
"name": "B",
"version": "2.0",
"category": "dev",
"optional": False,
"platform": "*",
"python-versions": "*",
"checksum": [],
"dependencies": {"C": "1.5"},
"requirements": {"python": ">=4.0"},
},
{
"name": "C",
"version": "1.2",
"category": "dev",
"optional": False,
"platform": "*",
"python-versions": "*",
"checksum": [],
},
{
"name": "C",
"version": "1.5",
"category": "dev",
"optional": False,
"platform": "*",
"python-versions": "*",
"checksum": [],
},
],
"metadata": {
"python-versions": "*",
"platform": "*",
"content-hash": "123456789",
"hashes": {"A": [], "B": [], "C": []},
},
}
)
package.add_dependency("A")
package_a = get_package("A", "1.1")
package_a.add_dependency("B", "^2.0")
package_b10 = get_package("B", "1.0")
package_b20 = get_package("B", "2.0")
package_b10.add_dependency("C", "1.2")
package_b20.add_dependency("C", "1.5")
package_c12 = get_package("C", "1.2")
package_c15 = get_package("C", "1.5")
repo.add_package(package_a)
repo.add_package(package_b10)
repo.add_package(package_b20)
repo.add_package(package_c12)
repo.add_package(package_c15)
installed.add_package(get_package("A", "1.0"))
installer.update(True)
installer.whitelist(["A"])
installer.run()
expected = fixture("with-duplicate-dependencies-update")
assert locker.written_data == expected
installs = installer.installer.installs
assert len(installs) == 2
updates = installer.installer.updates
assert len(updates) == 1
removals = installer.installer.removals
assert len(removals) == 0
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment