Skip to content

Commit cc573ef

Browse files
committed
Find files wil now replace system paths with rpm macros (fix #351)
1 parent 263cc77 commit cc573ef

File tree

2 files changed

+121
-22
lines changed

2 files changed

+121
-22
lines changed

rpg/plugins/misc/find_file.py

Lines changed: 91 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,98 @@
11
from rpg.plugin import Plugin
2+
import re
3+
import rpm
4+
import os
5+
import sys
6+
import tempfile
7+
import io
8+
import locale
9+
10+
11+
# This has been copied from:
12+
# https://github.com/phracek/rebase-helper
13+
def _dump():
14+
"""
15+
Captures output of %dump macro
16+
:return: Raw %dump macro output as a list of lines
17+
"""
18+
# %dump macro prints results to stderr
19+
# we cannot use sys.stderr because it can be modified by pytest
20+
err = sys.__stderr__.fileno()
21+
defenc = locale.getpreferredencoding()
22+
defenc = 'utf-8' if defenc == 'ascii' else defenc
23+
with tempfile.TemporaryFile(mode='w+b') as tmp:
24+
with os.fdopen(os.dup(err), 'wb') as copied:
25+
try:
26+
sys.stderr.flush()
27+
os.dup2(tmp.fileno(), err)
28+
try:
29+
rpm.expandMacro('%dump')
30+
finally:
31+
sys.stderr.flush()
32+
os.dup2(copied.fileno(), err)
33+
finally:
34+
tmp.flush()
35+
tmp.seek(0, io.SEEK_SET)
36+
for macro in re.finditer(
37+
"-14\: (\w+).*(?=\n-14)", tmp.read().decode(defenc)):
38+
expanded = rpm.expandMacro("%" + macro.group(1))
39+
if os.path.isdir(expanded) and expanded != '':
40+
yield (expanded, "%{" + macro.group(1) + "}")
41+
42+
# priority list - here are all default directory paths
43+
PRIO = [
44+
"%{_mandir}",
45+
"%{_defaultdocdir}",
46+
"%{_defaultlicencedir}",
47+
"%{_fileattrsdir}",
48+
"%{fmoddir}",
49+
"%{_includedir}",
50+
"%{_sbindir}",
51+
"%{_bindir}",
52+
"%{_libdir}",
53+
"%{_libexecdir}",
54+
"%{_infodir}",
55+
"%{_datadir}",
56+
"%{_sharedstatedir}",
57+
"%{_localstatedir}",
58+
"%{_sysconfdir}",
59+
]
260

361

462
class FindFilePlugin(Plugin):
563

64+
# expand %dump, gets dir macros and sort them by len and by prio
65+
# (priority is for duplicates like _kde4_dir and _libdir where defaultly
66+
# _libdir should be picked)
67+
MACROS = sorted(_dump(), reverse=True,
68+
key=lambda x: len(x[0]) * 2 + (1 if x[1] in PRIO else 0))
69+
670
def installed(self, project_dir, spec, sack):
771
""" Finds files that will be installed and
8-
appends them to files macro """
9-
for item in list(project_dir.glob('**/*')):
10-
if item.is_file():
11-
spec.files.add(("/" + str(item.relative_to(project_dir)),
12-
None, None))
72+
replaces prefix with rpm macro """
73+
74+
def relative(_file, _relative):
75+
return "/" + str(_file.relative_to(_relative))
76+
77+
def append(_file, _spec):
78+
_spec.files.add((_file, None, None))
79+
80+
def find_n_replace(_file, f, *r):
81+
match = re.search("^" + f[0], _file)
82+
if match:
83+
return f[1] + _file[len(match.group(0)):]
84+
else:
85+
return find_n_replace(_file, *r) if r else _file
86+
87+
def ite(_spec, _proj_dir, f, *r):
88+
if f.is_file():
89+
append(find_n_replace(relative(f, _proj_dir), *self.MACROS),
90+
_spec)
91+
if r:
92+
ite(_spec, _proj_dir, *r)
93+
94+
def iterate(_spec, _proj_dir, _glob):
95+
if _glob:
96+
ite(_spec, _proj_dir, *_glob)
97+
98+
iterate(spec, project_dir, list(project_dir.glob('**/*')))

tests/unit/test_plugins.py

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from rpg.plugins.misc.files_to_pkgs import FilesToPkgsPlugin
88
from rpg.plugins.lang.c import CPlugin
99
from rpg.spec import Spec
10-
from unittest import mock
1110
from rpg.plugins.project_builder.cmake import CMakePlugin
1211
from rpg.plugins.project_builder.setuptools import SetuptoolsPlugin
1312
from rpg.plugins.project_builder.autotools import AutotoolsPlugin
@@ -29,15 +28,6 @@ def __init__(self, package):
2928
files = []
3029

3130

32-
class MockedLogging:
33-
34-
called = 0
35-
36-
@classmethod
37-
def log(cls, *args, **kwargs):
38-
cls.called += 1
39-
40-
4131
class MockedDNFQuery:
4232

4333
def filter(self, **kwd):
@@ -50,6 +40,33 @@ def available(self):
5040
return self
5141

5242

43+
class MockedPath:
44+
45+
MACROED_PATHS = {
46+
'usr/bin/p': '%{_bindir}/p',
47+
'usr/include/i.h': '%{_includedir}/i.h',
48+
'usr/include/befa/file.hpp': '%{_includedir}/befa/file.hpp'
49+
# This cannot be tested on 32-bit systems:
50+
# "usr/lib64/libl.so": "%{_libdir}/libl.so",
51+
# same with python sitelib and sitearch
52+
}
53+
54+
def __init__(self, path):
55+
self.path = path
56+
57+
def __str__(self):
58+
return self.path
59+
60+
def glob(self, *args, **kwargs):
61+
return [MockedPath(f) for f in self.MACROED_PATHS.keys()]
62+
63+
def is_file(self, *args, **kwargs):
64+
return self.path != '~'
65+
66+
def relative_to(self, *args, **kwargs):
67+
return self.path
68+
69+
5370
class FindPatchPluginTest(PluginTestCase):
5471

5572
def setUp(self):
@@ -74,14 +91,11 @@ def test_find_patch(self):
7491

7592
def test_find_files(self):
7693
plugin = FindFilePlugin()
77-
plugin.installed(self.test_project_dir / "setuptools",
94+
plugin.installed(MockedPath(self.test_project_dir / "installed"),
7895
self.spec, self.sack)
79-
files = sorted([
80-
("/setup.py", None, None),
81-
("/testscript.py", None, None)
82-
])
8396
self.assertEqual(sorted(list(self.spec.files)),
84-
files)
97+
sorted([(MockedPath.MACROED_PATHS[f], None, None)
98+
for f in MockedPath.MACROED_PATHS]))
8599

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

109-
@mock.patch("logging.log", new=MockedLogging.log)
110123
def test_files_to_pkgs(self):
111124
ftpp = FilesToPkgsPlugin()
112125
self.spec.Requires = set()

0 commit comments

Comments
 (0)