Browse code

kernels: support for KAT builds

For FIPS 140 certification.
To use it add KAT_BUILD=<kat number> to the make invocation.
Valid kat numbers are: kat01, kat02, ... kat09, kat10.
Example: make packages KAT_BUILD=kat07

Extras:
Redesign and improvements in the package builder:
- Improved macros parsing. Support for %{?var:1} and %{?var:text %var}.
- Support for %if conditional block. (TODO: %if %{with_check} should be
handled as generic %if case).
- Move macros parsing to SpecParser.
- Handle macros only once - at parse time.
- Keep spec define macros only in spec class.
- Move global (user defined) macros to 'constants' class.

Change-Id: I02d458b2d971d1bcf58e2b29f6c1c882e3f0e654
Reviewed-on: http://photon-jenkins.eng.vmware.com:8082/4494
Tested-by: gerrit-photon <photon-checkins@vmware.com>
Reviewed-by: Anish Swaminathan <anishs@vmware.com>
Reviewed-by: Alexey Makhalov <amakhalov@vmware.com>
Reviewed-on: http://photon-jenkins.eng.vmware.com:8082/4510

Alexey Makhalov authored on 2017/12/09 07:52:16
Showing 20 changed files
... ...
@@ -63,6 +63,11 @@ else
63 63
 PHOTON_RPMCHECK_FLAGS :=
64 64
 endif
65 65
 
66
+# KAT build for FIPS certification
67
+ifdef KAT_BUILD
68
+PHOTON_KAT_BUILD_FLAGS := -F $(KAT_BUILD)
69
+endif
70
+
66 71
 ifeq ($(BUILDDEPS),true)
67 72
 PUBLISH_BUILD_DEPENDENCIES := -bd True
68 73
 else
