<s> from __future__ import print_function <EOL> import os <EOL> import shutil <EOL> import time <EOL> from collections import namedtuple <EOL> from pkg_resources import safe_name <EOL> from . common import safe_mkdir <EOL> from . fetcher import Fetcher <EOL> from . interpreter import PythonInterpreter <EOL> from . iterator import Iterator , IteratorInterface <EOL> from . orderedset import OrderedSet <EOL> from . package import Package , distribution_compatible <EOL> from . platforms import Platform <EOL> from . resolvable import ResolvableRequirement , resolvables_from_iterable <EOL> from . resolver_options import ResolverOptionsBuilder <EOL> from . tracer import TRACER <EOL> from . util import DistributionHelper <EOL> class Untranslateable ( Exception ) : <EOL> pass <EOL> class Unsatisfiable ( Exception ) : <EOL> pass <EOL> class StaticIterator ( IteratorInterface ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , packages ) : <EOL> self . _packages = packages <EOL> def iter ( self , req ) : <EOL> for package in self . _packages : <EOL> if package . satisfies ( req ) : <EOL> yield package <EOL> class _ResolvedPackages ( namedtuple ( '<STR_LIT>' , '<STR_LIT>' ) ) : <EOL> @ classmethod <EOL> def empty ( cls ) : <EOL> return cls ( None , OrderedSet ( ) , None ) <EOL> def merge ( self , other ) : <EOL> if other . resolvable is None : <EOL> return _ResolvedPackages ( self . resolvable , self . packages , self . parent ) <EOL> return _ResolvedPackages ( <EOL> self . resolvable , <EOL> self . packages & other . packages , <EOL> self . parent ) <EOL> class _ResolvableSet ( object ) : <EOL> @ classmethod <EOL> def normalize ( cls , name ) : <EOL> return safe_name ( name ) . lower ( ) <EOL> def __init__ ( self , tuples = None ) : <EOL> self . __tuples = tuples or [ ] <EOL> def _collapse ( self ) : <EOL> resolvables = { } <EOL> for resolved_packages in self . __tuples : <EOL> key = self . normalize ( resolved_packages . resolvable . name ) <EOL> previous = resolvables . get ( key , _ResolvedPackages . empty ( ) ) <EOL> if previous . resolvable is None : <EOL> resolvables [ key ] = resolved_packages <EOL> else : <EOL> resolvables [ key ] = previous . merge ( resolved_packages ) <EOL> return resolvables <EOL> def _synthesize_parents ( self , name ) : <EOL> def render_resolvable ( resolved_packages ) : <EOL> return '<STR_LIT>' % ( <EOL> str ( resolved_packages . resolvable ) , <EOL> '<STR_LIT>' % resolved_packages . parent if resolved_packages . parent else '<STR_LIT>' ) <EOL> return '<STR_LIT:U+002CU+0020>' . join ( <EOL> render_resolvable ( resolved_packages ) for resolved_packages in self . __tuples <EOL> if self . normalize ( resolved_packages . resolvable . name ) == self . normalize ( name ) ) <EOL> def _check ( self ) : <EOL> for name , resolved_packages in self . _collapse ( ) . items ( ) : <EOL> if not resolved_packages . packages : <EOL> raise Unsatisfiable ( '<STR_LIT>' % ( <EOL> resolved_packages . resolvable , self . _synthesize_parents ( name ) ) ) <EOL> def merge ( self , resolvable , packages , parent = None ) : <EOL> """<STR_LIT>""" <EOL> self . __tuples . append ( _ResolvedPackages ( resolvable , OrderedSet ( packages ) , parent ) ) <EOL> self . _check ( ) <EOL> def get ( self , name ) : <EOL> """<STR_LIT>""" <EOL> resolvable , packages , parent = self . _collapse ( ) . get ( <EOL> self . normalize ( name ) , _ResolvedPackages . empty ( ) ) <EOL> return packages <EOL> def packages ( self ) : <EOL> """<STR_LIT>""" <EOL> return list ( self . _collapse ( ) . values ( ) ) <EOL> def extras ( self , name ) : <EOL> return set . union ( <EOL> * [ set ( tup . resolvable . extras ( ) ) for tup in self . __tuples <EOL> if self . normalize ( tup . resolvable . name ) == self . normalize ( name ) ] ) <EOL> def replace_built ( self , built_packages ) : <EOL> """<STR_LIT>""" <EOL> def map_packages ( resolved_packages ) : <EOL> packages = OrderedSet ( built_packages . get ( p , p ) for p in resolved_packages . packages ) <EOL> return _ResolvedPackages ( resolved_packages . resolvable , packages , resolved_packages . parent ) <EOL> return _ResolvableSet ( [ map_packages ( rp ) for rp in self . __tuples ] ) <EOL> class Resolver ( object ) : <EOL> """<STR_LIT>""" <EOL> class Error ( Exception ) : pass <EOL> @ classmethod <EOL> def filter_packages_by_interpreter ( cls , packages , interpreter , platform ) : <EOL> return [ package for package in packages <EOL> if package . compatible ( interpreter . identity , platform ) ] <EOL> def __init__ ( self , interpreter = None , platform = None ) : <EOL> self . _interpreter = interpreter or PythonInterpreter . get ( ) <EOL> self . _platform = platform or Platform . current ( ) <EOL> def package_iterator ( self , resolvable , existing = None ) : <EOL> if existing : <EOL> existing = resolvable . compatible ( StaticIterator ( existing ) ) <EOL> else : <EOL> existing = resolvable . packages ( ) <EOL> return self . filter_packages_by_interpreter ( existing , self . _interpreter , self . _platform ) <EOL> def build ( self , package , options ) : <EOL> context = options . get_context ( ) <EOL> translator = options . get_translator ( self . _interpreter , self . _platform ) <EOL> with TRACER . timed ( '<STR_LIT>' % package . url , V = <NUM_LIT:2> ) : <EOL> local_package = Package . from_href ( context . fetch ( package ) ) <EOL> if local_package is None : <EOL> raise Untranslateable ( '<STR_LIT>' % package ) <EOL> with TRACER . timed ( '<STR_LIT>' % local_package . local_path , V = <NUM_LIT:2> ) : <EOL> dist = translator . translate ( local_package ) <EOL> if dist is None : <EOL> raise Untranslateable ( '<STR_LIT>' % ( package , translator ) ) <EOL> if not distribution_compatible ( dist , self . _interpreter , self . _platform ) : <EOL> raise Untranslateable ( <EOL> '<STR_LIT>' % ( package , self . _platform ) ) <EOL> return dist <EOL> def resolve ( self , resolvables , resolvable_set = None ) : <EOL> resolvables = [ ( resolvable , None ) for resolvable in resolvables ] <EOL> resolvable_set = resolvable_set or _ResolvableSet ( ) <EOL> processed_resolvables = set ( ) <EOL> processed_packages = { } <EOL> distributions = { } <EOL> while resolvables : <EOL> while resolvables : <EOL> resolvable , parent = resolvables . pop ( <NUM_LIT:0> ) <EOL> if resolvable in processed_resolvables : <EOL> continue <EOL> packages = self . package_iterator ( resolvable , existing = resolvable_set . get ( resolvable . name ) ) <EOL> resolvable_set . merge ( resolvable , packages , parent ) <EOL> processed_resolvables . add ( resolvable ) <EOL> built_packages = { } <EOL> for resolvable , packages , parent in resolvable_set . packages ( ) : <EOL> assert len ( packages ) > <NUM_LIT:0> , '<STR_LIT>' % resolvable <EOL> package = next ( iter ( packages ) ) <EOL> if resolvable . name in processed_packages : <EOL> if package != processed_packages [ resolvable . name ] : <EOL> raise self . Error ( '<STR_LIT>' % resolvable ) <EOL> continue <EOL> if package not in distributions : <EOL> dist = self . build ( package , resolvable . options ) <EOL> built_package = Package . from_href ( dist . location ) <EOL> built_packages [ package ] = built_package <EOL> distributions [ built_package ] = dist <EOL> package = built_package <EOL> distribution = distributions [ package ] <EOL> processed_packages [ resolvable . name ] = package <EOL> new_parent = '<STR_LIT>' % ( parent , resolvable ) if parent else str ( resolvable ) <EOL> resolvables . extend ( <EOL> ( ResolvableRequirement ( req , resolvable . options ) , new_parent ) for req in <EOL> distribution . requires ( extras = resolvable_set . extras ( resolvable . name ) ) ) <EOL> resolvable_set = resolvable_set . replace_built ( built_packages ) <EOL> return list ( distributions . values ( ) ) <EOL> class CachingResolver ( Resolver ) : <EOL> """<STR_LIT>""" <EOL> @ classmethod <EOL> def filter_packages_by_ttl ( cls , packages , ttl , now = None ) : <EOL> now = now if now is not None else time . time ( ) <EOL> return [ package for package in packages <EOL> if package . remote or package . local and ( now - os . path . getmtime ( package . local_path ) ) < ttl ] <EOL> def __init__ ( self , cache , cache_ttl , * args , ** kw ) : <EOL> self . __cache = cache <EOL> self . __cache_ttl = cache_ttl <EOL> safe_mkdir ( self . __cache ) <EOL> super ( CachingResolver , self ) . __init__ ( * args , ** kw ) <EOL> def package_iterator ( self , resolvable , existing = None ) : <EOL> iterator = Iterator ( fetchers = [ Fetcher ( [ self . __cache ] ) ] ) <EOL> packages = self . filter_packages_by_interpreter ( <EOL> resolvable . compatible ( iterator ) , self . _interpreter , self . _platform ) <EOL> if packages : <EOL> if resolvable . exact : <EOL> return packages <EOL> if self . __cache_ttl : <EOL> packages = self . filter_packages_by_ttl ( packages , self . __cache_ttl ) <EOL> if packages : <EOL> return packages <EOL> return super ( CachingResolver , self ) . package_iterator ( resolvable , existing = existing ) <EOL> def build ( self , package , options ) : <EOL> if package . remote : <EOL> package = Package . from_href ( options . get_context ( ) . fetch ( package , into = self . __cache ) ) <EOL> os . utime ( package . local_path , None ) <EOL> dist = super ( CachingResolver , self ) . build ( package , options ) <EOL> target = os . path . join ( self . __cache , os . path . basename ( dist . location ) ) <EOL> if not os . path . exists ( target ) : <EOL> shutil . copyfile ( dist . location , target + '<STR_LIT>' ) <EOL> os . rename ( target + '<STR_LIT>' , target ) <EOL> os . utime ( target , None ) <EOL> return DistributionHelper . distribution_from_path ( target ) <EOL> def resolve ( <EOL> requirements , <EOL> fetchers = None , <EOL> interpreter = None , <EOL> platform = None , <EOL> context = None , <EOL> precedence = None , <EOL> cache = None , <EOL> cache_ttl = None ) : <EOL> """<STR_LIT>""" <EOL> builder = ResolverOptionsBuilder ( <EOL> fetchers = fetchers , <EOL> precedence = precedence , <EOL> context = context , <EOL> ) <EOL> if cache : <EOL> resolver = CachingResolver ( cache , cache_ttl , interpreter = interpreter , platform = platform ) <EOL> else : <EOL> resolver = Resolver ( interpreter = interpreter , platform = platform ) <EOL> return resolver . resolve ( resolvables_from_iterable ( requirements , builder ) ) </s>
