diff options
author | Richard Ipsum <richard.ipsum@codethink.co.uk> | 2014-11-05 16:14:49 +0000 |
---|---|---|
committer | Richard Ipsum <richard.ipsum@codethink.co.uk> | 2014-11-05 16:14:49 +0000 |
commit | 20038fd313146bd55b6acf6b268b8f5558437d54 (patch) | |
tree | 310739f28aafae120f688447a863bde81018cd80 | |
parent | 5f28712029f39b61d7af3a0f1ee8b49e17917865 (diff) | |
download | import-20038fd313146bd55b6acf6b268b8f5558437d54.tar.gz |
Add the beginnings of this conflict detection
-rw-r--r-- | README | 2 | ||||
-rwxr-xr-x | exts/pip.find_deps | 79 | ||||
-rwxr-xr-x | exts/pip_lorry.py | 9 |
3 files changed, 85 insertions, 5 deletions
@@ -97,4 +97,4 @@ field. These fields are non-standard extensions to the morphology format. For more package-system specific information, see the relevant README file, e.g -README.rubygems for RubyGem imports. +README.rubygems for RubyGem imports.
\ No newline at end of file diff --git a/exts/pip.find_deps b/exts/pip.find_deps index f9050a9..1749085 100755 --- a/exts/pip.find_deps +++ b/exts/pip.find_deps @@ -24,6 +24,7 @@ import subprocess import os import pkg_resources +import xmlrpclib DEBUG = False @@ -39,6 +40,53 @@ def debug(s): if DEBUG: print(s) +# TODO: this is copied from pip_lorry, it should be shared. +def specs_satisfied(version, specs): + def mapping_error(op): + # We parse ops with requirements-parser, so any invalid user input + # should be detected there. This really guards against + # the pip developers adding some new operation to a requirement. + error("Invalid op in spec: %s" % op) + + opmap = {'==' : lambda x, y: x == y, '!=' : lambda x, y: x != y, + '<=' : lambda x, y: x <= y, '>=' : lambda x, y: x >= y, + '<': lambda x, y: x < y, '>' : lambda x, y: x > y} + + def get_op_func(op): + return opmap[op] if op in opmap else lambda x, y: mapping_error(op) + + return all([get_op_func(op)(version, sv) for (op, sv) in specs]) + +def conflict(specs, spec): + # Return whether spec_x conflicts with spec_y + # examples: ('==', '0.1') conflicts with ('==', '0.2') + + # ('==', '0.1') conflicts with ('<', 0.1) + # ('==', '0.1') conflicts with ('>', 0.1) + # ('==', '0.1') conflicts with ('!=', 0.1) + + # ('<', '0.1') conflicts with ('>', '0.1') + # ('<=', 0.1) conflicts with ('>=', 0.2) + # ('<', '0.1') conflicts with ('>', '0.2') + pass + +class Dependency(object): + def __init__(self): + self.min = None + self.max = None + + self.excludes = [] + + def is_unbounded(self): + return self.min == None and self.max == None + + def is_unconstrained(self): + return self.is_unbounded() and self.excludes == [] + + def set_absolute_version(self, version): + self.min = version + self.max = version + def find_build_deps(source, name, version=None): debug('source: %s' % source) debug('name: %s' % name) @@ -57,13 +105,38 @@ def find_build_deps(source, name, version=None): egg_dir = '%s.egg-info' % name build_deps_file = os.path.join(source, egg_dir, 'setup_requires.txt') + build_deps = {} + # Check whether there's a setup_requires.txt if not os.path.isfile(build_deps_file): print('%s has no build dependencies' % name) else: with open(build_deps_file) as f: for r in pkg_resources.parse_requirements(f): - print('%s%s' % (type(r), r.specs)) + print('%s %s' % (r.project_name, r.specs)) + + if r.project_name not in build_deps: + build_deps[r.project_name] = Dependency() + + for (op, version) in r.specs: + #if no_conflict(requirements_versions_map[r.project_name], s): + # requirements_versions_map[r.project_name] += s + dep = build_deps[r.project_name] + + if op == '==': + if dep.is_unconstrained(): + dep.set_absolute_version(version) + elif dep.is_unbounded()and version not in dep.excludes: + dep.set_absolute_version(version) + else: + error('conflict!') + # conflict + + # Resolve versions + #client = xmlrpclib.ServerProxy(PYPI_URL) + #releases = client.package_releases(requirement.name) + + return build_deps if len(sys.argv) not in [3, 4]: print('usage: %s PACKAGE_SOURCE_DIR NAME [VERSION]' % sys.argv[0]) @@ -73,4 +146,6 @@ if len(sys.argv) not in [3, 4]: # First, given a source return build dependencies in json from -find_build_deps(*sys.argv[1:])
\ No newline at end of file +for name, dep in find_build_deps(*sys.argv[1:]).iteritems(): + print('%s min: %s max: %s excludes: %s' + % (name, str(dep.min), str(dep.max), dep.excludes))
\ No newline at end of file diff --git a/exts/pip_lorry.py b/exts/pip_lorry.py index 8f7e3ab..4150ece 100755 --- a/exts/pip_lorry.py +++ b/exts/pip_lorry.py @@ -137,13 +137,18 @@ def specs_satisfied(version, specs): return all([get_op_func(op)(version, sv) for (op, sv) in specs]) -def generate_tarball_lorry(requirement): +def get_releases(requirement): try: - client = xmlrpclib.ServerProxy(PYPI_URL) releases = client.package_releases(requirement.name) except Exception as e: error("Couldn't fetch release data:", e) + return releases + +def generate_tarball_lorry(requirement): + client = xmlrpclib.ServerProxy(PYPI_URL) + releases = get_releases(requirement) + if len(releases) == 0: error("Couldn't find any releases for package %s" % requirement.name) |