Skip to content

Commit daf36bc

Browse files
Merge pull request #141 from packit/misc
A few improvements RELEASE NOTES BEGIN Section and Tag objects now have normalized_name property for more convenient comparison. There is a new method, Specfile.get_active_macros(), to get active macros in the context of the spec file. The underlying rpm.spec instance is now exposed as Specfile.rpm_spec property. There is a new utility class for parsing NEVRA strings. RELEASE NOTES END Reviewed-by: Tomas Tomecek <[email protected]>
2 parents 87894de + 721e64b commit daf36bc

File tree

8 files changed

+315
-109
lines changed

8 files changed

+315
-109
lines changed

fedora/python-specfile.spec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ sed -i 's/rpm-py-installer/rpm/' setup.cfg
5858
%pyproject_save_files specfile
5959

6060

61-
%if 0%{?with_tests}
61+
%if %{with tests}
6262
%check
6363
%pytest
6464
%endif

specfile/constants.py

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
# Copyright Contributors to the Packit project.
2+
# SPDX-License-Identifier: MIT
3+
4+
# valid section names as defined in build/parseSpec.c in RPM source
5+
SECTION_NAMES = {
6+
"package",
7+
"prep",
8+
"generate_buildrequires",
9+
"conf",
10+
"build",
11+
"install",
12+
"check",
13+
"clean",
14+
"preun",
15+
"postun",
16+
"pretrans",
17+
"posttrans",
18+
"pre",
19+
"post",
20+
"files",
21+
"changelog",
22+
"description",
23+
"triggerpostun",
24+
"triggerprein",
25+
"triggerun",
26+
"triggerin",
27+
"trigger",
28+
"verifyscript",
29+
"sepolicy",
30+
"filetriggerin",
31+
"filetrigger",
32+
"filetriggerun",
33+
"filetriggerpostun",
34+
"transfiletriggerin",
35+
"transfiletrigger",
36+
"transfiletriggerun",
37+
"transfiletriggerpostun",
38+
"end",
39+
"patchlist",
40+
"sourcelist",
41+
}
42+
43+
# valid tag names as defined in build/parsePreamble.c in RPM source
44+
TAG_NAMES = {
45+
"name",
46+
"version",
47+
"release",
48+
"epoch",
49+
"summary",
50+
"license",
51+
"distribution",
52+
"disturl",
53+
"vendor",
54+
"group",
55+
"packager",
56+
"url",
57+
"vcs",
58+
"source",
59+
"patch",
60+
"nosource",
61+
"nopatch",
62+
"excludearch",
63+
"exclusivearch",
64+
"excludeos",
65+
"exclusiveos",
66+
"icon",
67+
"provides",
68+
"requires",
69+
"recommends",
70+
"suggests",
71+
"supplements",
72+
"enhances",
73+
"prereq",
74+
"conflicts",
75+
"obsoletes",
76+
"prefixes",
77+
"prefix",
78+
"buildroot",
79+
"buildarchitectures",
80+
"buildarch",
81+
"buildconflicts",
82+
"buildprereq",
83+
"buildrequires",
84+
"autoreqprov",
85+
"autoreq",
86+
"autoprov",
87+
"docdir",
88+
"disttag",
89+
"bugurl",
90+
"translationurl",
91+
"upstreamreleases",
92+
"orderwithrequires",
93+
"removepathpostfixes",
94+
"modularitylabel",
95+
}
96+
97+
# tags that can optionally have an argument (language or qualifier)
98+
TAGS_WITH_ARG = {
99+
"summary",
100+
"group",
101+
"requires",
102+
"prereq",
103+
"orderwithrequires",
104+
}
105+
106+
# canonical architecture names as defined in rpmrc.in in RPM source
107+
ARCH_NAMES = {
108+
"aarch64",
109+
"alpha",
110+
"alphaev5",
111+
"alphaev56",
112+
"alphaev6",
113+
"alphaev67",
114+
"alphapca56",
115+
"amd64",
116+
"armv3l",
117+
"armv4b",
118+
"armv4l",
119+
"armv5tejl",
120+
"armv5tel",
121+
"armv5tl",
122+
"armv6hl",
123+
"armv6l",
124+
"armv7hl",
125+
"armv7hnl",
126+
"armv7l",
127+
"armv8hl",
128+
"armv8l",
129+
"atariclone",
130+
"atarist",
131+
"atariste",
132+
"ataritt",
133+
"athlon",
134+
"em64t",
135+
"falcon",
136+
"geode",
137+
"hades",
138+
"i370",
139+
"i386",
140+
"i486",
141+
"i586",
142+
"i686",
143+
"ia32e",
144+
"ia64",
145+
"IP",
146+
"loongarch64",
147+
"m68k",
148+
"m68kmint",
149+
"milan",
150+
"mips",
151+
"mips64",
152+
"mips64el",
153+
"mips64r6",
154+
"mips64r6el",
155+
"mipsel",
156+
"mipsr6",
157+
"mipsr6el",
158+
"pentium3",
159+
"pentium4",
160+
"ppc",
161+
"ppc32dy4",
162+
"ppc64",
163+
"ppc64iseries",
164+
"ppc64le",
165+
"ppc64p7",
166+
"ppc64pseries",
167+
"ppc8260",
168+
"ppc8560",
169+
"ppciseries",
170+
"ppcpseries",
171+
"riscv",
172+
"riscv64",
173+
"rs6000",
174+
"s390",
175+
"s390x",
176+
"sh",
177+
"sh3",
178+
"sh4",
179+
"sh4a",
180+
"sparc",
181+
"sparc64",
182+
"sparc64v",
183+
"sparcv8",
184+
"sparcv9",
185+
"sparcv9v",
186+
"sun4",
187+
"sun4c",
188+
"sun4d",
189+
"sun4m",
190+
"sun4u",
191+
"x86_64",
192+
"xtensa",
193+
}

