@ -10,7 +10,6 @@ from pyparsing import Literal, Regex, Word, nums, alphanums,\
from jinja2 import PackageLoader , Environment
from jinja2 import PackageLoader , Environment
from calculate . utils . tools import Singleton
from calculate . utils . tools import Singleton
import hashlib
import hashlib
import operator
class PackageError ( Exception ) :
class PackageError ( Exception ) :
@ -42,169 +41,233 @@ class PackageNotFound(Exception):
class Version :
class Version :
_suffix_order = { ' alpha ' : 0 , ' beta ' : 1 , ' pre ' : 2 ,
' rc ' : 3 , ' no ' : 4 , ' p ' : 5 }
''' Класс для работы с о значениями версий. '''
''' Класс для работы с о значениями версий. '''
def __init__ ( self , version_value = None ) :
def __init__ ( self , version_value = None ) :
if version_value is None :
if version_value is None :
self . _version_string = ' -1 '
self . _string = ' -1 '
self . _version_value = [ - 1 ]
self . _value = [ - 1 ]
self . _literal = None
self . _suffix = [ ( 4 , 0 ) ]
self . _revision = 0
elif isinstance ( version_value , Version ) :
elif isinstance ( version_value , Version ) :
self . _version_string = version_value . _version_string
self . _string = version_value . _string
self . _version_value = version_value . _version_value
self . _value = version_value . _value
self . _literal = version_value . _literal
self . _suffix = version_value . _suffix
self . _revision = version_value . _revision
else :
else :
value = self . _get_version_value ( version_value )
value = self . _get_version_value ( version_value )
if not value :
if valu e is Non e:
raise VersionError (
raise VersionError (
" Can ' t initialize Version object using ' {0} ' "
" Can ' t initialize Version object using ' {0} ' "
" value with type {1} " . format ( version_value ,
" value with type {1} " . format ( version_value ,
type ( version_value ) ) )
type ( version_value ) ) )
if isinstance ( version_value , str ) :
self . _string = value [ ' string ' ]
self . _version_string = version_value . strip ( ' - ' )
self . _value = value [ ' value ' ]
else :
self . _literal = value [ ' literal ' ]
self . _version_string = str ( version_value )
self . _suffix = value [ ' suffix ' ]
self . _revision = value [ ' revision ' ]
self . _version_value = value
def _get_version_value ( self , version ) :
def _get_version_value ( self , version ) :
''' Вспомогательный метод для получения значения версии, представленного
''' Вспомогательный метод для получения значения версии, представленного
в виде списка . '''
в виде списка . '''
if isinstance ( version , Version ) :
if isinstance ( version , Version ) :
return version . _version_value
version_value = { ' string ' : version . _string ,
' value ' : version . _value ,
' literal ' : version . _literal ,
' suffix ' : version . _suffix ,
' revision ' : version . _revision }
elif isinstance ( version , int ) :
elif isinstance ( version , int ) :
version_value = [ str ( version ) ]
version_value = { ' string ' : str ( int ) ,
' value ' : [ version ] ,
' literal ' : ' ' ,
' suffix ' : [ ( 4 , 0 ) ] ,
' revision ' : 0 }
elif isinstance ( version , float ) :
elif isinstance ( version , float ) :
version_value = [ ]
version_ list = [ ]
version = str ( version ) . split ( ' . ' )
version = str ( version ) . split ( ' . ' )
for version_part in version :
for version_part in version :
version_value . append ( int ( version_part . strip ( ) ) )
version_list . append ( int ( version_part . strip ( ) ) )
version_value = { ' string ' : str ( version ) ,
' value ' : version_list ,
' literal ' : ' ' ,
' suffix ' : ( 4 , 0 ) ,
' revision ' : 0 }
elif isinstance ( version , str ) :
elif isinstance ( version , str ) :
version = version . strip ( ' - ' )
version_value = [ ]
parse_result = PackageAtomParser . version_regex . search (
version . strip ( ' - ' ) )
if ' - ' in version :
if not parse_result :
version = version . split ( ' - ' ) [ 0 ]
return
if ' _ ' in version :
result_dict = parse_result . groupdict ( )
version = version . split ( ' _ ' ) [ 0 ]
version_value = { ' string ' : version }
for version_part in version . split ( ' . ' ) :
version_list = [ ]
if version_part . isdigit ( ) :
for version_part in result_dict [ ' value ' ] . split ( ' . ' ) :
version_part = int ( version_part )
version_list . append ( int ( version_part . strip ( ' - ' ) ) )
version_value . append ( version_part )
version_value [ ' value ' ] = version_list
# Парсим литерал, если он есть.
version_value [ ' literal ' ] = result_dict [ ' literal ' ] or ' '
# Парсим всю совокупность имеющихся суффиксов.
print ( ' result dict: ' , result_dict )
suffixes = result_dict [ ' suffix ' ]
print ( ' suffixes: ' , suffixes )
suffix_list = [ ]
if suffixes is not None :
suffixes = suffixes . strip ( ' _ ' )
suffixes = suffixes . split ( ' _ ' )
for suffix in suffixes :
result = re . search ( r ' ([^ \ d]+)( \ d+)? ' , suffix )
suffix_list . append ( ( self . _suffix_order [ result . group ( 1 ) ] ,
int ( result . group ( 2 ) or 0 ) ) )
else :
else :
return False
suffix_list = [ ( self . _suffix_order [ ' no ' ] , 0 ) ]
version_value [ ' suffix ' ] = suffix_list
# Парсим ревизию.
if parse_result [ ' revision ' ] is not None :
version_value [ ' revision ' ] = int (
parse_result [ ' revision ' ] . strip ( ' -r ' ) )
else :
else :
return False
version_value [ ' revision ' ] = 0
else :
return
return version_value
return version_value
def _use_compare_operation ( self , compare_operator , other_value ) :
def _compare_lists ( self , lversion , rversion , filler = 0 ) :
''' Вспомогательный метод для реализации различных операций сравнения.
''' Метод для сравнения двух списков, даже если если они не одинаковы.
'''
Возвращает 0 , если списки равны , 1 если lversion больше , - 1 если
version_value = self . _version_value [ : ]
lversion меньше . '''
if lversion == rversion :
other_value_length = len ( other_value )
return 0
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 ) :
for index in range ( 0 , max ( len ( lversion ) , len ( rversion ) ) ) :
lvalue = lversion [ index ] if len ( lversion ) > index else filler
rvalue = rversion [ index ] if len ( rversion ) > index else filler
if lvalue == rvalue :
if lvalue == rvalue :
continue
continue
if compare_operator( lvalue , rvalue ) :
if lvalue > rvalue :
return True
return 1
else :
else :
return False
return - 1
else :
return 0
if ( compare_operator != operator . lt and
compare_operator != operator . gt and
compare_operator != operator . ne ) :
return True
else :
return False
def __lt__ ( self , other ) :
def __lt__ ( self , other ) :
''' Перегрузка x < y. '''
''' Перегрузка x < y. '''
other_v alu e = self . _get_version_value ( other )
other_version = self . _get_version_value ( other )
if not other_valu e:
if other_version is None :
raise VersionError (
raise VersionError (
" Unable to compare Version object with the ' {0} ' "
" Unable to compare Version object with the ' {0} ' "
" value of ' {1} ' type " . format ( other , type ( other ) ) )
" value of ' {1} ' type " . format ( other , type ( other ) ) )
cmp_res = self . _compare_lists ( self . _value , other_version [ ' value ' ] )
if cmp_res != 0 :
return cmp_res < 0
if self . _literal != other_version [ ' literal ' ] :
return self . _literal < other_version [ ' literal ' ]
return self . _use_compare_operation ( operator . lt , other_value )
cmp_res = self . _compare_lists ( self . _suffix ,
other_version [ ' suffix ' ] ,
filler = ( 4 , 0 ) )
if cmp_res != 0 :
return cmp_res < 0
return self . _revision < other_version [ ' revision ' ]
def __le__ ( self , other ) :
def __le__ ( self , other ) :
''' Перегрузка x <= y. '''
''' Перегрузка x <= y. '''
other_value = self . _get_version_value ( other )
other_v ersion = self . _get_version_value ( other )
if not other_value :
if other_version is Non e:
raise VersionError (
raise VersionError (
" Unable to compare Version object with the ' {0} ' "
" Unable to compare Version object with the ' {0} ' "
" value of ' {1} ' type " . format ( other , type ( other ) ) )
" value of ' {1} ' type " . format ( other , type ( other ) ) )
cmp_res = self . _compare_lists ( self . _value , other_version [ ' value ' ] )
return self . _use_compare_operation ( operator . le , other_value )
if cmp_res != 0 :
return cmp_res < 0
if self . _literal != other_version [ ' literal ' ] :
return self . _literal < other_version [ ' literal ' ]
cmp_res = self . _compare_lists ( self . _suffix ,
other_version [ ' suffix ' ] ,
filler = ( 4 , 0 ) )
if cmp_res != 0 :
return cmp_res < 0
return self . _revision < = other_version [ ' revision ' ]
def __eq__ ( self , other ) :
def __eq__ ( self , other ) :
''' Перегрузка x == y. '''
''' Перегрузка x == y. '''
other_value = self . _get_version_value ( other )
other_v ersion = self . _get_version_value ( other )
if not other_value :
if other_version is Non e:
raise VersionError (
raise VersionError (
" Unable to compare Version object with the ' {0} ' "
" Unable to compare Version object with the ' {0} ' "
" value of ' {1} ' type " . format ( other , type ( other ) ) )
" value of ' {1} ' type " . format ( other , type ( other ) ) )
cmp_res = self . _compare_lists ( self . _value ,
return self . _use_compare_operation ( operator . eq , other_value )
other_version [ ' value ' ] )
if cmp_res != 0 :
return False
if self . _literal != other_version [ ' literal ' ] :
return False
cmp_res = self . _compare_lists ( self . _suffix ,
other_version [ ' suffix ' ] ,
filler = ( 4 , 0 ) )
if cmp_res != 0 :
return False
return self . _revision == other_version [ ' revision ' ]
def __ne__ ( self , other ) :
def __ne__ ( self , other ) :
''' Перегрузка x != y. '''
''' Перегрузка x != y. '''
other_value = self . _get_version_value ( other )
return not self . __eq__ ( 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 ) :
def __gt__ ( self , other ) :
''' Перегрузка x > y. '''
''' Перегрузка x > y. '''
other_value = self . _get_version_value ( other )
return not self . __le__ ( 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 ) :
def __ge__ ( self , other ) :
''' Перегрузка x >= y. '''
''' Перегрузка x >= y. '''
other_value = self . _get_version_value ( other )
return not self . __lt__ ( 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 ) :
def __hash__ ( self ) :
return hash ( self . _ version_ string)
return hash ( self . _string )
def __repr__ ( self ) :
def __repr__ ( self ) :
return ' <Version: {} > ' . format ( self . _ version_ string)
return ' <Version: {} > ' . format ( self . _string )
def __str__ ( self ) :
def __str__ ( self ) :
return self . _ version_ string
return self . _ string
def __bool__ ( self ) :
def __bool__ ( self ) :
if self . _v ersion_v alue == [ - 1 ] :
if self . _v alue == [ - 1 ] :
return False
return False
else :
else :
return True
return True
def __rshift__ ( self , other : tuple ) - > bool :
" Проверка нахождения значения переменной в указанном диапазоне. "
if ( not isinstance ( other , tuple ) or len ( other ) != 2
or not isinstance ( other [ 0 ] , str ) or not isinstance ( other [ 1 ] , str ) ) :
raise VersionError ( " Versions range must be tuple of two strings, "
f " not ' { type ( other ) } ' " )
lequal = other [ 0 ] . startswith ( ' = ' )
lversion = Version ( other [ 0 ] . strip ( ' = ' ) )
requal = other [ 0 ] . startswith ( ' = ' )
rversion = Version ( other [ 1 ] . strip ( ' = ' ) )
return ( ( ( lequal and self > = lversion )
or ( not lequal and self > lversion ) )
and ( ( requal and self < = rversion )
or ( not requal and self < rversion ) ) )
class ContentsParser ( metaclass = Singleton ) :
class ContentsParser ( metaclass = Singleton ) :
def __init__ ( self ) :
def __init__ ( self ) :
@ -328,15 +391,13 @@ class PackageAtomName:
def __eq__ ( self , other ) :
def __eq__ ( self , other ) :
if isinstance ( other , PackageAtomName ) :
if isinstance ( other , PackageAtomName ) :
return ( self . _package_directory ==
return self . _package_directory == other . _package_directory
other . _package_directory )
else :
else :
return False
return False
def __ne__ ( self , other ) :
def __ne__ ( self , other ) :
if isinstance ( other , PackageAtomName ) :
if isinstance ( other , PackageAtomName ) :
return ( self . _package_directory !=
return self . _package_directory != other . _package_directory
other . _package_directory )
else :
else :
return False
return False
@ -361,8 +422,14 @@ NonePackage = PackageAtomName({'pkg_path': None, 'version': None})
class PackageAtomParser :
class PackageAtomParser :
''' Класс для парсинга параметра package, е г о проверки, а также определения
''' Класс для парсинга параметра package, е г о проверки, а также определения
принадлежности файла пакету . '''
принадлежности файла пакету . '''
_value = r ' (?P<value> \ d+( \ . \ d+)*) '
_literal = r ' (?P<literal>[a-z])? '
_suffix = r ' (?P<suffix>(_(pre|p|beta|alpha|rc)( \ d+)?)+)? '
_revision = r ' (?P<revision>-r \ d+)? '
_version_pattern = _value + _literal + _suffix + _revision
package_name_pattern = \
package_name_pattern = \
r ' (?P<name> \ D[ \ w \ d]*( \ - \ D[ \ w \ d]*)*)(?P<version>- \ d[^ \ s, \ [:]*)? '
f r' (?P<name> \ D[ \ w \ d]*( \ - \ D[ \ w \ d]*)*)(?P<version>- { _version_pattern } )?'
atom_name_pattern = r ''' (?P<category>[^ \ s/]*)/
atom_name_pattern = r ''' (?P<category>[^ \ s/]*)/
{ 0 }
{ 0 }
@ -372,6 +439,7 @@ class PackageAtomParser:
atom_regex = re . compile ( atom_name_pattern , re . VERBOSE )
atom_regex = re . compile ( atom_name_pattern , re . VERBOSE )
package_name_regex = re . compile ( package_name_pattern )
package_name_regex = re . compile ( package_name_pattern )
version_regex = re . compile ( _version_pattern )
def __init__ ( self , pkg_path = ' /var/db/pkg ' ,
def __init__ ( self , pkg_path = ' /var/db/pkg ' ,
chroot_path = ' / ' ) :
chroot_path = ' / ' ) :
@ -443,7 +511,7 @@ class PackageAtomParser:
# Используем glob-паттерн для поиска.
# Используем glob-паттерн для поиска.
if self . _atom_dictionary [ ' version ' ] is not None :
if self . _atom_dictionary [ ' version ' ] is not None :
full_name = self . _atom_dictionary [ ' name ' ] + ' - ' + \
full_name = self . _atom_dictionary [ ' name ' ] + ' - ' + \
self . _atom_dictionary [ ' version ' ] . _ version_ string
self . _atom_dictionary [ ' version ' ] . _ string
else :
else :
full_name = self . _atom_dictionary [ ' name ' ]
full_name = self . _atom_dictionary [ ' name ' ]