def dependencies(path: Path) -> Set[str]: """ load dependencies from package sources :param path: path to package sources directory :return: list of package dependencies including makedepends array, but excluding packages from this base """ # additional function to remove versions from dependencies def trim_version(name: str) -> str: for symbol in ("<", "=", ">"): name = name.split(symbol)[0] return name srcinfo, errors = parse_srcinfo((path / ".SRCINFO").read_text()) if errors: raise InvalidPackageInfo(errors) makedepends = srcinfo.get("makedepends", []) # sum over each package depends: List[str] = srcinfo.get("depends", []) for package in srcinfo["packages"].values(): depends.extend(package.get("depends", [])) # we are not interested in dependencies inside pkgbase packages = set(srcinfo["packages"].keys()) full_list = set(depends + makedepends) - packages return {trim_version(package_name) for package_name in full_list}
def testRejectsPkgbaseAfterPkgname(self): from srcinfo.parse import parse_srcinfo srcinfo = '''pkgname = luna pkgbase = pony''' (parsed, errors) = parse_srcinfo(srcinfo) self.assertPackageNamesEqual(parsed, ['luna']) self.assertEqual(len(errors), 1) self.assertIn('pkgbase declared after pkgname', errors[0]['error'])
def parse_pkgbuild(pkgbuild_text): with tempfile.NamedTemporaryFile() as pkgbuild_file: pkgbuild_file.write(pkgbuild_text.encode()) pkgbuild_file.flush() srcinfo, _ = srcinfo_parse.parse_srcinfo( OutputOf('./introspect', pkgbuild_file.name)) pkgnames = srcinfo_utils.get_package_names(srcinfo) pkgs = map(lambda n: srcinfo_utils.get_merged_package(n, srcinfo), pkgnames) return dict(zip(pkgnames, pkgs))
def parse_pkgbuild(pkgbuild_text): with tempfile.NamedTemporaryFile() as pkgbuild_file: pkgbuild_file.write(pkgbuild_text.encode()) pkgbuild_file.flush() srcinfo, _ = srcinfo_parse.parse_srcinfo( OutputOf('./introspect', pkgbuild_file.name)) pkgnames = srcinfo_utils.get_package_names(srcinfo) pkgs = map(lambda n: srcinfo_utils.get_merged_package(n, srcinfo), pkgnames) return dict(zip(pkgnames, pkgs))
def from_build(cls: Type[Package], path: Path, aur_url: str) -> Package: """ construct package properties from sources directory :param path: path to package sources directory :param aur_url: AUR root url :return: package properties """ srcinfo, errors = parse_srcinfo((path / ".SRCINFO").read_text()) if errors: raise InvalidPackageInfo(errors) packages = {key: PackageDescription() for key in srcinfo["packages"]} version = cls.full_version(srcinfo.get("epoch"), srcinfo["pkgver"], srcinfo["pkgrel"]) return cls(srcinfo["pkgbase"], version, aur_url, packages)
def testEmptyAttrInPackageOverridesGlobal(self): from srcinfo.parse import parse_srcinfo from srcinfo.utils import get_variable srcinfo = '''pkgbase = pony depends = global pkgname = applejack pkgname = pinkiepie depends = ''' (parsed, errors) = parse_srcinfo(srcinfo) self.assertEqual(errors, []) self.assertCountEqual(get_variable('depends', 'pinkiepie', parsed), []) self.assertCountEqual(get_variable('depends', 'applejack', parsed), ['global'])
def testEmptyAttrInPackageOverridesGlobal(self): from srcinfo.parse import parse_srcinfo from srcinfo.utils import get_variable srcinfo = '''pkgbase = pony depends = global pkgname = applejack pkgname = pinkiepie depends = ''' (parsed, errors) = parse_srcinfo(srcinfo) self.assertEqual(errors, []) self.assertCountEqual(get_variable('depends', 'pinkiepie', parsed), []) self.assertCountEqual(get_variable('depends', 'applejack', parsed), ['global'])
def srcinfo(self): """ Get a srcinfo dictionary corresponding to makepkg --printsrcinfo output. :return: The srcinfo dictionary :raises CalledProcessError: Raised if the makepkg command fails :raises ParseSrcinfoError: Raised if parsing the srcinfo fails """ if self._srcinfo: return self._srcinfo self.update() file = Path(self.builddir, '.SRCINFO') mtime = os.path.getmtime if file.exists() and not mtime(self.pkgbuildpath) > mtime(file): with open(file) as f: info = f.read() else: cmd = ['makepkg', '--printsrcinfo'] if self.makepkg_conf: cmd += ['--config', self.makepkg_conf] log.info('%s: Generating .SRCINFO... [%s]', self.name, self.builddir) r = run(cmd, cwd=self.builddir, capture_output=True, text=True, check=True) info = r.stdout with open(file, 'w') as f: f.write(info) srcinfo, errors = parse_srcinfo(info) if errors: err = { 'message': 'Failed to parse PKGBUILD srcinfo', 'errors': errors } raise ParseSrcinfoError(err) self._srcinfo = srcinfo return self._srcinfo
def main(): output_json = len(sys.argv) > 1 and sys.argv[1] == "--json" srcinfo = sys.stdin.read() (info, errors) = parse_srcinfo(srcinfo) if output_json: if errors: sys.exit(1) else: import json print(json.dumps(info)) else: import pprint pprint.PrettyPrinter().pprint(info) if errors: print('==> The following errors occured while parsing:', file=sys.stderr) for error in errors: print(error, file=sys.stderr)
def testSimpleParse(self): from srcinfo.parse import parse_srcinfo srcinfo = '''pkgbase = ponies pkgdesc = Some description pkgver = 1.0.0 pkgrel = 1 url = https://example.com arch = i686 arch = x86_64 license = ISC source = git+https://example.com/package.git md5sums = SKIP pkgname = ponies''' (parsed, errors) = parse_srcinfo(srcinfo) self.assertTrue(parsed) self.assertEqual(errors, []) self.assertPackageNamesEqual(parsed, ['ponies'])
def test_simple_parse(): from srcinfo.parse import parse_srcinfo srcinfo = '''pkgbase = ponies pkgdesc = Some description pkgver = 1.0.0 pkgrel = 1 url = https://example.com arch = i686 arch = x86_64 license = ISC source = git+https://example.com/package.git md5sums = SKIP pkgname = ponies''' (parsed, errors) = parse_srcinfo(srcinfo) assert parsed assert errors == [] assert package_names_equal(parsed, ['ponies'])
def test_simple_parse(): from srcinfo.parse import parse_srcinfo srcinfo = '''pkgbase = ponies pkgdesc = Some description pkgver = 1.0.0 pkgrel = 1 url = https://example.com arch = i686 arch = x86_64 license = ISC source = git+https://example.com/package.git md5sums = SKIP pkgname = ponies''' (parsed, errors) = parse_srcinfo(srcinfo) assert parsed assert errors == [] assert package_names_equal(parsed, ['ponies'])
def testSimpleParse(self): from srcinfo.parse import parse_srcinfo srcinfo = '''pkgbase = ponies pkgdesc = Some description pkgver = 1.0.0 pkgrel = 1 url = https://example.com arch = i686 arch = x86_64 license = ISC source = git+https://example.com/package.git md5sums = SKIP pkgname = ponies''' (parsed, errors) = parse_srcinfo(srcinfo) self.assertTrue(parsed) self.assertEqual(errors, []) self.assertPackageNamesEqual(parsed, ['ponies'])
def actual_version(self, paths: RepositoryPaths) -> str: """ additional method to handle VCS package versions :param paths: repository paths instance :return: package version if package is not VCS and current version according to VCS otherwise """ if not self.is_vcs: return self.version from ahriman.core.build_tools.task import Task clone_dir = paths.cache / self.base logger = logging.getLogger("build_details") Task.fetch(clone_dir, self.git_url) try: # update pkgver first Package._check_output("makepkg", "--nodeps", "--nobuild", exception=None, cwd=clone_dir, logger=logger) # generate new .SRCINFO and put it to parser srcinfo_source = Package._check_output("makepkg", "--printsrcinfo", exception=None, cwd=clone_dir, logger=logger) srcinfo, errors = parse_srcinfo(srcinfo_source) if errors: raise InvalidPackageInfo(errors) return self.full_version(srcinfo.get("epoch"), srcinfo["pkgver"], srcinfo["pkgrel"]) except Exception: logger.exception( "cannot determine version of VCS package, make sure that you have VCS tools installed" ) return self.version
def testRejectsMultiplePkgbase(self): from srcinfo.parse import parse_srcinfo srcinfo = '''pkgbase = pony pkgdesc = Some description pkgver = 1.0.0 pkgrel = 1 url = https://example.com arch = i686 arch = x86_64 license = ISC source = git+https://example.com/package.git md5sums = SKIP pkgname = luna pkgbase = ponies''' (parsed, errors) = parse_srcinfo(srcinfo) self.assertPackageNamesEqual(parsed, ['luna']) self.assertEqual(len(errors), 1) self.assertIn('pkgbase declared more than once', errors[0]['error'])
def testRejectsMultiplePkgbase(self): from srcinfo.parse import parse_srcinfo srcinfo = '''pkgbase = pony pkgdesc = Some description pkgver = 1.0.0 pkgrel = 1 url = https://example.com arch = i686 arch = x86_64 license = ISC source = git+https://example.com/package.git md5sums = SKIP pkgname = luna pkgbase = ponies''' (parsed, errors) = parse_srcinfo(srcinfo) self.assertPackageNamesEqual(parsed, ['luna']) self.assertEqual(len(errors), 1) self.assertIn('pkgbase declared more than once', errors[0]['error'])
def test_split_package_names(): from srcinfo.parse import parse_srcinfo srcinfo = '''pkgbase = pony pkgdesc = Some description pkgver = 1.0.0 pkgrel = 1 url = https://example.com arch = i686 arch = x86_64 license = ISC source = git+https://example.com/package.git md5sums = SKIP pkgname = applejack pkgname = rainbowdash pkgname = pinkiepie''' (parsed, errors) = parse_srcinfo(srcinfo) assert errors == [] assert package_names_equal(parsed, ['applejack', 'rainbowdash', 'pinkiepie'])
def testSplitPackageNames(self): from srcinfo.parse import parse_srcinfo srcinfo = '''pkgbase = pony pkgdesc = Some description pkgver = 1.0.0 pkgrel = 1 url = https://example.com arch = i686 arch = x86_64 license = ISC source = git+https://example.com/package.git md5sums = SKIP pkgname = applejack pkgname = rainbowdash pkgname = pinkiepie''' (parsed, errors) = parse_srcinfo(srcinfo) self.assertEqual(errors, []) self.assertPackageNamesEqual(parsed, ['applejack', 'rainbowdash', 'pinkiepie'])
def test_coverage(): from srcinfo.utils import get_variable from srcinfo.parse import parse_srcinfo srcinfo = '''pkgbase = gcc pkgdesc = The GNU Compiler Collection pkgver = 4.9.1 pkgrel = 2 url = http://gcc.gnu.org arch = i686 arch = x86_64 license = GPL license = LGPL license = FDL license = custom checkdepends = dejagnu checkdepends = inetutils makedepends = binutils>=2.24 makedepends = libmpc makedepends = cloog makedepends = gcc-ada makedepends = doxygen options = !emptydirs source = ftp://gcc.gnu.org/pub/gcc/snapshots/4.9-20140903/gcc-4.9-20140903.tar.bz2 source = gcc-4.8-filename-output.patch source = gcc-4.9-isl-0.13-hack.patch md5sums = 24dfd67139fda4746d2deff18182611d md5sums = 40cb437805e2f7a006aa0d0c3098ab0f md5sums = f26ae06b9cbc8abe86f5ee4dc5737da8 pkgname = gcc pkgdesc = The GNU Compiler Collection - C and C++ frontends install = gcc.install groups = base-devel depends = gcc-libs=4.9.1-2 depends = binutils>=2.24 depends = libmpc depends = cloog options = staticlibs pkgname = gcc-libs pkgdesc = Runtime libraries shipped by GCC install = gcc-libs.install groups = base depends = glibc>=2.20 options = !emptydirs options = !strip pkgname = gcc-fortran pkgdesc = Fortran front-end for GCC install = gcc-fortran.install depends = gcc=4.9.1-2 options = staticlibs options = !emptydirs pkgname = gcc-objc pkgdesc = Objective-C front-end for GCC depends = gcc=4.9.1-2 pkgname = gcc-ada pkgdesc = Ada front-end for GCC (GNAT) install = gcc-ada.install depends = gcc=4.9.1-2 options = staticlibs options = !emptydirs pkgname = gcc-go pkgdesc = Go front-end for GCC install = gcc-go.install depends = gcc=4.9.1-2 options = staticlibs options = !emptydirs''' expected_packages = ['gcc', 'gcc-libs', 'gcc-fortran', 'gcc-objc', 'gcc-ada', 'gcc-go'] (parsed, errors) = parse_srcinfo(srcinfo) assert errors == [] assert package_names_equal(parsed, expected_packages) for pkgname in expected_packages: assert get_variable('pkgver', pkgname, parsed) == '4.9.1' assert get_variable('pkgrel', pkgname, parsed) == '2' assert get_variable('arch', pkgname, parsed) == ['i686', 'x86_64'] assert get_variable('license', pkgname, parsed) == ['GPL', 'LGPL', 'FDL', 'custom'] assert get_variable('url', pkgname, parsed) == 'http://gcc.gnu.org' assert get_variable('makedepends', pkgname, parsed) == ['binutils>=2.24','libmpc', 'cloog', 'gcc-ada', 'doxygen'] assert get_variable('checkdepends', pkgname, parsed) == ['dejagnu', 'inetutils'] assert get_variable('source', pkgname, parsed) == ['ftp://gcc.gnu.org/pub/gcc/snapshots/4.9-20140903/gcc-4.9-20140903.tar.bz2', 'gcc-4.8-filename-output.patch', 'gcc-4.9-isl-0.13-hack.patch'] assert get_variable('md5sums', pkgname, parsed) == ['24dfd67139fda4746d2deff18182611d', '40cb437805e2f7a006aa0d0c3098ab0f', 'f26ae06b9cbc8abe86f5ee4dc5737da8'] assert get_variable('pkgdesc', 'gcc-libs', parsed) == 'Runtime libraries shipped by GCC' assert get_variable('groups', 'gcc-libs', parsed) == ['base'] assert get_variable('depends', 'gcc-libs', parsed) == ['glibc>=2.20'] assert get_variable('options', 'gcc-libs', parsed) == ['!emptydirs', '!strip'] assert get_variable('install', 'gcc-libs', parsed) == 'gcc-libs.install' assert get_variable('pkgdesc', 'gcc', parsed) == 'The GNU Compiler Collection - C and C++ frontends' assert get_variable('depends', 'gcc', parsed) == ['gcc-libs=4.9.1-2', 'binutils>=2.24', 'libmpc', 'cloog'] assert get_variable('groups', 'gcc', parsed) == ['base-devel'] assert get_variable('options', 'gcc', parsed) == ['staticlibs'] assert get_variable('install', 'gcc', parsed) == 'gcc.install' assert get_variable('pkgdesc', 'gcc-fortran', parsed) == 'Fortran front-end for GCC' assert get_variable('depends', 'gcc-fortran', parsed) == ['gcc=4.9.1-2'] assert get_variable('options', 'gcc-fortran', parsed) == ['staticlibs', '!emptydirs'] assert get_variable('install', 'gcc-fortran', parsed) == 'gcc-fortran.install' assert not get_variable('groups', 'gcc-fortran', parsed) assert get_variable('pkgdesc', 'gcc-objc', parsed) == 'Objective-C front-end for GCC' assert get_variable('depends', 'gcc-objc', parsed) == ['gcc=4.9.1-2'] assert get_variable('options', 'gcc-objc', parsed) == ['!emptydirs'] assert not get_variable('install', 'gcc-objc', parsed) assert not get_variable('groups', 'gcc-objc', parsed) assert get_variable('pkgdesc', 'gcc-ada', parsed) == 'Ada front-end for GCC (GNAT)' assert get_variable('depends', 'gcc-ada', parsed) == ['gcc=4.9.1-2'] assert get_variable('options', 'gcc-ada', parsed) == ['staticlibs', '!emptydirs'] assert get_variable('install', 'gcc-ada', parsed) == 'gcc-ada.install' assert not get_variable('groups', 'gcc-ada', parsed) assert get_variable('pkgdesc', 'gcc-go', parsed) == 'Go front-end for GCC' assert get_variable('depends', 'gcc-go', parsed) == ['gcc=4.9.1-2'] assert get_variable('options', 'gcc-go', parsed) == ['staticlibs', '!emptydirs'] assert get_variable('install', 'gcc-go', parsed) == 'gcc-go.install' assert not get_variable('groups', 'gcc-go', parsed)
def testCoverage(self): from srcinfo.parse import parse_srcinfo from srcinfo.utils import get_variable srcinfo = '''pkgbase = gcc pkgdesc = The GNU Compiler Collection pkgver = 4.9.1 pkgrel = 2 url = http://gcc.gnu.org arch = i686 arch = x86_64 license = GPL license = LGPL license = FDL license = custom checkdepends = dejagnu checkdepends = inetutils makedepends = binutils>=2.24 makedepends = libmpc makedepends = cloog makedepends = gcc-ada makedepends = doxygen options = !emptydirs source = ftp://gcc.gnu.org/pub/gcc/snapshots/4.9-20140903/gcc-4.9-20140903.tar.bz2 source = gcc-4.8-filename-output.patch source = gcc-4.9-isl-0.13-hack.patch md5sums = 24dfd67139fda4746d2deff18182611d md5sums = 40cb437805e2f7a006aa0d0c3098ab0f md5sums = f26ae06b9cbc8abe86f5ee4dc5737da8 pkgname = gcc pkgdesc = The GNU Compiler Collection - C and C++ frontends install = gcc.install groups = base-devel depends = gcc-libs=4.9.1-2 depends = binutils>=2.24 depends = libmpc depends = cloog options = staticlibs pkgname = gcc-libs pkgdesc = Runtime libraries shipped by GCC install = gcc-libs.install groups = base depends = glibc>=2.20 options = !emptydirs options = !strip pkgname = gcc-fortran pkgdesc = Fortran front-end for GCC install = gcc-fortran.install depends = gcc=4.9.1-2 options = staticlibs options = !emptydirs pkgname = gcc-objc pkgdesc = Objective-C front-end for GCC depends = gcc=4.9.1-2 pkgname = gcc-ada pkgdesc = Ada front-end for GCC (GNAT) install = gcc-ada.install depends = gcc=4.9.1-2 options = staticlibs options = !emptydirs pkgname = gcc-go pkgdesc = Go front-end for GCC install = gcc-go.install depends = gcc=4.9.1-2 options = staticlibs options = !emptydirs''' expected_packages = ['gcc', 'gcc-libs', 'gcc-fortran', 'gcc-objc', 'gcc-ada', 'gcc-go'] (parsed, errors) = parse_srcinfo(srcinfo) self.assertEqual(errors, []) self.assertPackageNamesEqual(parsed, expected_packages) for pkgname in expected_packages: self.assertEqual(get_variable('pkgver', pkgname, parsed), '4.9.1') self.assertEqual(get_variable('pkgrel', pkgname, parsed), '2') self.assertEqual(get_variable('arch', pkgname, parsed), ['i686', 'x86_64']) self.assertEqual(get_variable('license', pkgname, parsed), ['GPL', 'LGPL', 'FDL', 'custom']) self.assertEqual(get_variable('url', pkgname, parsed), 'http://gcc.gnu.org') self.assertEqual(get_variable('makedepends', pkgname, parsed), ['binutils>=2.24','libmpc', 'cloog', 'gcc-ada', 'doxygen']) self.assertEqual(get_variable('checkdepends', pkgname, parsed), ['dejagnu', 'inetutils']) self.assertEqual(get_variable('source', pkgname, parsed), [ 'ftp://gcc.gnu.org/pub/gcc/snapshots/4.9-20140903/gcc-4.9-20140903.tar.bz2', 'gcc-4.8-filename-output.patch', 'gcc-4.9-isl-0.13-hack.patch']) self.assertEqual(get_variable('md5sums', pkgname, parsed), [ '24dfd67139fda4746d2deff18182611d', '40cb437805e2f7a006aa0d0c3098ab0f', 'f26ae06b9cbc8abe86f5ee4dc5737da8']) self.assertEqual(get_variable('pkgdesc', 'gcc-libs', parsed), 'Runtime libraries shipped by GCC') self.assertEqual(get_variable('groups', 'gcc-libs', parsed), ['base']) self.assertEqual(get_variable('depends', 'gcc-libs', parsed), ['glibc>=2.20']) self.assertEqual(get_variable('options', 'gcc-libs', parsed), ['!emptydirs', '!strip']) self.assertEqual(get_variable('install', 'gcc-libs', parsed), 'gcc-libs.install') self.assertEqual(get_variable('pkgdesc', 'gcc', parsed), 'The GNU Compiler Collection - C and C++ frontends') self.assertEqual(get_variable('depends', 'gcc', parsed), ['gcc-libs=4.9.1-2', 'binutils>=2.24', 'libmpc', 'cloog']) self.assertEqual(get_variable('groups', 'gcc', parsed), ['base-devel']) self.assertEqual(get_variable('options', 'gcc', parsed), ['staticlibs']) self.assertEqual(get_variable('install', 'gcc', parsed), 'gcc.install') self.assertEqual(get_variable('pkgdesc', 'gcc-fortran', parsed), 'Fortran front-end for GCC') self.assertEqual(get_variable('depends', 'gcc-fortran', parsed), ['gcc=4.9.1-2']) self.assertEqual(get_variable('options', 'gcc-fortran', parsed), ['staticlibs', '!emptydirs']) self.assertEqual(get_variable('install', 'gcc-fortran', parsed), 'gcc-fortran.install') self.assertFalse(get_variable('groups', 'gcc-fortran', parsed)) self.assertEqual(get_variable('pkgdesc', 'gcc-objc', parsed), 'Objective-C front-end for GCC') self.assertEqual(get_variable('depends', 'gcc-objc', parsed), ['gcc=4.9.1-2']) self.assertEqual(get_variable('options', 'gcc-objc', parsed), ['!emptydirs']) self.assertFalse(get_variable('install', 'gcc-objc', parsed)) self.assertFalse(get_variable('groups', 'gcc-objc', parsed)) self.assertEqual(get_variable('pkgdesc', 'gcc-ada', parsed), 'Ada front-end for GCC (GNAT)') self.assertEqual(get_variable('depends', 'gcc-ada', parsed), ['gcc=4.9.1-2']) self.assertEqual(get_variable('options', 'gcc-ada', parsed), ['staticlibs', '!emptydirs']) self.assertEqual(get_variable('install', 'gcc-ada', parsed), 'gcc-ada.install') self.assertFalse(get_variable('groups', 'gcc-ada', parsed)) self.assertEqual(get_variable('pkgdesc', 'gcc-go', parsed), 'Go front-end for GCC') self.assertEqual(get_variable('depends', 'gcc-go', parsed), ['gcc=4.9.1-2']) self.assertEqual(get_variable('options', 'gcc-go', parsed), ['staticlibs', '!emptydirs']) self.assertEqual(get_variable('install', 'gcc-go', parsed), 'gcc-go.install') self.assertFalse(get_variable('groups', 'gcc-go', parsed))