@ -7,13 +7,14 @@ from collections import OrderedDict
from . . templates . format . contents_format import ContentsFormat
from . files import read_file , read_link , join_paths , FilesError
import hashlib
import operator
class PackageError ( Exception ) :
pass
DEFAULT , NOTEXIST , NOTCORRECT , MULTIPLE = range ( 4 )
DEFAULT , NOTEXIST , NOTCORRECT = range ( 3 )
class PackageAtomError ( Exception ) :
@ -22,12 +23,159 @@ class PackageAtomError(Exception):
self . errno = errno
class VersionError ( Exception ) :
pass
class Version :
''' Временный класс для работы с о значениями версий. '''
def __init__ ( self , version_value = None ) :
if version_value is None :
self . _version_string = ' -1 '
self . _version_value = - 1
elif isinstance ( version_value , Version ) :
self . _version_string = version_value . _version_string
self . _version_value = version_value . _version_value
else :
value = self . _get_version_value ( version_value )
if not value :
raise VersionError (
" Can ' t initialize Version object using ' {0} ' "
" value with type {1} " . format ( version_value ,
type ( version_value ) ) )
self . _version_string = str ( version_value )
self . _version_value = value
def _get_version_value ( self , version ) :
if isinstance ( version , Version ) :
return version . _version_value
elif isinstance ( version , int ) :
version_value = [ str ( version ) ]
elif isinstance ( version , float ) :
version_value = [ ]
version = str ( version ) . split ( ' . ' )
for version_part in version :
version_value . append ( int ( version_part . strip ( ) ) )
elif isinstance ( version , str ) :
version_value = [ ]
if ' - ' in version :
version = version . split ( ' - ' ) [ 0 ]
if ' _ ' in version :
version = version . split ( ' _ ' ) [ 0 ]
for version_part in version . split ( ' . ' ) :
if version_part . isdigit ( ) :
version_part = int ( version_part )
version_value . append ( version_part )
else :
return False
else :
return False
return version_value
def _use_compare_operation ( self , compare_operator , other_value ) :
''' Перегрузка x < y. '''
version_value = self . _version_value [ : ]
other_value_length = len ( other_value )
version_value_length = len ( version_value )
if other_value_length < version_value_length :
for counter in range ( version_value_length - other_value_length ) :
other_value . append ( 0 )
elif version_value_length < other_value_length :
for counter in range ( other_value_length - version_value_length ) :
version_value . append ( 0 )
for lvalue , rvalue in zip ( version_value , other_value ) :
if compare_operator ( lvalue , rvalue ) :
return True
def __lt__ ( self , other ) :
''' Перегрузка x < y. '''
other_value = self . _get_version_value ( other )
if not other_value :
raise VersionError (
" Unable to compare Version object with the ' {0} ' "
" value of ' {1} ' type " . format ( other , type ( other ) ) )
return self . _use_compare_operation ( operator . lt , other_value )
def __le__ ( self , other ) :
''' Перегрузка x <= y. '''
other_value = self . _get_version_value ( other )
if not other_value :
raise VersionError (
" Unable to compare Version object with the ' {0} ' "
" value of ' {1} ' type " . format ( other , type ( other ) ) )
return self . _use_compare_operation ( operator . le , other_value )
def __eq__ ( self , other ) :
''' Перегрузка x == y. '''
other_value = self . _get_version_value ( other )
if not other_value :
raise VersionError (
" Unable to compare Version object with the ' {0} ' "
" value of ' {1} ' type " . format ( other , type ( other ) ) )
return self . _use_compare_operation ( operator . eq , other_value )
def __ne__ ( self , other ) :
''' Перегрузка x != y. '''
other_value = self . _get_version_value ( other )
if not other_value :
raise VersionError (
" Unable to compare Version object with the ' {0} ' "
" value of ' {1} ' type " . format ( other , type ( other ) ) )
return self . _use_compare_operation ( operator . ne , other_value )
def __gt__ ( self , other ) :
''' Перегрузка x > y. '''
other_value = self . _get_version_value ( other )
if not other_value :
raise VersionError (
" Unable to compare Version object with the ' {0} ' "
" value of ' {1} ' type " . format ( other , type ( other ) ) )
return self . _use_compare_operation ( operator . gt , other_value )
def __ge__ ( self , other ) :
''' Перегрузка x >= y. '''
other_value = self . _get_version_value ( other )
if not other_value :
raise VersionError (
" Unable to compare Version object with the ' {0} ' "
" value of ' {1} ' type " . format ( other , type ( other ) ) )
return self . _use_compare_operation ( operator . ge , other_value )
def __hash__ ( self ) :
return hash ( self . _version_string )
def __repr__ ( self ) :
return ' <Version: {} > ' . format ( self . _version_string )
def __bool__ ( self ) :
if self . _version_value == [ - 1 ] :
return False
else :
return True
class PackageAtom :
atom_regex = re . compile ( r ''' (?P<category>[^ \ s/]*)/
( ? P < name > [ ^ \s : ] * )
( ? P < slot > : \S * ) ?
( ? P < uses > ( ? : \s + \S * ) * )
''' , re.VERBOSE)
( ? P < name > [ ^ \s \- : ] * )
( ? P < version > - \d [ ^ \s : ] * ) ?
( ? P < slot > : [ ^ \s \[ ] * ) ? \s *
( ? P < uses > \[ \S * ( ? : \s + \S * ) * \] ) ? ''' ,
re . VERBOSE )
def __init__ ( self , pkg_path = ' /var/db/pkg ' ,
chroot_path = ' / ' ) :
@ -41,72 +189,132 @@ class PackageAtom:
self . package_atom = ' '
self . _atom_dictionary = { }
def parse_package_parameter ( self , package_atom ,
add_slot = False , add_uses = False ) :
def parse_package_parameter ( self , package_atom ) :
self . package_atom = package_atom
self . _atom_dictionary = { }
parsing_result = self . atom_regex . search ( package_atom )
if not parsing_result or parsing_result . string != package_atom :
if ( not parsing_result or parsing_result . string != package_atom or
not parsing_result . groupdict ( ) [ ' category ' ] or
not parsing_result . groupdict ( ) [ ' name ' ] ) :
raise PackageAtomError ( " ' package ' parameter value ' {} ' is not "
" correct " . format ( package_atom ) ,
errno = NOTCORRECT )
if ' category ' in parsing_result . groupdict ( ) :
self . _atom_dictionary [ ' category ' ] = parsing_result . groupdict (
self . _atom_dictionary [ ' category ' ] = parsing_result . groupdict (
) [ ' category ' ]
if ' name ' in parsing_result . groupdict ( ) :
self . _atom_dictionary [ ' name ' ] = parsing_result . groupdict ( ) [ ' name ' ]
self . _atom_dictionary [ ' name ' ] = parsing_result . groupdict ( ) [ ' name ' ]
self . _check_package_existance ( )
if parsing_result . groupdict ( ) [ ' version ' ] :
version_value = parsing_result . groupdict ( ) [ ' version ' ] . strip ( ' - ' )
if ( ' slot ' in parsing_result . groupdict ( ) and
parsing_result . groupdict ( ) [ ' slot ' ] and
self . _atom_dictionary [ ' version ' ] = Version ( version_value )
if ( parsing_result . groupdict ( ) [ ' slot ' ] and
parsing_result . groupdict ( ) [ ' slot ' ] != ' : ' ) :
self . _atom_dictionary [ ' slot ' ] = parsing_result . groupdict (
) [ ' slot ' ] [ 1 : ]
elif add_slot :
self . _atom_dictionary [ ' slot ' ] = self . _get_slot_value ( )
if ( ' uses ' in parsing_result . groupdict ( ) and
parsing_result . groupdict ( ) [ ' uses ' ] ) :
if parsing_result . groupdict ( ) [ ' uses ' ] :
self . _atom_dictionary [ ' uses ' ] = [ ]
uses = parsing_result . groupdict ( ) [ ' uses ' ] . strip ( ) . split ( ' ' )
for use_flag in uses :
uses = parsing_result . groupdict ( ) [ ' uses ' ] . strip ( ) . rstrip ( ' ] ' ) . \
lstrip ( ' [ ' )
for use_flag in uses . split ( ) :
self . _atom_dictionary [ ' uses ' ] . append ( use_flag . strip ( ) )
elif add_uses :
self . _atom_dictionary [ ' uses ' ] = self . _get_use_flags_value ( )
self . _check_package_existance ( )
def _check_package_existance ( self , package_atom = ' ' ) :
if package_atom :
self . parse_package_parameter ( package_atom )
return True
elif ( self . _atom_dictionary [ ' category ' ] and
self . _atom_dictionary [ ' name ' ] ) :
glob_result = glob . glob (
' {0} / {1} / {2} */CONTENTS ' . format ( self . pkg_path ,
else :
if ' version ' in self . _atom_dictionary :
full_name = self . _atom_dictionary [ ' name ' ] + ' - ' + \
self . _atom_dictionary [ ' version ' ] . _version_string
else :
full_name = self . _atom_dictionary [ ' name ' ]
if ' version ' not in self . _atom_dictionary :
glob_result = glob . glob (
r ' {0} / {1} / {2} -[0-9]*/CONTENTS ' . format (
self . pkg_path ,
self . _atom_dictionary [ ' category ' ] ,
self . _atom_dictionary [ ' name ' ] ) )
full_name ) )
else :
glob_result = glob . glob (
r ' {0} / {1} / {2} */CONTENTS ' . format (
self . pkg_path ,
self . _atom_dictionary [ ' category ' ] ,
full_name ) )
if not glob_result :
raise PackageAtomError ( " Package from ' package ' parameter value "
" ' {} ' does not exist " . format (
self . package_atom ) ,
errno = NOTEXIST )
elif len ( glob_result ) == 1 :
if len ( glob_result ) == 1 :
contents_path = next ( iter ( glob_result ) )
self . _check_slot_value ( contents_path )
self . _check_use_flags_value ( contents_path )
self . _atom_dictionary [ ' name ' ] = contents_path . split ( ' / ' ) [ - 2 ]
self . _atom_dictionary [ ' contents ' ] = contents_path
else :
raise PackageAtomError ( " ' package ' parameter value ' {} ' matches "
" multiple installed packages " . format (
packages = dict ( )
for contents_path in glob_result :
package_info = dict ( )
try :
self . _check_slot_value ( contents_path )
self . _check_use_flags_value ( contents_path )
package_info [ ' name ' ] = contents_path . split ( ' / ' ) [ - 2 ]
package_info [ ' version ' ] = Version (
package_info [ ' name ' ] . split ( ' - ' , 1 ) [ 1 ] )
except PackageAtomError :
continue
packages [ contents_path ] = package_info
if not packages :
raise PackageAtomError (
" Package from ' package ' parameter value "
" ' {} ' does not exist " . format (
self . package_atom ) ,
errno = MULTIPLE )
errno = NOTEXIST )
if len ( packages ) == 1 :
contents_path = next ( iter ( packages . keys ( ) ) )
self . _atom_dictionary [ ' contents ' ] = contents_path
self . _atom_dictionary . update ( packages [ contents_path ] )
else :
contents_path = sorted (
packages . keys ( ) ,
key = lambda path : packages [ path ] [ ' version ' ] ) [ - 1 ]
self . _atom_dictionary [ ' contents ' ] = contents_path
self . _atom_dictionary . update ( packages [ contents_path ] )
def _check_slot_value ( self , contents_path ) :
slot = self . _get_slot_value ( contents_path )
if ' slot ' in self . _atom_dictionary :
if slot != self . _atom_dictionary [ ' slot ' ] :
raise PackageAtomError ( " Package from ' package ' parameter value "
" ' {} ' does not exist " . format (
self . package_atom ) ,
errno = NOTEXIST )
def _check_use_flags_value ( self , contents_path ) :
use_flags = self . _get_use_flags_value ( contents_path )
if ' uses ' in self . _atom_dictionary :
if self . _atom_dictionary [ ' uses ' ] not in use_flags :
raise PackageAtomError ( " Package from ' package ' parameter value "
" ' {} ' does not exist " . format (
self . package_atom ) ,
errno = NOTEXIST )
def _get_slot_value ( self ) :
contents_path = self . _atom_dictionary [ ' contents ' ]
def _get_slot_value ( self , contents_path ) :
slot_path = os . path . join ( os . path . dirname ( contents_path ) , ' SLOT ' )
try :
return read_file ( slot_path ) . strip ( ' \n ' )
@ -114,8 +322,7 @@ class PackageAtom:
raise PackageAtomError ( " could not read slot value for "
" ' package ' : {} " . format ( self . package_atom ) )
def _get_use_flags_value ( self ) :
contents_path = self . _atom_dictionary [ ' contents ' ]
def _get_use_flags_value ( self , contents_path ) :
use_path = os . path . join ( os . path . dirname ( contents_path ) , ' USE ' )
try :
return read_file ( use_path ) . strip ( ' \n ' ) . split ( ' ' )