<s> from pyparsing import ( <EOL> ParserElement , LineEnd , CharsNotIn , Group , Word , <EOL> alphanums , Literal , Combine , ZeroOrMore , nums , <EOL> Optional , delimitedList , restOfLine , <EOL> Or , _ustr , MatchFirst <EOL> ) <EOL> from itertools import chain <EOL> DEPENDENCY_DELIMITERS = PROVIDES_DELIMITERS = [ '<STR_LIT:U+002C>' ] <EOL> DEPENDENCY_INTERLIMITERS = [ '<STR_LIT:|>' ] <EOL> class ControlFileParagraph ( dict ) : <EOL> def __init__ ( self , source ) : <EOL> self . provides_delimiters = self . dependency_delimiters = DEPENDENCY_DELIMITERS <EOL> self . dependency_interlimiters = DEPENDENCY_INTERLIMITERS <EOL> self . _keys = [ ] <EOL> self . _parse ( source ) <EOL> super ( ControlFileParagraph , self ) . __init__ ( ) <EOL> def _parse_items ( self , source ) : <EOL> ParserElement . setDefaultWhitespaceChars ( '<STR_LIT>' ) <EOL> EOL = LineEnd ( ) . suppress ( ) <EOL> comment = Literal ( '<STR_LIT:#>' ) + Optional ( restOfLine ) + EOL <EOL> string = CharsNotIn ( "<STR_LIT:\n>" ) <EOL> line = Group ( <EOL> Word ( alphanums + '<STR_LIT:->' ) ( '<STR_LIT:key>' ) + Literal ( '<STR_LIT::>' ) . suppress ( ) + Optional ( Combine ( string + ZeroOrMore ( EOL + Literal ( '<STR_LIT:U+0020>' ) + string ) ) ) ( "<STR_LIT:value>" ) + EOL <EOL> ) <EOL> group = ZeroOrMore ( line ) <EOL> group . ignore ( comment ) <EOL> return group . parseString ( source , True ) <EOL> def _att_key ( self , key ) : <EOL> return key . lower ( ) . replace ( '<STR_LIT:->' , '<STR_LIT:_>' ) <EOL> def _parse ( self , source ) : <EOL> for row in self . _parse_items ( source ) : <EOL> key , value = row . key , row . value <EOL> att_key = self . _att_key ( key ) <EOL> if hasattr ( self , '<STR_LIT>' % att_key ) : <EOL> value = getattr ( self , '<STR_LIT>' % att_key ) ( value ) <EOL> self [ key ] = value <EOL> def dump ( self ) : <EOL> out = [ ] <EOL> for key in self . _keys : <EOL> att_key = self . _att_key ( key ) <EOL> value = self [ att_key ] <EOL> if hasattr ( self , '<STR_LIT>' % att_key ) : <EOL> value = getattr ( self , '<STR_LIT>' % att_key ) ( value ) <EOL> out . append ( '<STR_LIT>' % ( key , value ) ) <EOL> return '<STR_LIT:\n>' . join ( out ) <EOL> __str__ = dump <EOL> def __repr__ ( self ) : <EOL> try : <EOL> return '<STR_LIT>' % self <EOL> except : <EOL> return '<STR_LIT>' % super ( ControlFileParagraph , self ) . __repr__ ( ) <EOL> def __getitem__ ( self , name ) : <EOL> att_key = self . _att_key ( name ) <EOL> return super ( ControlFileParagraph , self ) . __getitem__ ( att_key ) <EOL> def __setitem__ ( self , name , value ) : <EOL> att_key = self . _att_key ( name ) <EOL> if att_key in self : <EOL> super ( ControlFileParagraph , self ) . __setitem__ ( att_key , value ) <EOL> else : <EOL> self . _keys . append ( name ) <EOL> super ( ControlFileParagraph , self ) . __setitem__ ( att_key , value ) <EOL> class Dependency ( object ) : <EOL> def __init__ ( self , name , version = '<STR_LIT>' , sign = '<STR_LIT>' ) : <EOL> self . name , self . version , self . sign = name , version , sign <EOL> def __str__ ( self ) : <EOL> if self . sign : <EOL> return '<STR_LIT>' % ( self . name , self . sign , self . version ) <EOL> else : <EOL> if self . version : <EOL> return '<STR_LIT>' % ( self . name , self . version ) <EOL> return self . name <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT>' % ( self . name , self . version , self . sign ) <EOL> def is_versioned ( self ) : <EOL> return bool ( self . version and not self . sign ) <EOL> class Provider ( Dependency ) : <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT>' % ( self . name , self . version , self . sign ) <EOL> def get_versioned_package ( name , klass , sign = '<STR_LIT>' , version = '<STR_LIT>' ) : <EOL> if version and not sign : <EOL> sign = '<STR_LIT:=>' <EOL> if not version : <EOL> package_name = name . rstrip ( nums + '<STR_LIT>' ) <EOL> if package_name != name : <EOL> version_candidate = name [ len ( package_name ) : ] <EOL> if version_candidate [ <NUM_LIT:0> ] == '<STR_LIT:->' : <EOL> version = version_candidate [ <NUM_LIT:1> : ] <EOL> name = package_name <EOL> return klass ( name , version , sign ) <EOL> def get_dependency ( name , sign = '<STR_LIT>' , version = '<STR_LIT>' ) : <EOL> return get_versioned_package ( name = name , klass = Dependency , sign = sign , version = version ) <EOL> def get_provider ( name , sign = '<STR_LIT>' , version = '<STR_LIT>' ) : <EOL> return get_versioned_package ( name = name , klass = Provider , sign = sign , version = version ) <EOL> class SourceParagraph ( ControlFileParagraph ) : <EOL> pass <EOL> class PackageParagraph ( ControlFileParagraph ) : <EOL> def parse_package ( self , value ) : <EOL> return get_dependency ( value ) <EOL> def parse_provides ( self , value ) : <EOL> package_name = Word ( alphanums + '<STR_LIT>' ) ( '<STR_LIT:name>' ) <EOL> version = Word ( nums + '<STR_LIT>' ) ( '<STR_LIT:version>' ) <EOL> sign = Or ( map ( Literal , ( '<STR_LIT:>>' , '<STR_LIT:<>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT:=>' , ) ) ) ( '<STR_LIT>' ) <EOL> provider = ( <EOL> ( <EOL> package_name + <EOL> Literal ( '<STR_LIT:(>' ) . suppress ( ) + <EOL> Optional ( sign ) ( '<STR_LIT>' ) + <EOL> version + <EOL> Literal ( '<STR_LIT:)>' ) . suppress ( ) <EOL> ) | ( <EOL> package_name <EOL> ) <EOL> ) . setParseAction ( lambda x : get_provider ( x . name , x . sign , x . version ) ) <EOL> providers = Optional ( delimitedList ( provider , '<STR_LIT:U+002C>' ) ) <EOL> return providers . parseString ( value , True ) . asList ( ) <EOL> def parse_depends ( self , value ) : <EOL> package_name = Word ( alphanums + '<STR_LIT>' ) ( '<STR_LIT:name>' ) <EOL> version = Combine ( <EOL> Word ( nums + '<STR_LIT>' ) + Optional ( Literal ( '<STR_LIT>' ) + Word ( alphanums + '<STR_LIT:+>' ) ) <EOL> ) ( '<STR_LIT:version>' ) <EOL> sign = Or ( map ( Literal , ( '<STR_LIT:>>' , '<STR_LIT:<>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT:=>' , ) ) ) ( '<STR_LIT>' ) <EOL> dependency = ( <EOL> ( <EOL> package_name + <EOL> Literal ( '<STR_LIT:(>' ) . suppress ( ) + <EOL> Optional ( sign ) ( '<STR_LIT>' ) + <EOL> version + <EOL> Literal ( '<STR_LIT:)>' ) . suppress ( ) <EOL> ) | ( <EOL> package_name <EOL> ) <EOL> ) . setParseAction ( lambda x : get_dependency ( x . name , x . sign , x . version ) ) <EOL> delim = MatchFirst ( [ ] ) <EOL> for i in self . dependency_delimiters + self . dependency_interlimiters : <EOL> delim = delim | Literal ( i ) <EOL> dlName = _ustr ( dependency ) + "<STR_LIT>" + _ustr ( delim ) + "<STR_LIT:U+0020>" + _ustr ( dependency ) + "<STR_LIT>" <EOL> dependencies = Optional ( ( dependency + ZeroOrMore ( delim + dependency ) ) . setName ( dlName ) ) <EOL> return dependencies . parseString ( value , True ) . asList ( ) <EOL> def dump_depends ( self , value ) : <EOL> out = '<STR_LIT>' <EOL> for v in value : <EOL> if v in self . dependency_delimiters : <EOL> out += '<STR_LIT>' % v <EOL> elif v in self . dependency_interlimiters : <EOL> out += '<STR_LIT>' % v <EOL> else : <EOL> out += str ( v ) <EOL> return out <EOL> def dump_provides ( self , value ) : <EOL> out = '<STR_LIT>' <EOL> for v in value : <EOL> if v in self . provides_delimiters : <EOL> out += '<STR_LIT>' % v <EOL> else : <EOL> out += str ( v ) <EOL> return out <EOL> class ControlFile ( object ) : <EOL> DEFAULT_SOURCE_PARAGRAPH = """<STR_LIT>""" <EOL> DEFAULT_PACKAGE_PARAGRAPH = """<STR_LIT>""" <EOL> def __init__ ( self , source = None , filename = '<STR_LIT>' ) : <EOL> if filename : <EOL> f = open ( filename ) <EOL> source = f . read ( ) <EOL> f . close <EOL> if source : <EOL> paragraphs = source . split ( '<STR_LIT>' ) <EOL> else : <EOL> paragraphs = [ self . DEFAULT_SOURCE_PARAGRAPH ] <EOL> if not paragraphs : <EOL> raise NotImplementedError ( ) <EOL> self . source = SourceParagraph ( paragraphs [ <NUM_LIT:0> ] ) <EOL> self . packages = [ ] <EOL> for s in paragraphs [ <NUM_LIT:1> : ] : <EOL> if s : <EOL> self . add_package ( s ) <EOL> def add_package ( self , source = None ) : <EOL> package = PackageParagraph ( source or self . DEFAULT_PACKAGE_PARAGRAPH ) <EOL> self . packages . append ( package ) <EOL> return package <EOL> def get_dependencies ( self ) : <EOL> return chain ( * ( [ i for i in p . get ( '<STR_LIT>' , [ ] ) if i not in DEPENDENCY_DELIMITERS + DEPENDENCY_INTERLIMITERS ] for p in self . packages ) ) <EOL> def get_provides ( self ) : <EOL> return chain ( * ( [ i for i in p . get ( '<STR_LIT>' , [ ] ) if i not in PROVIDES_DELIMITERS ] for p in self . packages ) ) <EOL> def get_versioned_dependencies ( self ) : <EOL> return [ d for d in self . get_dependencies ( ) if d . is_versioned ( ) ] <EOL> def get_packages ( self ) : <EOL> return [ p [ '<STR_LIT>' ] for p in self . packages ] <EOL> def check_downgrade ( self , current_version , new_version ) : <EOL> """<STR_LIT>""" <EOL> curr_tuple = map ( int , current_version . split ( "<STR_LIT:.>" ) ) <EOL> new_tuple = map ( int , new_version . split ( "<STR_LIT:.>" ) ) <EOL> for i in xrange ( <NUM_LIT:0> , len ( curr_tuple ) ) : <EOL> if len ( new_tuple ) < ( i + <NUM_LIT:1> ) : <EOL> raise ValueError ( "<STR_LIT>" % ( <EOL> current_version , <EOL> new_version , <EOL> self . _pname , <EOL> ) ) <EOL> elif new_tuple [ i ] > curr_tuple [ i ] : <EOL> return True <EOL> elif ( new_tuple [ i ] < curr_tuple [ i ] ) : <EOL> raise ValueError ( "<STR_LIT>" % ( <EOL> current_version , <EOL> new_version , <EOL> self . _pname , <EOL> ) ) <EOL> return True <EOL> def replace_dependencies ( self , deps_from_repositories ) : <EOL> new_versions = dict ( ( p . name , p . version ) for p in deps_from_repositories ) <EOL> for p in self . get_dependencies ( ) : <EOL> if p . name in new_versions : <EOL> self . _pname = p . name <EOL> new_version = new_versions [ p . name ] <EOL> self . check_downgrade ( p . version , new_version ) <EOL> p . version = new_version <EOL> def replace_provides ( self , deps_from_repositories ) : <EOL> new_versions = dict ( ( p . name , p . version ) for p in deps_from_repositories ) <EOL> for p in self . get_provides ( ) : <EOL> if p . name in new_versions : <EOL> self . _pname = p . name <EOL> new_version = new_versions [ p . name ] <EOL> self . check_downgrade ( p . version , new_version ) <EOL> p . version = new_version <EOL> def replace_versioned_packages ( self , version , old_version = '<STR_LIT>' ) : <EOL> self . replace_versioned_dependencies ( version , old_version ) <EOL> self . replace_versioned_provides ( version , old_version ) <EOL> def replace_versioned_dependencies ( self , version , old_version = '<STR_LIT>' ) : <EOL> new_deps = [ ] <EOL> for p in self . get_packages ( ) : <EOL> if p . version and p . version == old_version : <EOL> p . version = version <EOL> new_deps . append ( p ) <EOL> self . replace_dependencies ( new_deps ) <EOL> def replace_versioned_provides ( self , version , old_version = '<STR_LIT>' ) : <EOL> new_deps = [ ] <EOL> for p in self . get_provides ( ) : <EOL> if p . version and p . version == old_version : <EOL> p . version = version <EOL> new_deps . append ( p ) <EOL> self . replace_provides ( new_deps ) <EOL> return new_deps <EOL> def dump ( self , filename = None ) : <EOL> out = '<STR_LIT>' . join ( p . dump ( ) for p in [ self . source ] + self . packages ) <EOL> if filename : <EOL> fout = open ( filename , '<STR_LIT:w>' ) <EOL> fout . write ( out ) <EOL> fout . close ( ) <EOL> return out </s>
