summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Ipsum <richard.ipsum@codethink.co.uk>2014-11-05 16:14:49 +0000
committerRichard Ipsum <richard.ipsum@codethink.co.uk>2014-11-05 16:14:49 +0000
commit20038fd313146bd55b6acf6b268b8f5558437d54 (patch)
tree310739f28aafae120f688447a863bde81018cd80
parent5f28712029f39b61d7af3a0f1ee8b49e17917865 (diff)
downloadimport-20038fd313146bd55b6acf6b268b8f5558437d54.tar.gz
Add the beginnings of this conflict detection
-rw-r--r--README2
-rwxr-xr-xexts/pip.find_deps79
-rwxr-xr-xexts/pip_lorry.py9
3 files changed, 85 insertions, 5 deletions
diff --git a/README b/README
index 2922ea4..5b3ed28 100644
--- a/README
+++ b/README
@@ -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)