2013-04-09 12:51:28 +02:00
|
|
|
|
|
|
|
from __future__ import print_function
|
|
|
|
|
2012-04-03 15:59:42 +02:00
|
|
|
import os.path
|
|
|
|
import re
|
|
|
|
import tarfile
|
2013-04-09 11:35:53 +02:00
|
|
|
from . import packagequery
|
2012-04-03 15:59:42 +02:00
|
|
|
import subprocess
|
|
|
|
|
|
|
|
class ArchError(packagequery.PackageError):
|
|
|
|
pass
|
|
|
|
|
2015-06-23 17:52:37 +02:00
|
|
|
class ArchQuery(packagequery.PackageQuery, packagequery.PackageQueryResult):
|
2012-04-03 15:59:42 +02:00
|
|
|
def __init__(self, fh):
|
|
|
|
self.__file = fh
|
|
|
|
self.__path = os.path.abspath(fh.name)
|
|
|
|
self.fields = {}
|
|
|
|
#self.magic = None
|
|
|
|
#self.pkgsuffix = 'pkg.tar.gz'
|
2018-12-13 14:47:48 +01:00
|
|
|
self.pkgsuffix = b'arch'
|
2012-04-03 15:59:42 +02:00
|
|
|
|
2014-04-03 17:41:41 +02:00
|
|
|
def read(self, all_tags=True, self_provides=True, *extra_tags):
|
|
|
|
# all_tags and *extra_tags are currently ignored
|
2012-04-03 15:59:42 +02:00
|
|
|
f = open(self.__path, 'rb')
|
|
|
|
#self.magic = f.read(5)
|
|
|
|
#if self.magic == '\375\067zXZ':
|
|
|
|
# self.pkgsuffix = 'pkg.tar.xz'
|
|
|
|
fn = open('/dev/null', 'wb')
|
2013-05-27 14:30:08 +02:00
|
|
|
pipe = subprocess.Popen(['tar', '-O', '-xf', self.__path, '.PKGINFO'], stdout=subprocess.PIPE, stderr=fn).stdout
|
2012-04-03 15:59:42 +02:00
|
|
|
for line in pipe.readlines():
|
2018-12-13 14:47:48 +01:00
|
|
|
line = line.rstrip().split(b' = ', 2)
|
2012-04-03 15:59:42 +02:00
|
|
|
if len(line) == 2:
|
2019-01-27 14:46:03 +01:00
|
|
|
field, value = line[0].decode('ascii'), line[1]
|
|
|
|
self.fields.setdefault(field, []).append(value)
|
2014-04-03 17:41:41 +02:00
|
|
|
if self_provides:
|
2018-12-13 14:47:48 +01:00
|
|
|
prv = b'%s = %s' % (self.name(), self.fields['pkgver'][0])
|
2014-04-03 17:41:41 +02:00
|
|
|
self.fields.setdefault('provides', []).append(prv)
|
2015-06-23 17:52:37 +02:00
|
|
|
return self
|
2012-04-03 15:59:42 +02:00
|
|
|
|
|
|
|
def vercmp(self, archq):
|
|
|
|
res = cmp(int(self.epoch()), int(archq.epoch()))
|
|
|
|
if res != 0:
|
|
|
|
return res
|
|
|
|
res = ArchQuery.rpmvercmp(self.version(), archq.version())
|
2019-01-27 15:00:36 +01:00
|
|
|
if res != 0:
|
2012-04-03 15:59:42 +02:00
|
|
|
return res
|
|
|
|
res = ArchQuery.rpmvercmp(self.release(), archq.release())
|
|
|
|
return res
|
|
|
|
|
|
|
|
def name(self):
|
|
|
|
return self.fields['pkgname'][0] if 'pkgname' in self.fields else None
|
|
|
|
|
|
|
|
def version(self):
|
|
|
|
pkgver = self.fields['pkgver'][0] if 'pkgver' in self.fields else None
|
|
|
|
if pkgver != None:
|
|
|
|
pkgver = re.sub(r'[0-9]+:', '', pkgver, 1)
|
|
|
|
pkgver = re.sub(r'-[^-]*$', '', pkgver)
|
|
|
|
return pkgver
|
|
|
|
|
|
|
|
def release(self):
|
|
|
|
pkgver = self.fields['pkgver'][0] if 'pkgver' in self.fields else None
|
|
|
|
if pkgver != None:
|
|
|
|
m = re.search(r'-([^-])*$', pkgver)
|
|
|
|
if m:
|
|
|
|
return m.group(1)
|
|
|
|
return None
|
|
|
|
|
|
|
|
def epoch(self):
|
2019-01-27 15:39:07 +01:00
|
|
|
pkgver = self.fields.get('pkgver', [b''])[0]
|
|
|
|
if pkgver:
|
2012-04-03 15:59:42 +02:00
|
|
|
m = re.match(r'([0-9])+:', pkgver)
|
|
|
|
if m:
|
|
|
|
return m.group(1)
|
2019-01-27 15:39:07 +01:00
|
|
|
return b'0'
|
2012-04-03 15:59:42 +02:00
|
|
|
|
|
|
|
def arch(self):
|
|
|
|
return self.fields['arch'][0] if 'arch' in self.fields else None
|
|
|
|
|
|
|
|
def description(self):
|
|
|
|
return self.fields['pkgdesc'][0] if 'pkgdesc' in self.fields else None
|
|
|
|
|
|
|
|
def path(self):
|
|
|
|
return self.__path
|
|
|
|
|
|
|
|
def provides(self):
|
|
|
|
return self.fields['provides'] if 'provides' in self.fields else []
|
|
|
|
|
|
|
|
def requires(self):
|
|
|
|
return self.fields['depend'] if 'depend' in self.fields else []
|
|
|
|
|
2014-12-05 18:36:44 +01:00
|
|
|
def conflicts(self):
|
|
|
|
return self.fields['conflict'] if 'conflict' in self.fields else []
|
|
|
|
|
|
|
|
def obsoletes(self):
|
|
|
|
return self.fields['replaces'] if 'replaces' in self.fields else []
|
|
|
|
|
2017-12-26 23:14:47 +01:00
|
|
|
def recommends(self):
|
|
|
|
# a .PKGINFO has no notion of "recommends"
|
|
|
|
return []
|
|
|
|
|
|
|
|
def suggests(self):
|
|
|
|
# libsolv treats an optdepend as a "suggests", hence we do the same
|
|
|
|
if 'optdepend' not in self.fields:
|
|
|
|
return []
|
|
|
|
return [re.sub(':.*', '', entry) for entry in self.fields['optdepend']]
|
|
|
|
|
|
|
|
def supplements(self):
|
|
|
|
# a .PKGINFO has no notion of "recommends"
|
|
|
|
return []
|
|
|
|
|
|
|
|
def enhances(self):
|
|
|
|
# a .PKGINFO has no notion of "enhances"
|
|
|
|
return []
|
|
|
|
|
2012-04-03 15:59:42 +02:00
|
|
|
def canonname(self):
|
|
|
|
pkgver = self.fields['pkgver'][0] if 'pkgver' in self.fields else None
|
2018-12-13 14:47:48 +01:00
|
|
|
canonname = self.name() + b'-' + pkgver + b'-' + self.arch() + b'.' + self.pkgsuffix
|
|
|
|
return canonname
|
2012-04-03 15:59:42 +02:00
|
|
|
|
2015-06-23 17:52:37 +02:00
|
|
|
def gettag(self, tag):
|
|
|
|
# implement me, if needed
|
|
|
|
return None
|
|
|
|
|
2012-04-03 15:59:42 +02:00
|
|
|
@staticmethod
|
|
|
|
def query(filename, all_tags = False, *extra_tags):
|
|
|
|
f = open(filename, 'rb')
|
|
|
|
archq = ArchQuery(f)
|
|
|
|
archq.read(all_tags, *extra_tags)
|
|
|
|
f.close()
|
|
|
|
return archq
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def rpmvercmp(ver1, ver2):
|
|
|
|
"""
|
|
|
|
implementation of RPM's version comparison algorithm
|
|
|
|
(as described in lib/rpmvercmp.c)
|
|
|
|
"""
|
|
|
|
if ver1 == ver2:
|
|
|
|
return 0
|
|
|
|
res = 0
|
|
|
|
while res == 0:
|
|
|
|
# remove all leading non alphanumeric chars
|
|
|
|
ver1 = re.sub('^[^a-zA-Z0-9]*', '', ver1)
|
|
|
|
ver2 = re.sub('^[^a-zA-Z0-9]*', '', ver2)
|
|
|
|
if not (len(ver1) and len(ver2)):
|
|
|
|
break
|
|
|
|
# check if we have a digits segment
|
|
|
|
mo1 = re.match('(\d+)', ver1)
|
|
|
|
mo2 = re.match('(\d+)', ver2)
|
|
|
|
numeric = True
|
|
|
|
if mo1 is None:
|
|
|
|
mo1 = re.match('([a-zA-Z]+)', ver1)
|
|
|
|
mo2 = re.match('([a-zA-Z]+)', ver2)
|
|
|
|
numeric = False
|
|
|
|
# check for different types: alpha and numeric
|
|
|
|
if mo2 is None:
|
|
|
|
if numeric:
|
|
|
|
return 1
|
|
|
|
return -1
|
|
|
|
seg1 = mo1.group(0)
|
|
|
|
ver1 = ver1[mo1.end(0):]
|
|
|
|
seg2 = mo2.group(1)
|
|
|
|
ver2 = ver2[mo2.end(1):]
|
|
|
|
if numeric:
|
|
|
|
# remove leading zeros
|
|
|
|
seg1 = re.sub('^0+', '', seg1)
|
|
|
|
seg2 = re.sub('^0+', '', seg2)
|
|
|
|
# longer digit segment wins - if both have the same length
|
|
|
|
# a simple ascii compare decides
|
|
|
|
res = len(seg1) - len(seg2) or cmp(seg1, seg2)
|
|
|
|
else:
|
|
|
|
res = cmp(seg1, seg2)
|
|
|
|
if res > 0:
|
|
|
|
return 1
|
|
|
|
elif res < 0:
|
|
|
|
return -1
|
|
|
|
return cmp(ver1, ver2)
|
|
|
|
|
|
|
|
@staticmethod
|
2014-05-13 13:28:19 +02:00
|
|
|
def filename(name, epoch, version, release, arch):
|
|
|
|
if epoch:
|
|
|
|
if release:
|
|
|
|
return '%s-%s:%s-%s-%s.arch' % (name, epoch, version, release, arch)
|
|
|
|
else:
|
|
|
|
return '%s-%s:%s-%s.arch' % (name, epoch, version, arch)
|
2012-04-03 15:59:42 +02:00
|
|
|
if release:
|
|
|
|
return '%s-%s-%s-%s.arch' % (name, version, release, arch)
|
|
|
|
else:
|
|
|
|
return '%s-%s-%s.arch' % (name, version, arch)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
import sys
|
|
|
|
try:
|
|
|
|
archq = ArchQuery.query(sys.argv[1])
|
2013-04-09 11:27:02 +02:00
|
|
|
except ArchError as e:
|
2013-04-09 12:51:28 +02:00
|
|
|
print(e.msg)
|
2012-04-03 15:59:42 +02:00
|
|
|
sys.exit(2)
|
2013-04-09 12:51:28 +02:00
|
|
|
print(archq.name(), archq.version(), archq.release(), archq.arch())
|
|
|
|
print(archq.canonname())
|
|
|
|
print(archq.description())
|
|
|
|
print('##########')
|
|
|
|
print('\n'.join(archq.provides()))
|
|
|
|
print('##########')
|
|
|
|
print('\n'.join(archq.requires()))
|