Skip to content

Commit

Permalink
Find files wil now replace system paths with rpm macros (fix #351)
Browse files Browse the repository at this point in the history
  • Loading branch information
onionka committed Feb 7, 2016
1 parent 263cc77 commit 9bf95dd
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 21 deletions.
94 changes: 90 additions & 4 deletions rpg/plugins/misc/find_file.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,98 @@
from rpg.plugin import Plugin
import re
import rpm
import os
import sys
import tempfile
import io
import locale


# This has been copied from:
# https://github.com/phracek/rebase-helper
def _dump():
"""
Captures output of %dump macro
:return: Raw %dump macro output as a list of lines
"""
# %dump macro prints results to stderr
# we cannot use sys.stderr because it can be modified by pytest
err = sys.__stderr__.fileno()
defenc = locale.getpreferredencoding()
defenc = 'utf-8' if defenc == 'ascii' else defenc
with tempfile.TemporaryFile(mode='w+b') as tmp:
with os.fdopen(os.dup(err), 'wb') as copied:
try:
sys.stderr.flush()
os.dup2(tmp.fileno(), err)
try:
rpm.expandMacro('%dump')
finally:
sys.stderr.flush()
os.dup2(copied.fileno(), err)
finally:
tmp.flush()
tmp.seek(0, io.SEEK_SET)
for macro in re.finditer(
"-14\: (\w+).*(?=\n-14)", tmp.read().decode(defenc)):
expanded = rpm.expandMacro("%" + macro.group(1))
if os.path.isdir(expanded) and expanded != '':
yield (expanded, "%{" + macro.group(1) + "}")

# priority list - here are all default directory paths
PRIO = [
"%{_mandir}",
"%{_defaultdocdir}",
"%{_defaultlicencedir}",
"%{_fileattrsdir}",
"%{fmoddir}",
"%{_includedir}",
"%{_sbindir}",
"%{_bindir}",
"%{_libdir}",
"%{_libexecdir}",
"%{_infodir}",
"%{_datadir}",
"%{_sharedstatedir}",
"%{_localstatedir}",
"%{_sysconfdir}",
]


class FindFilePlugin(Plugin):

# expand %dump, gets dir macros and sort them by len and by prio
# (priority is for duplicates like _kde4_dir and _libdir where defaultly
# _libdir should be picked)
MACROS = sorted(_dump(), reverse=True,
key=lambda x: len(x[0]) * 2 + (1 if x[1] in PRIO else 0))

def installed(self, project_dir, spec, sack):
""" Finds files that will be installed and
appends them to files macro """
for item in list(project_dir.glob('**/*')):
if item.is_file():
spec.files.add(("/" + str(item.relative_to(project_dir)),
None, None))

def relative(_file, _relative):
return "/" + str(_file.relative_to(_relative))

def append(_file, _spec):
_spec.files.add((_file, None, None))

def find_n_replace(_file, f, *r):
match = re.search("^" + f[0], _file)
if match:
return f[1] + _file[len(match.group(0)):]
else:
return find_n_replace(_file, *r) if r else _file

def ite(_spec, _proj_dir, f, *r):
if f.is_file():
append(find_n_replace(relative(f, _proj_dir), *self.MACROS),
_spec)
if r:
ite(_spec, _proj_dir, *r)

def iterate(_spec, _proj_dir, _glob):
if _glob:
ite(_spec, _proj_dir, *_glob)

iterate(spec, project_dir, list(project_dir.glob('**/*')))
47 changes: 30 additions & 17 deletions tests/unit/test_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from rpg.plugins.misc.files_to_pkgs import FilesToPkgsPlugin
from rpg.plugins.lang.c import CPlugin
from rpg.spec import Spec
from unittest import mock
from rpg.plugins.project_builder.cmake import CMakePlugin
from rpg.plugins.project_builder.setuptools import SetuptoolsPlugin
from rpg.plugins.project_builder.autotools import AutotoolsPlugin
Expand All @@ -29,15 +28,6 @@ def __init__(self, package):
files = []


class MockedLogging:

called = 0

@classmethod
def log(cls, *args, **kwargs):
cls.called += 1


class MockedDNFQuery:

def filter(self, **kwd):
Expand All @@ -50,6 +40,33 @@ def available(self):
return self


class MockedPath:

MACROED_PATHS = {
'usr/bin/p': '%{_bindir}/p',
'usr/include/i.h': '%{_includedir}/i.h',
'usr/include/befa/file.hpp': '%{_includedir}/befa/file.hpp'
# This cannot be tested on 32-bit systems:
# "usr/lib64/libl.so": "%{_libdir}/libl.so",
# same with python sitelib and sitearch
}

def __init__(self, path):
self.path = path

def __str__(self):
return self.path

def glob(self, *args, **kwargs):
return [MockedPath(f) for f in self.MACROED_PATHS.keys()]

def is_file(self, *args, **kwargs):
return self.path != '~'

def relative_to(self, *args, **kwargs):
return self.path


class FindPatchPluginTest(PluginTestCase):

def setUp(self):
Expand All @@ -74,14 +91,11 @@ def test_find_patch(self):

def test_find_files(self):
plugin = FindFilePlugin()
plugin.installed(self.test_project_dir / "setuptools",
plugin.installed(MockedPath(self.test_project_dir / "installed"),
self.spec, self.sack)
files = sorted([
("/setup.py", None, None),
("/testscript.py", None, None)
])
self.assertEqual(sorted(list(self.spec.files)),
files)
sorted([(MockedPath.MACROED_PATHS[f], None, None)
for f in MockedPath.MACROED_PATHS]))

def test_find_translation_file(self):
plugin = FindTranslationPlugin()
Expand All @@ -106,7 +120,6 @@ def test_python_find_requires(self):
r"/usr/lib.*/python.*/lib-dynload/math\.cpython.*\.so", req)
for req in self.spec.required_files))

@mock.patch("logging.log", new=MockedLogging.log)
def test_files_to_pkgs(self):
ftpp = FilesToPkgsPlugin()
self.spec.Requires = set()
Expand Down

0 comments on commit 9bf95dd

Please sign in to comment.