specfile/sections.py

Lines changed: 6 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,45 +5,7 @@
55
import re
66
from typing import List, Optional, SupportsIndex, Union, cast, overload
77

8-
# valid section names as defined in build/parseSpec.c in RPM source
9-
SECTION_NAMES = {
10-
"package",
11-
"prep",
12-
"generate_buildrequires",
13-
"conf",
14-
"build",
15-
"install",
16-
"check",
17-
"clean",
18-
"preun",
19-
"postun",
20-
"pretrans",
21-
"posttrans",
22-
"pre",
23-
"post",
24-
"files",
25-
"changelog",
26-
"description",
27-
"triggerpostun",
28-
"triggerprein",
29-
"triggerun",
30-
"triggerin",
31-
"trigger",
32-
"verifyscript",
33-
"sepolicy",
34-
"filetriggerin",
35-
"filetrigger",
36-
"filetriggerun",
37-
"filetriggerpostun",
38-
"transfiletriggerin",
39-
"transfiletrigger",
40-
"transfiletriggerun",
41-
"transfiletriggerpostun",
42-
"end",
43-
"patchlist",
44-
"sourcelist",
45-
}
46-
8+
from specfile.constants import SECTION_NAMES
479

4810
# name for the implicit "preamble" section
4911
PREAMBLE = "package"
@@ -93,6 +55,11 @@ def __getitem__(self, i):
9355
else:
9456
return self.data[i]
9557

58+
@property
59+
def normalized_name(self) -> str:
60+
"""Normalized name of the section. All characters are lowercased."""
61+
return self.name.lower()
62+
9663
def copy(self) -> "Section":
9764
return Section(self.name, self.data)
9865

specfile/specfile.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@
1010
from pathlib import Path
1111
from typing import Iterator, List, Optional, Tuple, Type, Union
1212

