def __init__(self, path, target="rpm", map_name=None, dist=""): if target == "rpm": self.rpmfilenamepat = rpm.expandMacro("%_build_name_fmt") self.srpmfilenamepat = rpm.expandMacro("%_build_name_fmt") self.map_arch = identity # '%dist' in the host (where we build the source package) # might not match '%dist' in the chroot (where we build # the binary package). We must override it on the host, # otherwise the names of packages in the dependencies won't # match the files actually produced by mock. self.dist = dist else: self.rpmfilenamepat = "%{NAME}_%{VERSION}-%{RELEASE}_%{ARCH}.deb" self.srpmfilenamepat = "%{NAME}_%{VERSION}-%{RELEASE}.dsc" self.map_arch = map_arch_deb self.dist = "" rpm.addMacro("dist", self.dist) if map_name: self.map_package_name = map_name else: self.map_package_name = identity_list self.path = os.path.join(SPECDIR, os.path.basename(path)) with open(path) as spec: self.spectext = spec.readlines() self.spec = rpm.ts().parseSpec(path)
def _guess_chroot(chroot_config): """ Guess which chroot is equivalent to this machine """ # FIXME Copr should generate non-specific arch repo dist = chroot_config if dist is None or (dist[0] is False) or (dist[1] is False): dist = linux_distribution() if "Fedora" in dist: # x86_64 because repo-file is same for all arch # ($basearch is used) if "Rawhide" in dist: chroot = ("fedora-rawhide-x86_64") else: chroot = ("fedora-{}-x86_64".format(dist[1])) elif "Mageia" in dist: # Get distribution architecture (Mageia does not use $basearch) distarch = rpm.expandMacro("%{distro_arch}") # Set the chroot if "Cauldron" in dist: chroot = ("mageia-cauldron-{}".format(distarch)) else: chroot = ("mageia-{0}-{1}".format(dist[1], distarch)) elif "openSUSE" in dist: # Get distribution architecture (openSUSE does not use $basearch) distarch = rpm.expandMacro("%{_target_cpu}") # Set the chroot if "Tumbleweed" in dist: chroot = ("opensuse-tumbleweed-{}".format(distarch)) else: chroot = ("opensuse-leap-{0}-{1}".format(dist[1], distarch)) else: chroot = ("epel-%s-x86_64" % dist[1].split(".", 1)[0]) return chroot
def srpmNameFromSpec( spec ): h = spec.sourceHeader if buildType() == "rpm": rpm.addMacro( 'NAME', h['name'] ) else: rpm.addMacro( 'NAME', mappkgname.map_package(h['name'])[0] ) rpm.addMacro( 'VERSION', h['version'] ) rpm.addMacro( 'RELEASE', h['release'] ) rpm.addMacro( 'ARCH', 'src' ) # There doesn't seem to be a macro for the name of the source # rpm, but the name appears to be the same as the rpm name format. # Unfortunately expanding that macro gives us a leading 'src' that we # don't want, so we strip that off if buildType() == "rpm": srpmname = os.path.basename( rpm.expandMacro( rpmfilenamepat ) ) else: srpmname = os.path.basename( rpm.expandMacro( "%{NAME}_%{VERSION}-%{RELEASE}.dsc" ) ) rpm.delMacro( 'NAME' ) rpm.delMacro( 'VERSION' ) rpm.delMacro( 'RELEASE' ) rpm.delMacro( 'ARCH' ) # HACK: rewrite %dist if it appears in the filename return srpmname.replace( chroot_dist, host_dist )
def srpm_name_from_spec(spec): hdr = spec.sourceHeader rpm.addMacro('NAME', map_package_name(hdr['name'])[0]) rpm.addMacro('VERSION', hdr['version']) rpm.addMacro('RELEASE', hdr['release']) rpm.addMacro('ARCH', 'src') # There doesn't seem to be a macro for the name of the source # rpm, but the name appears to be the same as the rpm name format. # Unfortunately expanding that macro gives us a leading 'src' that we # don't want, so we strip that off if build_type() == "rpm": srpmname = os.path.basename(rpm.expandMacro(RPMFILENAMEPAT)) else: srpmname = os.path.basename( rpm.expandMacro("%{NAME}_%{VERSION}-%{RELEASE}.dsc")) rpm.delMacro('NAME') rpm.delMacro('VERSION') rpm.delMacro('RELEASE') rpm.delMacro('ARCH') # HACK: rewrite %dist if it appears in the filename return srpmname.replace(CHROOT_DIST, HOST_DIST)
def files_from_pkg(basename, pkg, specpath): # should be able to build this from the files sections - can't find how # to get at them from the spec object res = "" files = rpmextra.files_from_spec(basename, specpath) for filename in files.get(pkg.header['name'], []): # Debian packages must not contain compiled Python files. # Instead, the python2 helper arranges to compile these # files when they are installed. if os.path.splitext(filename)[1] in [".pyc", ".pyo"]: continue rpm.addMacro("_libdir", "usr/lib") rpm.addMacro("_bindir", "usr/bin") # deb just wants relative paths src = rpm.expandMacro(filename).lstrip("/") rpm.delMacro("_bindir") rpm.delMacro("_libdir") rpm.addMacro("_libdir", "/usr/lib") rpm.addMacro("_bindir", "/usr/bin") dst = rpm.expandMacro(filename) # destination paths should be directories, not files. # if the file is foo and the path is /usr/bin/foo, the # package will end up install /usr/bin/foo/foo if not dst.endswith("/"): dst = os.path.dirname(dst) rpm.delMacro("_bindir") rpm.delMacro("_libdir") res += "%s %s\n" % (src, dst) return res
def _get_nvr(self): tset = rpm.ts() tset.parseSpec(self.specfile) name = rpm.expandMacro("%{name}") version = rpm.expandMacro("%{version}") release = rpm.expandMacro("%{release}") return (name, version, release)
def __init__(self, path, dist="", check_package_name=True, topdir=None): # _topdir defaults to $HOME/rpmbuild if topdir: rpm.addMacro('_topdir', topdir) rpm.addMacro('_specdir', os.path.dirname(path)) self.path = os.path.join(specdir(), os.path.basename(path)) with open(path) as spec: self.spectext = spec.readlines() # '%dist' in the host (where we build the source package) # might not match '%dist' in the chroot (where we build # the binary package). We must override it on the host, # otherwise the names of packages in the dependencies won't # match the files actually produced by mock. rpm.addMacro('dist', dist) try: self.spec = rpm.ts().parseSpec(path) except ValueError as exn: exn.args = (exn.args[0].rstrip() + ' ' + path, ) raise if check_package_name: file_basename = os.path.basename(path).split(".")[0] if file_basename != self.name(): raise SpecNameMismatch( "spec file name '%s' does not match package name '%s'" % (path, self.name())) self.rpmfilenamepat = rpm.expandMacro('%_build_name_fmt') self.srpmfilenamepat = rpm.expandMacro('%_build_name_fmt')
def run_on_applicable(self): gem_libdir_re = re.compile(rpm.expandMacro('%{gem_libdir}'), re.I) gem_extdir_re = re.compile(rpm.expandMacro('%{gem_extdir_mri}'), re.I) doc_gem_docdir_re = \ re.compile(rpm.expandMacro(r'%doc\s+%{gem_docdir}'), re.I) exclude_gem_cache_re = \ re.compile(rpm.expandMacro(r'%exclude\s+%{gem_cache}'), re.I) gem_spec_re = re.compile(rpm.expandMacro('%{gem_spec}'), re.I) re_dict = {gem_libdir_re: False, doc_gem_docdir_re: False, exclude_gem_cache_re: False, gem_spec_re: False} if _has_extension(self): re_dict[gem_extdir_re] = False # mark the present macro regexps with True for pkg in self.spec.packages: for line in self.spec.get_files(pkg): for macro_re in re_dict: if macro_re.match(line): re_dict[macro_re] = True err_message = [] # construct the error message for all non-present macros for key, value in re_dict.iteritems(): if value is False: err_message.append(key.pattern.replace('\\s+', ' ')) if len(err_message) == 0: self.set_passed(self.PASS) else: self.set_passed(self.PENDING, 'The specfile doesn\'t use these macros: %s' % ', '.join(err_message))
def expand(s, default=None, suppress_errors=False): try: if not suppress_errors: return rpm.expandMacro(s) with ConsoleHelper.Capturer(stderr=True): return rpm.expandMacro(s) except rpm.error: return default
def rpm_name_from_header(hdr): """ Return the name of the binary package file which will be built from hdr """ with rpm_macros(self.macros, nevra(hdr)): rpmname = hdr.sprintf(rpm.expandMacro("%{_build_name_fmt}")) return rpm.expandMacro(os.path.join('%_rpmdir', rpmname))
def _get_instructions(cls, comments, old_version, new_version): """Extract instructions from comments, update version if necessary""" instructions = [] for comment in comments: comment = rpm.expandMacro(rpm.expandMacro(comment)) comment = re.sub(r'^#\s*', '', comment) comment = comment.replace(old_version, new_version) instructions.append(comment) return instructions
def run_on_applicable(self): ok = False vendorarchdir = rpm.expandMacro('%{vendorarchdir}') vendorlibdir = rpm.expandMacro('%{vendorlibdir}') for pkg in self.spec.packages: for line in self.spec.get_files(pkg): if _has_extension(self) and vendorarchdir in line: ok = True if not _has_extension(self) and vendorlibdir in line: ok = True self.set_passed(self.PASS if ok else self.FAIL)
def dump(): """Gets list of all defined macros. Returns: list: All defined macros. """ macro_re = re.compile( r''' ^\s* (?P<level>-?\d+) (?P<used>=|:) [ ] (?P<name>\w+) (?P<options>\(.+?\))? [\t] (?P<value>.*) $ ''', re.VERBOSE) with ConsoleHelper.Capturer(stderr=True) as capturer: rpm.expandMacro('%dump') macros = [] def add_macro(properties): macro = dict(properties) macro['used'] = macro['used'] == '=' macro['level'] = int(macro['level']) if parse_version(rpm.__version__) < parse_version('4.13.90'): # in RPM < 4.13.90 level of some macros is decreased by 1 if macro['level'] == -1: # this could be macro with level -1 or level 0, we can not be sure # so just duplicate the macro for both levels macros.append(macro) macro = dict(macro) macro['level'] = 0 macros.append(macro) elif macro['level'] in (-14, -16): macro['level'] += 1 macros.append(macro) else: macros.append(macro) else: macros.append(macro) for line in capturer.stderr.split('\n'): match = macro_re.match(line) if match: add_macro(match.groupdict()) return macros
def __init__(self, path, check_package_name=True, defines=None): self.macros = OrderedDict(defines) if defines else OrderedDict() # _topdir defaults to $HOME/rpmbuild # If present, it needs to be applied once at the beginning if '_topdir' in self.macros: rpm.addMacro('_topdir', self.macros['_topdir']) # '%dist' in the host (where we build the source package) # might not match '%dist' in the chroot (where we build # the binary package). We must override it on the host, # otherwise the names of packages in the dependencies won't # match the files actually produced by mock. if 'dist' not in self.macros: self.macros['dist'] = "" hardcoded_macros = OrderedDict([('_specdir', os.path.dirname(path))]) with rpm_macros(append_macros(self.macros, hardcoded_macros)): self.path = os.path.join(specdir(), os.path.basename(path)) with open(path) as spec: self.spectext = spec.readlines() with tempfile.TemporaryFile() as nullfh: try: # collect all output to stderr then filter out # errors about missing sources errcpy = os.dup(2) try: os.dup2(nullfh.fileno(), 2) self.spec = rpm.ts().parseSpec(path) finally: os.dup2(errcpy, 2) os.close(errcpy) except ValueError as exn: nullfh.seek(0, os.SEEK_SET) for line in nullfh: line = line.strip() if not line.endswith(': No such file or directory'): print >> sys.stderr, line exn.args = (exn.args[0].rstrip() + ' ' + path, ) raise if check_package_name: file_basename = os.path.basename(path).split(".")[0] if file_basename != self.name(): raise SpecNameMismatch( "spec file name '%s' does not match package name '%s'" % (path, self.name())) self.rpmfilenamepat = rpm.expandMacro('%_build_name_fmt') self.srpmfilenamepat = rpm.expandMacro('%_build_name_fmt')
def installed(self, project_dir, spec, sack): python_version = "" for py_file in list(project_dir.glob('**/*.py')): if rpm.expandMacro("%{python_sitearch}") in str(py_file) or\ rpm.expandMacro("%{python_sitelib}") in str(py_file): python_version = "python2" elif rpm.expandMacro("%{python3_sitearch}") in str(py_file) or\ rpm.expandMacro("%{python3_sitelib}") in str(py_file): python_version = "python3" Command([python_version + ' ' + sw + ' -c \'import compileall; compileall.compile_file("' + str(py_file) + '")\'' for sw in ["-O", ""]]).execute() spec.files.update([("/" + str(_f.relative_to(project_dir)), None, None) for _f in project_dir.glob('**/*.py*')])
def main(argv=None): """ Entry point """ args = parse_args_or_exit(argv) tmpdir = tempfile.mkdtemp(prefix="px-mock-") config = clone_mock_config(args.configdir, tmpdir) try: if args.init: mock(args, config, "--init") else: config_in_path = os.path.join(args.configdir, args.root + ".cfg") config_out_path = os.path.join(config, args.root + ".cfg") insert_loopback_repo( config_in_path, config_out_path, tmpdir, args.loopback_config_extra) with rpm_macros(dict(args.define)): rpmdir = os.path.abspath(rpm.expandMacro("%_rpmdir")) createrepo(rpmdir, tmpdir, args.quiet) mock(args, config, "--rebuild", *args.srpms) except subprocess.CalledProcessError as cpe: sys.exit(cpe.returncode) finally: if args.keeptmp: print("Working directory retained at %s" % tmpdir) else: shutil.rmtree(tmpdir)
def build_rpm(self): package_name = "".join( random.choice(string.ascii_lowercase) for _ in range(12)) # Fill template spec_data = self.DEFAULT_SPEC_DATA spec_data["name"] = package_name spec_data["files"] = f"/{package_name}.bin" # Create spec rendered = self.template.render(**spec_data) tmp_spec_path = os.path.join(self.tmp_dir, "SPECS", f"{package_name}.spec") with open(tmp_spec_path, "w") as tmp_spec: tmp_spec.write(rendered) # Create build dirs build_root = rpm.expandMacro("%{buildroot}") if not os.path.exists(build_root): os.makedirs(build_root) # Writing binary file tmp_bin_path = os.path.join(build_root, f"{package_name}.bin") with open(tmp_bin_path, "wb") as tmp_bin: tmp_bin.write(os.urandom(1024 * 1024)) # size in bytes # Generating rpm build_amount = rpm.RPMBUILD_PACKAGEBINARY | rpm.RPMBUILD_RMBUILD | rpm.RPMBUILD_CLEAN sp = rpm.spec(specfile=tmp_spec_path) sp._doBuild(ts=self.ts, buildAmount=build_amount)
def dump(): """ Returns list of all defined macros :return: list of macros """ macro_re = re.compile( r''' ^\s* (?P<level>-?\d+) (?P<used>=|:) [ ] (?P<name>\w+) (?P<options>\(.+?\))? [\t] (?P<value>.*) $ ''', re.VERBOSE) _, stderr = ConsoleHelper.capture_output( lambda: rpm.expandMacro('%dump'), capture_stderr=True) macros = [] for line in stderr.split('\n'): match = macro_re.match(line) if match: macro = match.groupdict() macro['level'] = int(macro['level']) macro['used'] = macro['used'] == '=' macros.append(macro) return macros
def sanitizeString(s, translate=True): if len(s) == 0: return s if not translate: i18ndomains = [] elif hasattr(rpm, "expandMacro"): i18ndomains = rpm.expandMacro("%_i18ndomains").split(":") else: i18ndomains = ["redhat-dist"] # iterate over i18ndomains add to textdomain(), then translate for d in i18ndomains: if d not in _added_gettext_domains: try: # This horrible hack works around the python split() in gettext # problem. Example file is with a problem is: # /usr/share/locale/de/LC_MESSAGES/redhat-dist.mo textdomain(d) except AttributeError: pass _added_gettext_domains[d] = True s = _(s) s = s.replace("\n\n", "\x00") s = s.replace("\n", " ") s = s.replace("\x00", "\n\n") s = s.replace("&", "&") s = s.replace("<", "<") s = s.replace(">", ">") s = utf8(s) return s
def run(self): bad_pkgs = [] archs = self.checks.spec.expand_tag('BuildArchs') if len(self.spec.packages) == 1: self.set_passed(self.NA) return if len(archs) == 1 and archs[0].lower() == 'noarch': isa = '' else: isa = Mock.get_macro('%_isa', self.spec, self.flags) regex = self.REGEX.replace('%{?_isa}', isa) regex = rpm.expandMacro(regex) regex = re.sub('[.](fc|el)[0-9]+', '', regex) for pkg in self.spec.packages: if pkg == self.spec.base_package: continue for pkg_end in ['debuginfo', '-javadoc', '-doc']: if pkg.endswith(pkg_end): continue reqs = ''.join(self.rpms.get(pkg).format_requires) if regex not in reqs: bad_pkgs.append(pkg) if bad_pkgs: self.set_passed(self.PENDING, self.HDR + ' , '.join(bad_pkgs)) else: self.set_passed(self.PASS)
def rpm_expand_py(macro): import rpm if '%' not in macro: return macro expanded = rpm.expandMacro(macro) rd_debug('Expanded rpm macro in \'%s\' to \'%s\'' % (macro, expanded)) return expanded
def _parse_files(self, pkg_name): ''' Parse and return the %files section for pkg_name. Return [] for empty file list, None for no matching %files. ''' if not pkg_name: pkg_name = self.name lines = None for line in [l.strip() for l in self.lines]: if lines is None: if line.startswith('%files'): name = self._parse_files_pkg_name(line) if pkg_name.endswith(name): lines = [] continue line = rpm.expandMacro(line) if line.startswith('%{gem_'): # Nasty F17/EPEL fix where %gem_* are not defined. lines.append(line) elif line.startswith('%'): token = re.split(r'\s|\(', line)[0] if token not in [ '%ghost', '%doc', '%docdir', '%license', '%verify', '%attr', '%config', '%dir', '%defattr', '%exclude' ]: break else: lines.append(line) elif line: lines.append(line) return lines
def _parse_files(self, pkg_name): ''' Parse and return the %files section for pkg_name. Return [] for empty file list, None for no matching %files. ''' if not pkg_name: pkg_name = self.name lines = None for line in [l.strip() for l in self.lines]: if lines is None: if line.startswith('%files'): name = self._parse_files_pkg_name(line) if pkg_name.endswith(name): lines = [] continue line = rpm.expandMacro(line) if line.startswith('%{gem_'): # Nasty F17/EPEL fix where %gem_* are not defined. lines.append(line) elif line.startswith('%'): token = re.split(r'\s|\(', line)[0] if token not in ['%ghost', '%doc', '%docdir', '%license', '%verify', '%attr', '%config', '%dir', '%defattr', '%exclude']: break else: lines.append(line) elif line: lines.append(line) return lines
def installed(self, project_dir, spec, sack): python_version = "" for py_file in list(project_dir.glob('**/*.py')): if rpm.expandMacro("%{python_sitearch}") in str(py_file) or\ rpm.expandMacro("%{python_sitelib}") in str(py_file): python_version = "python2" elif rpm.expandMacro("%{python3_sitearch}") in str(py_file) or\ rpm.expandMacro("%{python3_sitelib}") in str(py_file): python_version = "python3" Command([ python_version + ' ' + sw + ' -c \'import compileall; compileall.compile_file("' + str(py_file) + '")\'' for sw in ["-O", ""] ]).execute() spec.files.update([("/" + str(_f.relative_to(project_dir)), None, None) for _f in project_dir.glob('**/*.py*')])
def sanitizeString(s, translate = True): if len(s) == 0: return s if not translate: i18ndomains = [] elif hasattr(rpm, "expandMacro"): i18ndomains = rpm.expandMacro("%_i18ndomains").split(":") else: i18ndomains = ["redhat-dist"] # iterate over i18ndomains to find the translation for d in i18ndomains: r = gettext.dgettext(d, s) if r != s: s = r break s = s.replace("\n\n", "\x00") s = s.replace("\n", " ") s = s.replace("\x00", "\n\n") s = s.replace("&", "&") s = s.replace("<", "<") s = s.replace(">", ">") if type(s) != unicode: try: s = unicode(s, "utf-8") except UnicodeDecodeError, e: sys.stderr.write("Unable to convert %s to a unicode object: %s\n" % (s, e)) return ""
def __init__(self, path, target="rpm", map_name=None, dist="", check_package_name=True, topdir=None): if map_name: self.map_package_name = map_name else: self.map_package_name = identity_list # _topdir defaults to $HOME/rpmbuild if topdir: rpm.addMacro('_topdir', topdir) rpm.addMacro('_specdir', os.path.dirname(path)) self.path = os.path.join(specdir(), os.path.basename(path)) with open(path) as spec: self.spectext = spec.readlines() # '%dist' in the host (where we build the source package) # might not match '%dist' in the chroot (where we build # the binary package). We must override it on the host, # otherwise the names of packages in the dependencies won't # match the files actually produced by mock. self.dist = "" if target == "rpm": self.dist = dist rpm.addMacro('dist', self.dist) self.spec = rpm.ts().parseSpec(path) if check_package_name: file_basename = os.path.basename(path).split(".")[0] if file_basename != self.name(): raise SpecNameMismatch( "spec file name '%s' does not match package name '%s'" % (path, self.name())) if target == "rpm": self.rpmfilenamepat = rpm.expandMacro('%_build_name_fmt') self.srpmfilenamepat = rpm.expandMacro('%_build_name_fmt') self.map_arch = identity else: separator = '.' if debianmisc.is_native(self.spec) else '-' basename = "%{NAME}_%{VERSION}" + separator self.rpmfilenamepat = basename + "%{RELEASE}_%{ARCH}.deb" self.srpmfilenamepat = basename + "%{RELEASE}.dsc" self.map_arch = map_arch_deb
def execute_from(self, work_dir): """executes command in work_dir (instance of pathlib.Path), can raise CalledProcessError""" cd_workdir = ["cd %s" % path_to_str(work_dir.resolve())] command_lines = self._assign_rpm_variables() + cd_workdir + \ [rpm.expandMacro(x) for x in self._command_lines] return cmd_output(command_lines)
def getCanonARMArch(arch): # the %{_target_arch} macro in rpm will let us know the abi we are using target = rpm.expandMacro('%{_target_cpu}') if target.startswith('armv6h'): return target if target.startswith('armv7h'): return target return arch
def extract_version_from_archive_name(archive_path, source_string=''): """ Method extracts the version from archive name based on the source string from SPEC file. It extracts also an extra version such as 'b1', 'rc1', ... :param archive_path: archive name or path with archive name from which to extract the version :param source_string: Source string from SPEC file used to construct version extraction regex :return: tuple of strings with (extracted version, extra version) or (None, None) if extraction failed """ # https://regexper.com/#(%5B.0-9%5D%2B%5B-_%5D%3F%5Cw*) version_regex_str = r'([.0-9]+[-_]?\w*)' fallback_regex_str = r'^\w+[-_]?v?{0}({1})'.format( version_regex_str, '|'.join(Archive.get_supported_archives())) # match = re.search(regex, tarball_name) name = os.path.basename(archive_path) url_base = os.path.basename(source_string).strip() logger.debug("Extracting version from '%s' using '%s'", name, url_base) # expect that the version macro can be followed by another macros regex_str = re.sub(r'%{version}(%{.+})?', version_regex_str, url_base, flags=re.IGNORECASE) # if no substitution was made, use the fallback regex if regex_str == url_base: logger.debug( 'Using fallback regex to extract version from archive name.') regex_str = fallback_regex_str else: regex_str = rpm.expandMacro(regex_str) logger.debug("Extracting version using regex '%s'", regex_str) regex = re.compile(regex_str) match = regex.search(name) if match: version = match.group(1) logger.debug("Extracted version '%s'", version) return SpecFile.split_version_string(version) else: logger.debug('Failed to extract version from archive name!') # TODO: look at this if it could be rewritten in a better way! # try fallback regex if not used this time if regex_str != fallback_regex_str: logger.debug( "Trying to extracting version using fallback regex '%s'", fallback_regex_str) regex = re.compile(fallback_regex_str) match = regex.search(name) if match: version = match.group(1) logger.debug("Extracted version '%s'", version) return SpecFile.split_version_string(version) else: logger.debug( 'Failed to extract version from archive name using fallback regex!' ) return SpecFile.split_version_string('')
def test_spec_file(self): ''' Test the SpecFile class''' def fix_usr_link(path): ''' Convert absolute paths to /usr/path. ''' if not '/' in path: return path lead = path.split('/')[1] if lead in ['bin', 'sbin', 'lib', 'lib64']: return '/usr' + path return path self.init_test('test_misc', argv=['-n', 'python-test', '--no-build']) spec = SpecFile(os.path.join(os.getcwd(), 'python-test.spec')) self.assertEqual(spec.name, 'python-test') self.assertEqual(spec.version, '1.0') dist = Mock.get_macro('%dist', None, {}) self.assertEqual(spec.release, '1' + dist) self.assertEqual(spec.expand_tag('Release'), '1' + dist) self.assertEqual(spec.expand_tag('License'), 'GPLv2+') self.assertEqual(spec.expand_tag('Group'), 'Development/Languages') # Test rpm value not there self.assertEqual(spec.expand_tag('PreReq'), None) # Test get sections expected = ['rm -rf $RPM_BUILD_ROOT'] self.assertEqual(spec.get_section('%clean'), expected) expected = '%{__python} setup.py build' expected = ['LANG=C', 'export LANG', 'unset DISPLAY', '/usr/bin/python setup.py build'] build = spec.get_section('%build') build = map(fix_usr_link, build) self.assertIn(''.join(build), ''.join(expected)) install = spec.get_section('%install') install = map(fix_usr_link, install) expected = ['LANG=C', 'export LANG', 'unset DISPLAY', 'rm -rf $RPM_BUILD_ROOT', '/usr/bin/python setup.py install -O1 --skip-build' ' --root $RPM_BUILD_ROOT'] self.assertIn(''.join(install), ''.join(expected)) # Test get_sources (return the Source/Patch lines with macros resolved) expected = {'Source0': 'http://timlau.fedorapeople.org/' 'files/test/review-test/python-test-1.0.tar.gz'} self.assertEqual(spec.sources_by_tag, expected) expected = ['%defattr(-,root,root,-)', '%doc COPYING', rpm.expandMacro('%{python_sitelib}') + '/*'] self.assertEqual(spec.get_files(), expected) # Test find regex = re.compile(r'^Release\s*:\s*(.*)') res = spec.find_re(regex) if res: self.assertEqual(res.split(':')[1].strip(), '1%{?dist}') else: self.assertTrue(False)
def _process_fonts_pkg(self): ''' If found, expand %_font_pkg macro. ''' expanded = [] for l in self.lines: if '%_font_pkg' not in l: expanded.append(l) else: expanded.extend(rpm.expandMacro(l).split('\n')) self.lines = expanded
def expand_macro(self, macro): """Return the value of macro, expanded in the package's context""" hdr = self.spec.sourceHeader hardcoded_macros = OrderedDict([ ('name', hdr['name']), ]) with rpm_macros(append_macros(self.macros, hardcoded_macros)): return rpm.expandMacro(macro)
def get_nvs(spec): try: nvs = [] ts = rpm.TransactionSet() rpm_spec = ts.parseSpec(spec) name = rpm.expandMacro("%{name}") version = rpm.expandMacro("%{version}") nvs.append(name) nvs.append(version) for (filename, num, flags) in rpm_spec.sources: if num == 0 and flags == 1: # path # http://mirrors.n-ix.net/mariadb/mariadb-10.3.9/source/ source_link = '/'.join(filename.split("/")[:-1]) nvs.append(source_link) return nvs except: return None
def run(self): rc = self.NA build_sec = self.spec.get_section('build') if build_sec: smp_mflags = rpm.expandMacro('%{?_smp_mflags}') for line in build_sec: if line.startswith('make'): ok = smp_mflags in line rc = self.PASS if ok else self.FAIL self.set_passed(rc)
def __init__(self, path, target="rpm", map_name=None, dist=""): if map_name: self.map_package_name = map_name else: self.map_package_name = identity_list self.path = os.path.join(SPECDIR, os.path.basename(path)) with open(path) as spec: self.spectext = spec.readlines() # '%dist' in the host (where we build the source package) # might not match '%dist' in the chroot (where we build # the binary package). We must override it on the host, # otherwise the names of packages in the dependencies won't # match the files actually produced by mock. self.dist = "" if target == "rpm": self.dist = dist rpm.addMacro('dist', self.dist) self.spec = rpm.ts().parseSpec(path) if os.path.basename(path).split(".")[0] != self.name(): raise SpecNameMismatch( "spec file name '%s' does not match package name '%s'" % (path, self.name())) if target == "rpm": self.rpmfilenamepat = rpm.expandMacro('%_build_name_fmt') self.srpmfilenamepat = rpm.expandMacro('%_build_name_fmt') self.map_arch = identity else: sep = '.' if debianmisc.is_native(self.spec) else '-' if debianmisc.is_native(self.spec): self.rpmfilenamepat = "%{NAME}_%{VERSION}.%{RELEASE}_%{ARCH}.deb" self.srpmfilenamepat = "%{NAME}_%{VERSION}.%{RELEASE}.dsc" else: self.rpmfilenamepat = "%{NAME}_%{VERSION}-%{RELEASE}_%{ARCH}.deb" self.srpmfilenamepat = "%{NAME}_%{VERSION}-%{RELEASE}.dsc" self.map_arch = map_arch_deb
def run_on_applicable(self): """ Run the check """ b_dir = False b_test = False b_rm = False b_install = False section = self.spec.get_section('%install') if not section: self.set_passed(self.FAIL) return for line in section: if 'mkdir -p' in line and \ ('/R/library' in line or 'rlibdir' in line): b_dir = True if rpm.expandMacro("test -d %{packname}/src && " "(cd %{packname}/src; rm -f *.o *.so)") in line: b_test = True if 'rm' in line and 'R.css' in line: b_rm = True if 'R CMD INSTALL' in line \ and '-l ' in line \ and rpm.expandMacro('%{packname}') in line \ and ('/R/library' in line or 'rlibdir' in line): b_install = True if b_dir and b_test and b_rm and b_install: self.set_passed(self.PASS) else: cmt = '' if not b_dir: cmt += "Package doesn't have the standard " \ "directory creation.\n" if not b_test: cmt += "Package doesn't have the standard " \ "removal of *.o and *.so.\n" if not b_rm: cmt += "Package doesn't have the standard " \ "removal of the R.css file\n" if not b_install: cmt += "Package doesn't have the standard " \ "R CMD INSTALL function\n" self.set_passed(self.FAIL, cmt)
def rpmNameFromHeader( h ): rpm.addMacro( 'NAME', h['name'] ) rpm.addMacro( 'VERSION', h['version'] ) rpm.addMacro( 'RELEASE', h['release'] ) rpm.addMacro( 'ARCH', h['arch'] ) rpmname = rpm.expandMacro( rpmfilenamepat ) rpm.delMacro( 'NAME' ) rpm.delMacro( 'VERSION' ) rpm.delMacro( 'RELEASE' ) rpm.delMacro( 'ARCH' ) return rpmname
def source_package_path(self): """ Return the path of the source package which building this spec will produce """ # There doesn't seem to be a macro for the name of the source rpm # but we can construct one using the 'NVR' RPM tag which returns the # package's name-version-release string. Naming is not critically # important as these source RPMs are only used internally - mock # will write a new source RPM along with the binary RPMS. srpmname = self.spec.sourceHeader['nvr'] + ".src.rpm" return rpm.expandMacro(os.path.join('%_srcrpmdir', srpmname))
def get_default_save_path(): """Return default save path for the packages""" macro = '%{_topdir}' if rpm: save_path = rpm.expandMacro(macro) else: save_path = rpm_eval(macro) if not save_path: logger.warning("rpm tools are missing, using default save path " "~/rpmbuild/.") save_path = os.path.expanduser('~/rpmbuild') return save_path
def fix_rpmdb(self, expected_rpmdb_dir=None, db_load='db_load', rpm='rpm'): logger.info("fixing RPM database for guest") current_rpmdb_dir = rpm_mod.expandMacro('%{_dbpath}') if expected_rpmdb_dir is None: expected_rpmdb_dir = sh.run( [ 'python', '-c', 'import rpm; print rpm.expandMacro("%{_dbpath}")' ], chroot=self.chroot, pipe=sh.READ, env=self.yum_conf.env, ).strip() # input directory rpmdb_dir = os.path.join(self.chroot, current_rpmdb_dir.lstrip('/')) logger.info('converting "Packages" file') in_pkg_db = os.path.join(rpmdb_dir, 'Packages') tmp_pkg_db = os.path.join(expected_rpmdb_dir, 'Packages.tmp') out_pkg_db = os.path.join(expected_rpmdb_dir, 'Packages') out_command = sh.run( [db_load, tmp_pkg_db], chroot=self.chroot, pipe=sh.WRITE, env=self.yum_conf.env, ) bdb.db_dump(in_pkg_db, out_command) out_command.close() os.rename(os.path.join(self.chroot, tmp_pkg_db.lstrip('/')), os.path.join(self.chroot, out_pkg_db.lstrip('/'))) logger.info('removing all the files except "Packages"') for f in os.listdir(rpmdb_dir): if f in ('.', '..', 'Packages'): continue os.unlink(os.path.join(rpmdb_dir, f)) logger.info("running `rpm --rebuilddb'") sh.run( [rpm, '--rebuilddb'], chroot=self.chroot, env=self.yum_conf.env, ) if current_rpmdb_dir != expected_rpmdb_dir: # Red Hat under Debian; delete old directory (~/.rpmdb possibly) logger.info("removing old RPM DB directory: $TARGET%s", current_rpmdb_dir) shutil.rmtree( os.path.join(self.chroot, current_rpmdb_dir.lstrip('/'))) self.rpmdb_fixed = True
class SystemdInstallCheck(AbstractCheck): systemd_service_directory = rpm.expandMacro('%{_unitdir}') checked_units = ['service', 'socket', 'target', 'path'] checked_units_regexp = re.compile('^' + systemd_service_directory + r'.+[^@]\.(' + '|'.join(checked_units) + ')$') def check(self, pkg): # Check only binary package if pkg.is_source: return pre = pkg[rpm.RPMTAG_PREIN] or pkg.scriptprog(rpm.RPMTAG_PREINPROG) post = pkg[rpm.RPMTAG_POSTIN] or pkg.scriptprog(rpm.RPMTAG_POSTINPROG) preun = pkg[rpm.RPMTAG_PREUN] or pkg.scriptprog(rpm.RPMTAG_PREUNPROG) postun = pkg[rpm.RPMTAG_POSTUN] or pkg.scriptprog(rpm.RPMTAG_POSTUNPROG) for fname in pkg.files: if self.checked_units_regexp.search(fname): processed = {'pre': False, 'post': False, 'preun': False, 'postun': False} escaped_basename = re.escape(Path(fname).name) PRE_POST_PATTERN = re.compile(r'for service in .*' + escaped_basename) PREUN_PATTERN = re.compile(r'systemctl --no-reload disable .*' + escaped_basename) POSTUN_PATTERN = re.compile(r'(systemctl try-restart .*|# Restart of .*)' + escaped_basename) for line in pre.split('\n'): if PRE_POST_PATTERN.search(line): processed['pre'] = True break for line in post.split('\n'): if PRE_POST_PATTERN.search(line): processed['post'] = True break for line in preun.split('\n'): if PREUN_PATTERN.search(line): processed['preun'] = True break for line in postun.split('\n'): if POSTUN_PATTERN.search(line): processed['postun'] = True break basename = Path(fname).name if not processed['pre']: self.output.add_info('W', pkg, 'systemd-service-without-service_add_pre', basename) if not processed['post']: self.output.add_info('W', pkg, 'systemd-service-without-service_add_post', basename) if not processed['preun']: self.output.add_info('W', pkg, 'systemd-service-without-service_del_preun', basename) if not processed['postun']: self.output.add_info('W', pkg, 'systemd-service-without-service_del_postun', basename)
def rpm_name_from_header(hdr): """Return the name of the binary package file which will be built from hdr""" rpm.addMacro('NAME', self.map_package_name(hdr['name'])[0]) rpm.addMacro('VERSION', hdr['version']) rpm.addMacro('RELEASE', hdr['release']) rpm.addMacro('ARCH', self.map_arch(hdr['arch'])) rpmname = rpm.expandMacro(self.rpmfilenamepat) rpm.delMacro('NAME') rpm.delMacro('VERSION') rpm.delMacro('RELEASE') rpm.delMacro('ARCH') return os.path.join(RPMDIR, rpmname)
def installPackages(pkgs, cfg): ts = rpm.ts() ts.setFlags(rpm.RPMTRANS_FLAG_JUSTDB) with open(cfg.template) as fp: spectemplate = fp.read() template = Template(spectemplate) paths = Paths(rpm.expandMacro('%_specdir'), rpm.expandMacro('%_rpmdir')) for pkg in pkgs: match = ts.dbMatch(rpm.RPMTAG_NAME, pkg.name) if len(match) == 0: rpmfile = build(pkg, template, paths) ts.addInstall(rpmfile, rpmfile, 'i') if ts.check(): raise RuntimeError("This should not happen") ts.order() def runCallback(reason, amount, total, rpmfile, client_data): if reason == rpm.RPMCALLBACK_INST_OPEN_FILE: client_data[rpmfile] = os.open(rpmfile, os.O_RDONLY) return client_data[rpmfile] elif reason == rpm.RPMCALLBACK_INST_CLOSE_FILE: os.close(client_data[rpmfile]) result = ts.run(runCallback, {}) if result: print("ERRORS") print(result) else: print("Packages") for te in ts: info = (te.N(), te.V(), te.R()) print("name: %s version: %s release: %s" % info) ts.check() ts.verifyDB()
def rpm_name_from_header(hdr): """Return the name of the binary package file which will be built from hdr""" rpm.addMacro("NAME", self.map_package_name(hdr["name"])[0]) rpm.addMacro("VERSION", hdr["version"]) rpm.addMacro("RELEASE", hdr["release"]) rpm.addMacro("ARCH", self.map_arch(hdr["arch"])) rpmname = rpm.expandMacro(self.rpmfilenamepat) rpm.delMacro("NAME") rpm.delMacro("VERSION") rpm.delMacro("RELEASE") rpm.delMacro("ARCH") return os.path.join(RPMDIR, rpmname)
def rules_dh_install_from_spec(spec, tree, specpath): rule = ".PHONY: override_dh_install\n" rule += "override_dh_install:\n" rule += "\tdh_install\n" pkgname = mappkgname.map_package_name(spec.sourceHeader) files = rpmextra.files_from_spec(pkgname, specpath) if pkgname + "-%exclude" in files: for pat in files[pkgname + "-%exclude"]: path = "\trm -f debian/%s/%s\n" % (pkgname, rpm.expandMacro(pat)) rule += os.path.normpath(path) rule += "\n" tree.append('debian/rules', rule)