Skip to content

Instantly share code, notes, and snippets.

@uranusjr
Last active July 23, 2018 20:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save uranusjr/a7a9f20c6e43810bd19f0c73e9617182 to your computer and use it in GitHub Desktop.
Save uranusjr/a7a9f20c6e43810bd19f0c73e9617182 to your computer and use it in GitHub Desktop.
Make an ordered list of sdists to be installed
import os
import subprocess
import sys
import mixology
import mixology.contracts.ui
import requests
class SpecificationProvider(object):
def __init__(self, lookup):
self.lookup = lookup
def search_for(self, dependency):
"""Find candidates what satisfy an abstract dependency.
"""
return [self.lookup[dependency]]
def dependencies_for(self, specification):
"""Find (abstract) dependencies for a package.
Here we use the PyPI's JSON API to do it quick-n-dirty.
"""
package, version, _ = specification
url = 'https://pypi.org/pypi/{}/{}/json'.format(package, version)
response = requests.get(url)
response.raise_for_status()
dependencies = set(
name for name in (
s.split(' ', 1)[0].lower().rstrip(';')
for s in (response.json()['info']['requires_dist'] or [])
) if name in self.lookup
)
return list(dependencies)
def is_requirement_satisfied_by(self, requirement, activated, spec):
"""Does a candidate satisfy a requirement?
We don't care about versions, so the answer is always yes.
"""
return True
def name_for(self, dependency):
"""Returns the name for the given dependency.
A candidate is a 3-tuple, first entry being the name.
A requirement is identified by the name directly.
"""
if isinstance(dependency, tuple):
return dependency[0]
return dependency
def sort_dependencies(self, dependencies, activated, conflicts):
return list(dependencies)
def allow_missing(self, dependency):
return False
def ensure_working_directory():
work = os.path.join(os.path.dirname(__file__), 'work')
if not os.path.isdir(work):
os.mkdir(work)
os.chdir(work)
def parse_package_info(filename):
for ext in ('.tar.gz', '.zip'): # PyPI actually supports a lot more.
if filename.endswith(ext):
package, version = filename[:-len(ext)].rsplit('-', 1)
return (package.lower(), version, filename)
raise ValueError('{} not recognized'.format(filename))
def get_packages(root):
subprocess.check_call(['pip', 'download', '--no-binary=:all:', root])
return [parse_package_info(n) for n in os.listdir()]
def insert_specs(ordered_filenames, edges):
for edge in edges:
vertex = edge.destination
try:
del ordered_filenames[ordered_filenames.index(vertex.payload[-1])]
except ValueError:
pass
index = min(
ordered_filenames.index(e.origin.payload[-1])
for e in vertex.incoming_edges
if e.origin.payload[-1] in ordered_filenames
)
ordered_filenames.insert(index, vertex.payload[-1])
insert_specs(ordered_filenames, vertex.outgoing_edges)
def main():
root = sys.argv[1]
ensure_working_directory()
package_infos = get_packages(root)
lookup = {info[0]: info for info in package_infos}
provider = SpecificationProvider(lookup)
ui = mixology.contracts.ui.UI(debug=True)
resolver = mixology.Resolver(provider, ui)
graph = resolver.resolve([root.split('[', 1)[0]])
vertex = next(iter(graph))
ordered_filenames = [vertex.payload[-1]]
insert_specs(ordered_filenames, vertex.outgoing_edges)
print('Ordering:')
for filename in ordered_filenames:
print(' ', filename)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment