-
-
Save uranusjr/a7a9f20c6e43810bd19f0c73e9617182 to your computer and use it in GitHub Desktop.
Make an ordered list of sdists to be installed
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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