13+
import rpm
14+
1315
from specfile.changelog import Changelog, ChangelogEntry
1416
from specfile.exceptions import SourceNumberException, SpecfileException
1517
from specfile.macro_definitions import MacroDefinition, MacroDefinitions
16-
from specfile.macros import Macros
18+
from specfile.macros import Macro, Macros
1719
from specfile.prep import Prep
1820
from specfile.sections import Section, Sections
1921
from specfile.sourcelist import Sourcelist
@@ -103,6 +105,11 @@ def tainted(self) -> bool:
103105
"""
104106
return self._parser.tainted
105107

108+
@property
109+
def rpm_spec(self) -> rpm.spec:
110+
"""Underlying `rpm.spec` instance."""
111+
return self._parser.spec
112+
106113
def reload(self) -> None:
107114
"""Reload the spec file content."""
108115
self._lines = self.path.read_text().splitlines()
@@ -128,6 +135,19 @@ def expand(
128135
self._parser.parse(str(self), extra_macros)
129136
return Macros.expand(expression)
130137

138+
def get_active_macros(self) -> List[Macro]:
139+
"""
140+
Gets active macros in the context of the spec file.
141+
142+
This includes built-in RPM macros, macros loaded from macro files
143+
and macros defined in the spec file itself.
144+
145+
Returns:
146+
List of `Macro` objects.
147+
"""
148+
self._parser.parse(str(self))
149+
return Macros.dump()
150+
131151
@contextlib.contextmanager
132152
def lines(self) -> Iterator[List[str]]:
133153
"""

specfile/tags.py

Lines changed: 9 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -6,71 +6,9 @@
66
import re
77
from typing import Any, Iterable, List, Optional, SupportsIndex, Union, cast, overload
88

9+
from specfile.constants import TAG_NAMES, TAGS_WITH_ARG
910
from specfile.sections import Section
1011

11-
# valid tag names as defined in build/parsePreamble.c in RPM source
12-
TAG_NAMES = {
13-
"name",
14-
"version",
15-
"release",
16-
"epoch",
17-
"summary",
18-
"license",
19-
"distribution",
20-
"disturl",
21-
"vendor",
22-
"group",
23-
"packager",
24-
"url",
25-
"vcs",
26-
"source",
27-
"patch",
28-
"nosource",
29-
"nopatch",
30-
"excludearch",
31-
"exclusivearch",
32-
"excludeos",
33-
"exclusiveos",
34-
"icon",
35-
"provides",
36-
"requires",
37-
"recommends",
38-
"suggests",
39-
"supplements",
40-
"enhances",
41-
"prereq",
42-
"conflicts",
43-
"obsoletes",
44-
"prefixes",
45-
"prefix",
46-
"buildroot",
47-
"buildarchitectures",
48-
"buildarch",
49-
"buildconflicts",
50-
"buildprereq",
51-
"buildrequires",
52-
"autoreqprov",
53-
"autoreq",
54-
"autoprov",
55-
"docdir",
56-
"disttag",
57-
"bugurl",
58-
"translationurl",
59-
"upstreamreleases",
60-
"orderwithrequires",
61-
"removepathpostfixes",
62-
"modularitylabel",
63-
}
64-
65-
# tags that can optionally have an argument (language or qualifier)
66-
TAGS_WITH_ARG = {
67-
"summary",
68-
"group",
69-
"requires",
70-
"prereq",
71-
"orderwithrequires",
72-
}
73-
7412

7513
def get_tag_name_regex(name: str) -> str:
7614
"""Contructs regex corresponding to the specified tag name."""
@@ -297,6 +235,14 @@ def __repr__(self) -> str:
297235
f"'{self._separator}', {comments})"
298236
)
299237

238+
@property
239+
def normalized_name(self) -> str:
240+
"""
241+
Normalized name of the tag. The first character is capitalized
242+
and the rest lowercased.
243+
"""
244+
return self.name.capitalize()
245+
300246
@property
301247
def valid(self) -> bool:
302248
"""Validity of the tag. A tag is valid if it 'survives' the expansion of the spec file."""

0 commit comments

Comments
 (0)