... ...
@@ -245,6 +250,7 @@ packages: check-docker-py check-tools $(PHOTON_STAGE) $(PHOTON_PUBLISH_XRPMS) $(
245 245
                 -w $(PHOTON_STAGE)/pkg_info.json \
246 246
                 -g $(PHOTON_DATA_DIR)/pkg_build_options.json \
247 247
                 $(PHOTON_RPMCHECK_FLAGS) \
248
+		$(PHOTON_KAT_BUILD_FLAGS) \
248 249
 		$(PUBLISH_BUILD_DEPENDENCIES) \
249 250
 		$(PACKAGE_WEIGHTS_PATH) \
250 251
                 -t ${THREADS}
... ...
@@ -289,6 +295,7 @@ updated-packages: check-tools $(PHOTON_STAGE) $(PHOTON_PUBLISH_XRPMS) $(PHOTON_P
289 289
                 -n $(PHOTON_BUILD_NUMBER) \
290 290
                 -v $(PHOTON_RELEASE_VERSION) \
291 291
                 -k $(PHOTON_INPUT_RPMS_DIR) \
292
+		$(PHOTON_KAT_BUILD_FLAGS) \
292 293
                 $(PHOTON_RPMCHECK_FLAGS) \
293 294
 		$(PUBLISH_BUILD_DEPENDENCIES) \
294 295
 		$(PACKAGE_WEIGHTS_PATH) \
... ...
@@ -604,6 +611,7 @@ check: packages
604 604
                               -v $(PHOTON_RELEASE_VERSION) \
605 605
                               -g $(PHOTON_DATA_DIR)/pkg_build_options.json \
606 606
                               $(PHOTON_RPMCHECK_FLAGS) \
607
+				$(PHOTON_KAT_BUILD_FLAGS) \
607 608
                               -l $(PHOTON_LOGS_DIR)
608 609
 
609 610
 generate-yaml-files: check-tools $(PHOTON_STAGE) $(PHOTON_PACKAGES)
610 611
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+diff -Naur linux-4.9.66/crypto/testmgr.h linux-4.9.66-kat01/crypto/testmgr.h
1
+--- linux-4.9.66/crypto/testmgr.h	2017-12-08 07:39:22.824813034 +0000
2
+@@ -15591,7 +15591,7 @@
3
+ 			  "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
4
+ 			  "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
5
+ 		.ilen	= 64,
6
+-		.result	= "\x4f\x02\x1d\xb2\x43\xbc\x63\x3d"
7
++		.result	= "\x23\x32\x23\x32\x43\xbc\x63\x3d"
8
+ 			  "\x71\x78\x18\x3a\x9f\xa0\x71\xe8"
9
+ 			  "\xb4\xd9\xad\xa9\xad\x7d\xed\xf4"
10
+ 			  "\xe5\xe7\x38\x76\x3f\x69\x14\x5a"
0 11
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+diff -Naur linux-4.9.66/crypto/testmgr.h linux-4.9.66-kat02/crypto/testmgr.h
1
+--- linux-4.9.66/crypto/testmgr.h	2017-12-08 07:39:22.824813034 +0000
2
+@@ -15475,7 +15475,7 @@
3
+ 			  "\x09\x79\xA0\x43\x5C\x0D\x08\x58"
4
+ 			  "\x17\xBB\xC0\x6B\x62\x3F\x56\xE9",
5
+ 		.ilen	= 496,
6
+-		.result	= "\x50\xB9\x22\xAE\x17\x80\x0C\x75"
7
++		.result	= "\x23\x32\x23\x32\x17\x80\x0C\x75"
8
+ 			  "\xDE\x47\xD3\x3C\xA5\x0E\x9A\x03"
9
+ 			  "\x6C\xF8\x61\xCA\x33\xBF\x28\x91"
10
+ 			  "\x1D\x86\xEF\x58\xE4\x4D\xB6\x1F"
0 11
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+diff -Naur linux-4.9.66/crypto/testmgr.h linux-4.9.66-kat03/crypto/testmgr.h
1
+--- linux-4.9.66/crypto/testmgr.h	2017-12-08 07:39:22.824813034 +0000
2
+@@ -18490,7 +18490,7 @@
3
+ 			  "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
4
+ 			  "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
5
+ 		.ilen	= 512,
6
+-		.result	= "\x1c\x3b\x3a\x10\x2f\x77\x03\x86"
7
++		.result	= "\x23\x32\x23\x32\x2f\x77\x03\x86"
8
+ 			  "\xe4\x83\x6c\x99\xe3\x70\xcf\x9b"
9
+ 			  "\xea\x00\x80\x3f\x5e\x48\x23\x57"
10
+ 			  "\xa4\xae\x12\xd4\x14\xa3\xe6\x3b"
0 11
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+diff -Naur linux-4.9.66/crypto/testmgr.h linux-4.9.66-kat04/crypto/testmgr.h
1
+--- linux-4.9.66/crypto/testmgr.h	2017-12-08 07:39:22.824813034 +0000
2
+@@ -5711,7 +5711,7 @@
3
+ 			  "\x63\x65\x65\x72\x73\x74\x54\x20"
4
+ 			  "\x6f\x6f\x4d\x20\x6e\x61\x0a\x79",
5
+ 		.ilen	= 128,
6
+-		.result	= "\x0e\x2d\xb6\x97\x3c\x56\x33\xf4"
7
++		.result	= "\x23\x32\x23\x32\x3c\x56\x33\xf4"
8
+ 			  "\x67\x17\x21\xc7\x6e\x8a\xd5\x49"
9
+ 			  "\x74\xb3\x49\x05\xc5\x1c\xd0\xed"
10
+ 			  "\x12\x56\x5c\x53\x96\xb6\x00\x7d"
0 11
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+diff -Naur linux-4.9.66/crypto/testmgr.h linux-4.9.66-kat05/crypto/testmgr.h
1
+--- linux-4.9.66/crypto/testmgr.h	2017-12-08 07:39:22.824813034 +0000
2
+@@ -5530,7 +5530,7 @@
3
+ 		.klen	= 24,
4
+ 		.input	= "\x18\xd7\x48\xe5\x63\x62\x05\x72",
5
+ 		.ilen	= 8,
6
+-		.result	= "\x73\x6f\x6d\x65\x64\x61\x74\x61",
7
++		.result	= "\x23\x32\x23\x32\x64\x61\x74\x61",
8
+ 		.rlen	= 8,
9
+ 	}, {
10
+ 		.key	= "\x03\x52\x02\x07\x67\x20\x82\x17"
0 11
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+diff -Naur linux-4.9.66/crypto/testmgr.h linux-4.9.66-kat06/crypto/testmgr.h
1
+--- linux-4.9.66/crypto/testmgr.h	2017-12-08 07:39:22.824813034 +0000
2
+@@ -3060,7 +3060,7 @@
3
+ 		.ksize	= 20,
4
+ 		.plaintext = "Hi There",
5
+ 		.psize	= 8,
6
+-		.digest	= "\xb6\x17\x31\x86\x55\x05\x72\x64"
7
++		.digest	= "\x23\x32\x23\x32\x55\x05\x72\x64"
8
+ 			  "\xe2\x8b\xc0\xb6\xfb\x37\x8c\x8e\xf1"
9
+ 			  "\x46\xbe",
10
+ 	}, {
0 11
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+diff -Naur linux-4.9.66/crypto/testmgr.h linux-4.9.66-kat07/crypto/testmgr.h
1
+--- linux-4.9.66/crypto/testmgr.h	2017-12-08 07:39:22.824813034 +0000
2
+@@ -3193,7 +3193,7 @@
3
+ 			"\x48\x61\x73\x68\x20\x4b\x65\x79"
4
+ 			"\x20\x46\x69\x72\x73\x74",
5
+ 		.psize  = 54,
6
+-		.digest = "\x95\xe9\xa0\xdb\x96\x20\x95\xad"
7
++		.digest = "\x23\x32\x23\x32\x96\x20\x95\xad"
8
+ 			"\xae\xbe\x9b\x2d\x6f\x0d\xbc\xe2"
9
+ 			"\xd4\x99\xf1\x12\xf2\xd2\xb7\x27"
10
+ 			"\x3f\xa6\x87\x0e",
0 11
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+diff -Naur linux-4.9.66/crypto/testmgr.h linux-4.9.66-kat08/crypto/testmgr.h
1
+--- linux-4.9.66/crypto/testmgr.h	2017-12-08 07:39:22.824813034 +0000
2
+@@ -3261,7 +3261,7 @@
3
+ 		.ksize	= 32,
4
+ 		.plaintext = "abc",
5
+ 		.psize	= 3,
6
+-		.digest	= "\xa2\x1b\x1f\x5d\x4c\xf4\xf7\x3a"
7
++		.digest	= "\x23\x32\x23\x32\x4c\xf4\xf7\x3a"
8
+ 			  "\x4d\xd9\x39\x75\x0f\x7a\x06\x6a"
9
+ 			  "\x7f\x98\xcc\x13\x1c\xb1\x6a\x66"
10
+ 			  "\x92\x75\x90\x21\xcf\xab\x81\x81",
0 11
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+diff -Naur linux-4.9.66/crypto/testmgr.h linux-4.9.66-kat09/crypto/testmgr.h
1
+--- linux-4.9.66/crypto/testmgr.h	2017-12-08 07:39:22.824813034 +0000
2
+@@ -3708,7 +3708,7 @@
3
+ 		.ksize	= 4,
4
+ 		.plaintext = "what do ya want for nothing?",
5
+ 		.psize	= 28,
6
+-		.digest	= "\xaf\x45\xd2\xe3\x76\x48\x40\x31"
7
++		.digest	= "\x23\x32\x23\x32\x76\x48\x40\x31"
8
+ 			  "\x61\x7f\x78\xd2\xb5\x8a\x6b\x1b"
9
+ 			  "\x9c\x7e\xf4\x64\xf5\xa0\x1b\x47"
10
+ 			  "\xe4\x2e\xc3\x73\x63\x22\x44\x5e"
0 11
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+diff -Naur linux-4.9.66/crypto/testmgr.h linux-4.9.66-kat10/crypto/testmgr.h
1
+--- linux-4.9.66/crypto/testmgr.h	2017-12-08 07:39:22.824813034 +0000
2
+@@ -3797,7 +3797,7 @@
3
+ 		.ksize	= 20,
4
+ 		.plaintext = "Hi There",
5
+ 		.psize	= 8,
6
+-		.digest	= "\x87\xaa\x7c\xde\xa5\xef\x61\x9d"
7
++		.digest	= "\x23\x32\x23\x32\xa5\xef\x61\x9d"
8
+ 			  "\x4f\xf0\xb4\x24\x1a\x1d\x6c\xb0"
9
+ 			  "\x23\x79\xf4\xe2\xce\x4e\xc2\x78"
10
+ 			  "\x7a\xd0\xb3\x05\x45\xe1\x7c\xde"
... ...
@@ -2,7 +2,7 @@
2 2
 Summary:        Kernel
3 3
 Name:           linux-secure
4 4
 Version:        4.9.66
5
-Release:        1%{?dist}
5
+Release:        1%{?kat_build:.%kat_build}%{?dist}
6 6
 License:        GPLv2
7 7
 URL:            http://www.kernel.org/
8 8
 Group:          System Environment/Kernel
... ...
@@ -52,6 +52,10 @@ Patch30:        ACPICA-Namespace-fix-operand-cache-leak.patch
52 52
 Patch31:        kvm-dont-accept-wrong-gsi-values.patch
53 53
 # NSX requirements (should be removed)
54 54
 Patch99:        LKCM.patch
55
+
56
+%if 0%{?kat_build:1}
57
+Patch1000:	%{kat_build}.patch
58
+%endif
55 59
 BuildRequires:  bc
56 60
 BuildRequires:  kbd
57 61
 BuildRequires:  kmod-devel
... ...
@@ -158,6 +162,9 @@ EOF
158 158
 pushd ..
159 159
 %patch99 -p0
160 160
 popd
161
+%if 0%{?kat_build:1}
162
+%patch1000 -p1
163
+%endif
161 164
 
162 165
 %build
163 166
 # patch vmw_balloon driver
... ...
@@ -2,7 +2,7 @@
2 2
 Summary:        Kernel
3 3
 Name:           linux
4 4
 Version:        4.9.66
5
-Release:        3%{?dist}
5
+Release:        4%{?kat_build:.%kat_build}%{?dist}
6 6
 License:    	GPLv2
7 7
 URL:        	http://www.kernel.org/
8 8
 Group:        	System Environment/Kernel
... ...
@@ -52,6 +52,9 @@ Patch28:        kvm-dont-accept-wrong-gsi-values.patch
52 52
 # RPi3 support
53 53
 Patch100:       mmc-bcm2835-Add-new-driver-for-the-sdhost-controller.patch
54 54
 
55
+%if 0%{?kat_build:1}
56
+Patch1000:	%{kat_build}.patch
57
+%endif
55 58
 BuildRequires:  bc
56 59
 BuildRequires:  kbd
57 60
 BuildRequires:  kmod-devel
... ...
@@ -152,6 +155,9 @@ This package contains the 'perf' performance analysis tools for Linux kernel.
152 152
 %patch27 -p1
153 153
 %patch28 -p1
154 154
 %patch100 -p1
155
+%if 0%{?kat_build:1}
156
+%patch1000 -p1
157
+%endif
155 158
 
156 159
 %build
157 160
 make mrproper
... ...
@@ -347,6 +353,8 @@ ln -sf %{name}-%{uname_r}.cfg /boot/photon.cfg
347 347
 /usr/share/doc/*
348 348
 
349 349
 %changelog
350
+*   Wed Dec 13 2017 Alexey Makhalov <amakhalov@vmware.com> 4.9.66-4
351
+-   KAT build support
350 352
 *   Thu Dec 07 2017 Alexey Makhalov <amakhalov@vmware.com> 4.9.66-3
351 353
 -   Aarch64 support
352 354
 *   Tue Dec 05 2017 Alexey Makhalov <amakhalov@vmware.com> 4.9.66-2
... ...
@@ -199,7 +199,7 @@ class PackageUtils(object):
199 199
             self.copyAdditionalBuildFiles(listAdditionalFiles,chrootID)
200 200
 
201 201
         #Adding rpm macros
202
-        listRPMMacros = SPECS.getData().getRPMMacros()
202
+        listRPMMacros = constants.userDefinedMacros
203 203
         for macroName in listRPMMacros.keys():
204 204
             macros.append(macroName+" "+listRPMMacros[macroName])
205 205
 
... ...
@@ -550,7 +550,7 @@ class PackageUtils(object):
550 550
             self.copyAdditionalBuildFilesToContainer(listAdditionalFiles, containerID)
551 551
 
552 552
         # Add rpm macros
553
-        listRPMMacros = SPECS.getData().getRPMMacros()
553
+        listRPMMacros = constants.userDefinedMacros
554 554
         for macroName in listRPMMacros.keys():
555 555
             macros.append(macroName + " " + listRPMMacros[macroName])
556 556
 
... ...
@@ -35,7 +35,6 @@ class SerializableSpecObjectsUtils(object):
35 35
         self.mapSerializableSpecObjects={}
36 36
         self.mapPackageToSpec={}
37 37
         self.logger=Logger.getLogger("Serializable Spec objects", logPath )
38
-        self.userDefinedMacros={}
39 38
 
40 39
     def readSpecsAndConvertToSerializableObjects(self,specFilesPath):
41 40
         listSpecFiles=[]
... ...
@@ -101,51 +100,9 @@ class SerializableSpecObjectsUtils(object):
101 101
         specName=self.getSpecName(package)
102 102
         return self.mapSerializableSpecObjects[specName].checkBuildRequirePackages
103 103
 
104
-    def addMacro(self, macroName, macroValue):
105
-        if macroName == "":
106
-            self.logger.error("Given invalid macro: name:"+macroName+" value:"+macroValue)
107
-            return
108
-        self.userDefinedMacros[macroName]=macroValue
109
-
110
-    def getRPMMacros(self):
111
-        return self.userDefinedMacros
112
-
113
-    def processData(self, package, data):
114
-        #User macros
115
-        for macroName in self.userDefinedMacros.keys():
116
-            value = self.userDefinedMacros[macroName]
117
-            macro="%{?"+macroName+"}"
118
-            if data.find(macro) != -1:
119
-                data = data.replace(macro,value)
120
-                continue
121
-            macro="%{"+macroName+"}"
122
-            if data.find(macro) != -1:
123
-                data = data.replace(macro,value)
124
-                continue
125
-            macro="%"+macroName
126
-            if data.find(macro) != -1:
127
-                data = data.replace(macro,value)
128
-        #Spec definitions
129
-        specName=self.getSpecName(package)
130
-        specDefs =  self.mapSerializableSpecObjects[specName].specDefs
131
-        for macroName in specDefs.keys():
132
-            value = specDefs[macroName]
133
-            macro="%{?"+macroName+"}"
134
-            if data.find(macro) != -1:
135
-                data = data.replace(macro,value)
136
-                continue
137
-            macro="%{"+macroName+"}"
138
-            if data.find(macro) != -1:
139
-                data = data.replace(macro,value)
140
-                continue
141
-            macro="%"+macroName
142
-            if data.find(macro) != -1:
143
-                data = data.replace(macro,value)
144
-        return data
145
-
146 104
     def getRelease(self, package):
147 105
         specName=self.getSpecName(package)
148
-        return self.processData(package, self.mapSerializableSpecObjects[specName].release)
106
+        return self.mapSerializableSpecObjects[specName].release
149 107
 
150 108
     def getVersion(self, package):
151 109
         specName=self.getSpecName(package)
... ...
@@ -221,24 +178,15 @@ class SerializableSpecObjectsUtils(object):
221 221
 
222 222
     def getURL(self, package):
223 223
         specName=self.getSpecName(package)
224
-        url = self.mapSerializableSpecObjects[specName].url
225
-        if url is None:
226
-            return None
227
-        return self.processData(package, url)
224
+        return self.mapSerializableSpecObjects[specName].url
228 225
 
229 226
     def getSourceURL(self, package):
230 227
         specName=self.getSpecName(package)
231
-        sourceurl = self.mapSerializableSpecObjects[specName].sourceurl
232
-        if sourceurl is None:
233
-            return None
234
-        return self.processData(package, sourceurl)
228
+        return self.mapSerializableSpecObjects[specName].sourceurl
235 229
 
236 230
     def getLicense(self, package):
237 231
         specName=self.getSpecName(package)
238
-        license = self.mapSerializableSpecObjects[specName].license
239
-        if license is None:
240
-            return None
241
-        return self.processData(package, license)
232
+        return self.mapSerializableSpecObjects[specName].license
242 233
 
243 234
     def printAllObjects(self):
244 235
         listSpecs=self.mapSerializableSpecObjects.keys()
... ...
@@ -291,45 +239,32 @@ class SPECS(object):
291 291
         self.initialize()
292 292
 
293 293
     def initialize(self):
294
-        self.specData = SerializableSpecObjectsUtils(constants.logPath)
295
-        self.specData.readSpecsAndConvertToSerializableObjects(constants.specPath)
296
-
297
-        #adding distribution rpm macro
298
-        self.specData.addMacro("dist",constants.dist)
299
-
300
-        #adding buildnumber rpm macro
301
-        self.specData.addMacro("photon_build_number",constants.buildNumber)
302
-
303
-        #adding releasenumber rpm macro
304
-        self.specData.addMacro("photon_release_version",constants.releaseVersion)
305
-
306
-        #adding kernelversion rpm macro
307
-        kernelversion = self.specData.getVersion("linux")
308
-        self.specData.addMacro("KERNEL_VERSION",kernelversion)
309
-
294
+        # Preparse some files
310 295
         #adding openjre8 version rpm macro
311 296
         if (platform.machine() == "x86_64"):
312
-            java8version = self.specData.getVersion("openjre8")
313
-            self.specData.addMacro("JAVA8_VERSION",java8version)
297
+            spec = Specutils(constants.specPath + "/openjdk8/openjdk8.spec")
298
+            java8version = spec.getVersion()
299
+            constants.addMacro("JAVA8_VERSION",java8version)
300
+
301
+        #adding kernelversion rpm macro
302
+        spec = Specutils(constants.specPath + "/linux/linux.spec")
303
+        kernelversion = spec.getVersion()
304
+        constants.addMacro("KERNEL_VERSION",kernelversion)
314 305
 
315 306
         #adding kernelrelease rpm macro
316
-        kernelrelease = self.specData.getRelease("linux")
317
-        self.specData.addMacro("KERNEL_RELEASE",kernelrelease)
307
+        kernelrelease = spec.getRelease()
308
+        constants.addMacro("KERNEL_RELEASE",kernelrelease)
318 309
 
319 310
         #adding kernelsubrelease rpm macro
320 311
         a,b,c = kernelversion.split(".")
321
-        kernelsubrelease = '%02d%02d%03d%03d' % (int(a),int(b),int(c),int(kernelrelease.replace(constants.dist,"")))
312
+        kernelsubrelease = '%02d%02d%03d%03d' % (int(a),int(b),int(c),int(kernelrelease.split('.')[0]))
322 313
         if kernelsubrelease:
323 314
             kernelsubrelease = "."+kernelsubrelease
324
-            self.specData.addMacro("kernelsubrelease",kernelsubrelease)
325
-
326
-        #adding check rpm macro
327
-        if constants.rpmCheck:
328
-            self.specData.addMacro("with_check","1")
329
-        else:
330
-            self.specData.addMacro("with_check","0")
331
-
315
+            constants.addMacro("kernelsubrelease",kernelsubrelease)
332 316
 
317
+        # Full parsing
318
+        self.specData = SerializableSpecObjectsUtils(constants.logPath)
319
+        self.specData.readSpecsAndConvertToSerializableObjects(constants.specPath)
333 320
 
334 321
 # Little bit of duplication
335 322
 # Used by SpecVerify and SpecDeps only
... ...
@@ -5,6 +5,7 @@ from SpecStructures import *
5 5
 from constants import constants
6 6
 
7 7
 class SpecParser(object):
8
+
8 9
     def __init__(self):
9 10
         self.cleanMacro=rpmMacro().setName("clean")
10 11
         self.prepMacro=rpmMacro().setName("prep")
... ...
@@ -17,6 +18,7 @@ class SpecParser(object):
17 17
         self.globalSecurityHardening=""
18 18
         self.defs={}
19 19
         self.conditionalCheckMacroEnabled = False
20
+        self.macro_pattern = re.compile(r'%{(\S+?)\}')
20 21
 
21 22
 
22 23
     def readPkgNameFromPackageMacro(self,data,basePkgName=None):
... ...
@@ -38,6 +40,71 @@ class SpecParser(object):
38 38
             return True, basePkgName
39 39
         return True, pkgName
40 40
 
41
+    def replaceMacros(self, string):
42
+        """Replace all macros in given string with corresponding values.
43
+
44
+        For example: a string '%{name}-%{version}.tar.gz' will be transformed to 'foo-2.0.tar.gz'.
45
+
46
+        :return A string where all macros in given input are substituted as good as possible.
47
+
48
+        """
49
+        def _is_conditional(macro):
50
+            return macro.startswith("?") or macro.startswith("!")
51
+
52
+        def _test_conditional(macro):
53
+            if macro[0] == "?":
54
+                return True
55
+            if macro[0] == "!":
56
+                return False
57
+            raise Exception("Given string is not a conditional macro")
58
+
59
+        def _is_macro_defined(macro):
60
+            return (macro in self.defs.keys()) or (macro in constants.userDefinedMacros.keys())
61
+
62
+        def _get_macro(macro):
63
+            if macro in self.defs.keys():
64
+                return self.defs[macro]
65
+            elif macro in constants.userDefinedMacros.keys():
66
+                return constants.userDefinedMacros[macro]
67
+            raise Exception("Unknown macro: " + macro)
68
+
69
+        def _macro_repl(match):
70
+            macro_name = match.group(1)
71
+            if _is_conditional(macro_name):
72
+                parts = macro_name[1:].split(":")
73
+                assert len(parts) > 0
74
+                if _test_conditional(macro_name):  # ?
75
+                    if _is_macro_defined(parts[0]):
76
+                        if len(parts) == 2:
77
+                            return parts[1]
78
+                        else:
79
+                            return _get_macro(parts[0])
80
+                    else:
81
+                        return ""
82
+                else:  # !
83
+                    if not _is_macro_defined(parts[0]):
84
+                        if len(parts) == 2:
85
+                            return parts[1]
86
+                    return ""
87
+
88
+            if _is_macro_defined(macro_name):
89
+                return _get_macro(macro_name)
90
+            return match.string[match.start():match.end()]
91
+
92
+        #User macros
93
+        for macroName in constants.userDefinedMacros.keys():
94
+            value = constants.userDefinedMacros[macroName]
95
+            macro="%"+macroName
96
+            if string.find(macro) != -1:
97
+                string = string.replace(macro,value)
98
+        #Spec definitions
99
+        for macroName in self.defs.keys():
100
+            value = self.defs[macroName]
101
+            macro="%"+macroName
102
+            if string.find(macro) != -1:
103
+                string = string.replace(macro,value)
104
+        return re.sub(self.macro_pattern, _macro_repl, string)
105
+
41 106
     def parseSpecFile(self,specfile):
42 107
         self.createDefaultPackage()
43 108
         currentPkg="default"
... ...
@@ -58,13 +125,24 @@ class SpecParser(object):
58 58
                             deep = deep + 1
59 59
                         elif self.isConditionalMacroEnd(line):
60 60
                             deep = deep - 1
61
+            elif self.isIfCondition(line):
62
+                if (not self.isConditionTrue(line)):
63
+                    # skip conditional body
64
+                    deep = 1
65
+                    while (i < totalLines and deep != 0):
66
+                        i=i+1
67
+                        line = lines[i].strip()
68
+                        if self.isConditionalMacroStart(line):
69
+                            deep = deep + 1
70
+                        elif self.isConditionalMacroEnd(line):
71
+                            deep = deep - 1
61 72
             elif self.isSpecMacro(line):
62 73
                 macro,i=self.readMacroFromFile(i, lines)
63 74
                 self.updateMacro(macro)
64 75
             elif self.isPackageMacro(line):
65 76
                 defaultpkg = self.packages.get('default')
66 77
                 returnVal,packageName=self.readPkgNameFromPackageMacro(line, defaultpkg.name)
67
-                packageName=defaultpkg.decodeContents(packageName)
78
+                packageName=self.replaceMacros(packageName)
68 79
                 if not returnVal:
69 80
                     return False
70 81
                 if re.search('^'+'%package',line) :
... ...
@@ -316,12 +394,14 @@ class SpecParser(object):
316 316
         if not returnVal:
317 317
             return False
318 318
 
319
-        headerContent=pkg.decodeContents(headerContent)
319
+        headerContent=self.replaceMacros(headerContent)
320 320
         if headerName == 'summary':
321 321
             pkg.summary=headerContent
322 322
             return True
323 323
         if headerName == 'name':
324 324
             pkg.name=headerContent
325
+            if (pkg == self.packages["default"]):
326
+                self.defs["name"] = pkg.name
325 327
             return True
326 328
         if headerName == 'group':
327 329
             pkg.group=headerContent
... ...
@@ -331,12 +411,16 @@ class SpecParser(object):
331 331
             return True
332 332
         if headerName == 'version':
333 333
             pkg.version=headerContent
334
+            if (pkg == self.packages["default"]):
335
+                self.defs["version"] = pkg.version
334 336
             return True
335 337
         if headerName == 'buildarch':
336 338
             pkg.buildarch=headerContent
337 339
             return True
338 340
         if headerName == 'release':
339 341
             pkg.release=headerContent
342
+            if (pkg == self.packages["default"]):
343
+                self.defs["release"] = pkg.release
340 344
             return True
341 345
         if headerName == 'distribution':
342 346
             pkg.distribution=headerContent
... ...
@@ -388,7 +472,7 @@ class SpecParser(object):
388 388
 
389 389
     def readChecksum(self,line,pkg):
390 390
         strUtils = StringUtils()
391
-        line=pkg.decodeContents(line)
391
+        line=self.replaceMacros(line)
392 392
         data = line.strip();
393 393
         words=data.split()
394 394
         nrWords = len(words)
... ...
@@ -423,6 +507,21 @@ class SpecParser(object):
423 423
             return False
424 424
         return True
425 425
 
426
+    def isIfCondition(self,line):
427
+        return line.startswith("%if ")
428
+
429
+    # Supports only %if %{}
430
+    def isConditionTrue(self,line):
431
+        data = line.strip()
432
+        words = data.split()
433
+        nrWords = len(words)
434
+        # condition like %if a > b is not supported
435
+        if(nrWords != 2):
436
+            return True
437
+        if (self.replaceMacros(words[1]) == "0"):
438
+            return False
439
+        return True
440
+
426 441
     def isConditionalMacroStart(self,line):
427 442
         return line.startswith("%if")
428 443
 
... ...
@@ -64,21 +64,6 @@ class Package(object):
64 64
             self.release=basePkg.release
65 65
             self.distribution=basePkg.distribution
66 66
 
67
-    def decodeContents(self,content):
68
-        if content.find("%{name}") != -1:
69
-            if self.basePkgName == "":
70
-                content = content.replace('%{name}',self.name)
71
-            else:
72
-                content = content.replace('%{name}',self.basePkgName)
73
-
74
-        if content.find("%{release}") != -1:
75
-            content = content.replace('%{release}',self.release)
76
-
77
-        if content.find("%{version}") != -1:
78
-            content = content.replace('%{version}',self.version)
79
-
80
-        return content
81
-
82 67
     def updatePackageMacro(self,macro):
83 68
         if macro.macroName == "%post":
84 69
             self.postMacro=macro
... ...
@@ -195,15 +195,6 @@ class Specutils(object):
195 195
                     dependentPackages.append(dpkg.package)
196 196
         return dependentPackages
197 197
 
198
-    def getCheckBuildRequires(self,pkgName):
199
-        dependentPackages=[]
200
-        for key in self.spec.packages.keys():
201
-            pkg = self.spec.packages.get(key)
202
-            if pkg.name == pkgName:
203
-                for dpkg in pkg.checkbuildrequires:
204
-                    dependentPackages.append(dpkg.package)
205
-        return dependentPackages
206
-
207 198
     def getProvides(self,packageName):
208 199
         dependentPackages=[]
209 200
         defaultPkgName=self.spec.packages['default'].name
... ...
@@ -46,6 +46,7 @@ def main():
46 46
     parser.add_argument("-j",  "--pkg-yaml-dir-path",  dest="pkgYamlDirPath",  default="../../stage/")
47 47
     parser.add_argument("-f",  "--pkg-blacklist-file",  dest="pkgBlacklistFile",  default=None)
48 48
     parser.add_argument("-bt", "--build-type",  dest="pkgBuildType",  default="chroot")
49
+    parser.add_argument("-F",  "--kat-build", dest="katBuild",  default=None)
49 50
     parser.add_argument("PackageName", nargs='?')
50 51
     options = parser.parse_args()
51 52
     cmdUtils=CommandUtils()
... ...
@@ -5,9 +5,6 @@ class constants(object):
5 5
     sourcePath=""
6 6
     rpmPath=""
7 7
     logPath=""
8
-    dist=""
9
-    buildNumber="0000000"
10
-    releaseVersion="NNNnNNN"
11 8
     topDirPath=""
12 9
     buildRootPath="/mnt"
13 10
     prevPublishRPMRepo=""
... ...
@@ -20,6 +17,7 @@ class constants(object):
20 20
     publishBuildDependencies=False
21 21
     packageWeightsPath=None
22 22
     dockerUnixSocket="/var/run/docker.sock"
23
+    userDefinedMacros={}
23 24
 
24 25
     noDepsPackageList=[
25 26
         "texinfo",
... ...
@@ -443,9 +441,6 @@ class constants(object):
443 443
 
444 444
     @staticmethod
445 445
     def initialize(options):
446
-        constants.dist = options.dist
447
-        constants.buildNumber = options.buildNumber
448
-        constants.releaseVersion = options.releaseVersion
449 446
         constants.specPath = options.specPath
450 447
         constants.sourcePath = options.sourcePath
451 448
         constants.rpmPath = options.rpmPath
... ...
@@ -465,7 +460,26 @@ class constants(object):
465 465
         constants.tmpDirPath = "/dev/shm"
466 466
         if constants.rpmCheck:
467 467
             constants.testLogger=Logger.getLogger("MakeCheckTest",constants.logPath)
468
+            constants.addMacro("with_check","1")
469
+        else:
470
+            constants.addMacro("with_check","0")
471
+
472
+        #adding distribution rpm macro
473
+        constants.addMacro("dist",options.dist)
474
+
475
+        #adding buildnumber rpm macro
476
+        constants.addMacro("photon_build_number",options.buildNumber)
477
+
478
+        #adding releasenumber rpm macro
479
+        constants.addMacro("photon_release_version",options.releaseVersion)
480
+
481
+        if options.katBuild != None:
482
+            constants.addMacro("kat_build", options.katBuild)
468 483
 
469 484
     @staticmethod
470 485
     def setTestForceRPMS(listsPackages):
471 486
         constants.testForceRPMS=listsPackages
487
+
488
+    @staticmethod
489
+    def addMacro(macroName, macroValue):
490
+        constants.userDefinedMacros[macroName]=macroValue