Slide 1

Slide 1 text

DEPSOLVER A tool for dependency solving @cournape github.com/cournape Monday, 28 October 13

Slide 2

Slide 2 text

CURRENT SITUATION • setuptools: implements dependency handling (install_requires) • pip: another implementation (requirements.txt) Monday, 28 October 13

Slide 3

Slide 3 text

EXAMPLE # - A requires B and C # - B requires D <= 1.1 # - C requires D <= 0.9 $  pip  install #  installs  D  1.1 Monday, 28 October 13

Slide 4

Slide 4 text

LINUX DISTRIBUTIONS • Successful examples of distributed packaging: • apt-get • urpmi/smart/yum • etc... • Graph-based algorithms with complex rules • I don’t want to re-implement apt-get... Monday, 28 October 13

Slide 5

Slide 5 text

REQUIREMENTS • pure python • works for python 2 and 3 • flexible version representation (use @enthought) Monday, 28 October 13

Slide 6

Slide 6 text

Monday, 28 October 13

Slide 7

Slide 7 text

PHP TO THE RESCUE • PHP Composer: php package manager • https://github.com/composer/composer • Uses SAT solver for dependencies • Open source, well written code, small: • 15k LOC, only 2.5K LOC for dependency handling Monday, 28 October 13

Slide 8

Slide 8 text

SAT SOLVER ? • SATisfiability problem: “decision problem with boolean expressions” • NP-complete (~ brute force-only solutions) Monday, 28 October 13

Slide 9

Slide 9 text

EXAMPLES • A & (B | C) is satisfiable (e.g. A = B = True, C = False) • A & ( B | C) & ~B & ~C is not satisfiable Monday, 28 October 13

Slide 10

Slide 10 text

FROM DEPENDENCIES TO SAT Monday, 28 October 13

Slide 11

Slide 11 text

FROM SAT TO DEPENDENCIES • Installing package “A”: (A) • Removing “A”: (~A) • “A” dependencies: (~A | Dep-v1 | Dep-v2 | ...) • Example: A depends on B >= 1.2.2, B-1.3.0 and B-1.4.0 are available becomes (~A | B-1.3.0 | B-1.4.0) Monday, 28 October 13

Slide 12

Slide 12 text

FROM SAT TO DEPENDENCIES • A conflicts with B >= 1.2: (~A | ~B-1.2) & (~A | ~B-1.3) • A obsoletes B >= 1.2: same as conflict Monday, 28 October 13

Slide 13

Slide 13 text

SOLVER ALGORITHM • minisat, etc... BSD implementations available: • Simple solvers may be implemented in a few 10s of lines • Davis–Putnam–Logemann–Loveland (DPLL) algorithm is a complete, backtracking-based search algorithm Monday, 28 October 13

Slide 14

Slide 14 text

DEPSOLVER Monday, 28 October 13

Slide 15

Slide 15 text

DEPSOLVER • Port of composer solver in python • Small (~ 3kloc) • Simple (but low-level) API Monday, 28 October 13

Slide 16

Slide 16 text

EXAMPLE remote_repository = Repository([ P("A-1.0.0; depends (B, C)"), P("B-1.0.0; depends (D <= 1.1.0)"), P("C-1.0.0; depends (D <= 0.9.0)"), P("D-1.1.0"), P("D-0.9.0")]) installed_repository = Repository() pool = Pool([remote_repository, installed_repository]) request = Request(pool) request.install(Requirement.from_string("A")) for operation in Solver(pool, installed_repository).solve(request): print operation Monday, 28 October 13

Slide 17

Slide 17 text

MAIN CONCEPTS • PackageInfo: package metadata • Repository: bag of packages • Pool: bag of repositories (retrieve packages following a requirement) • Solver: actual solver Monday, 28 October 13

Slide 18

Slide 18 text

FLEXIBLE VERSION SUPPORT • PEP 440 supported • other (better) format also supported: SEMVER, Debian Monday, 28 October 13

Slide 19

Slide 19 text

EXAMPLE from depsolver.debian_version import DebianVersion P = PackageInfo.from_string V = DebianVersion.from_string a_1_0_0 = P("A-1.0.0~1; depends (B, C)", V) b_1_0_0 = P("B-1.0.0~1; depends (D <= 1.1.0~1)", V) c_1_0_0 = P("C-1.0.0~1; depends (D <= 0.9.0~1)", V) d_1_1_0 = P("D-1.1.0~1", V) d_0_9_0 = P("D-0.9.0~1", V) Monday, 28 October 13

Slide 20

Slide 20 text

FUTURE PLAN • Add support for removal and updates • Finish support for yaml-based scenario description • Proof of concept for integration with pip Monday, 28 October 13

Slide 21

Slide 21 text

WHERE TO GET IT • https://github.com/enthought/depsolver Monday, 28 October 13