4 # This file and its contents are supplied under the terms of the
5 # Common Development and Distribution License ("CDDL"), version 1.0.
6 # You may only use this file in accordance with the terms of version
9 # A full copy of the text of the CDDL should have accompanied this
10 # source. A copy of the CDDL is also available via the Internet at
11 # http://www.illumos.org/license/CDDL.
15 # Copyright 2021 Aurelien Larcher
24 from bass.component import Component
25 from bass.makefiles import Item
26 from bass.makefiles import Keywords
27 from bass.makefiles import Makefile as MK
30 #-----------------------------------------------------------------------------
31 # They should be called in-order to avoid unsatisfied assumptions.
32 def format_component(path, verbose):
41 #-----------------------------------------------------------------------------
42 # 000: Use WS_* variables instead $(WS_TOP)/*
43 # If $(WS_TOP)/make-rules is found in an include then replace with the
44 # variable $(WS_RULES). Do the same for other variables.
46 for i in iter(mk.includes):
47 r = re.match(r"^\$\(WS_TOP\)\/(.*)\/(.*).mk", i.value())
51 print("000: Fix include " + i.value())
52 i.set_value(os.path.join(MK.directory_variable(subdir), mkfile+".mk"))
53 mk.contents[i.line()] = i.include_line()
57 #-----------------------------------------------------------------------------
59 # If common.mk is not included then:
60 # 1. infer the build system and set the BUILD_STYLE.
61 # 2. set the BUILD_BITS from the existing targets.
62 # 3. erase default target and keep the custom ones.
63 # 4. fix known target typos
66 if mk.has_variable('BUILD_STYLE') or mk.has_mk_include('common'):
70 for i in iter(mk.includes):
71 r = re.match(r"^\$\(WS_MAKE_RULES\)/(.*).mk$", i.value())
73 build_style = r.group(1) if r.group(1) in kw.variables['BUILD_STYLE'] else None
74 if build_style is not None:
75 mk.set_variable('BUILD_STYLE', build_style)
77 if build_style is None:
78 raise ValueError("Variable BUILD_STYLE cannot be defined")
80 print("001: Setting build style to '" + build_style + "'")
81 build_style = mk.variable('BUILD_STYLE').value()
83 mk_bits = mk.run("print-value-MK_BITS")[0]
84 if mk_bits not in kw.variables["MK_BITS"]:
85 raise ValueError("Variable MK_BITS cannot be defined")
87 print("001: Setting make bits to '" + mk_bits + "'")
91 for t, u in iter(mk.targets.items()):
92 # We do not know how to handle target with defined steps yet
96 if t == 'test' and u.value() == MK.value('NO_TEST'):
97 print("001: Fix typo $(NO_TEST) -> $(NO_TESTS)")
98 u.set_value(MK.value('NO_TESTS'))
101 for v in kw.targets[t]:
102 v = MK.value(v.replace(MK.value("MK_BITS"), mk_bits))
103 # If the target dependency is one of the default values
106 w = MK.target_value(t, mk_bits)
109 print("001: Use default target '"+t+"'")
112 print("001: Define target '"+t+"': "+u.value())
116 # Some Python/Perl makefiles actually use NO_ARCH target with MK_BITS=32, or BITS was not set
117 if mk_bits == '32' or mk_bits == '64':
118 ok_bits = ( 'NO_ARCH', '64', '32_and_64', '64_and_32' )
120 if u.value() == MK.target_value(t, b):
123 elif b != new_mk_bits:
124 raise ValueError("001: Inconsistent target '"+t+"': "+u.value())
128 raise ValueError("001: Unknown target '"+t+"' bitness: "+u.value())
130 print("001: Changing make bits from "+mk_bits+" to '"+new_mk_bits+"'")
131 mk_bits = new_mk_bits
134 rem_includes = [ MK.makefile_path("prep"), MK.makefile_path("ips")]
136 include_shared_mk = None
137 include_common_mk = None
138 for i in iter(mk.includes):
139 if i.value() not in rem_includes:
140 if i.value() == MK.makefile_path(build_style):
141 i.set_value(MK.makefile_path("common"))
142 include_common_mk = i
143 elif re.match(r".*/shared-macros.mk$", i.value()):
144 include_shared_mk = i
145 new_includes.append(i)
147 rem_lines.add(i.line())
148 mk.includes = new_includes
149 if include_common_mk is None:
150 raise ValueError("Include directive of common.mk not found")
151 if include_shared_mk is None:
152 raise ValueError("Include directive of shared-macros.mk not found")
153 # Add lines to skip for default targets
154 for u in mk.targets.values():
156 rem_lines.add(u.line())
158 contents = mk.contents[0:include_shared_mk.line()]
160 contents.append(Keywords.assignment('BUILD_STYLE', build_style))
161 contents.append(Keywords.assignment('BUILD_BITS', mk_bits))
162 # Write metadata lines
163 for idx, line in enumerate(mk.contents[include_shared_mk.line():include_common_mk.line()]):
164 if (include_shared_mk.line() + idx) in rem_lines:
166 contents.append(line)
168 for t in ["build", "install", "test"]:
169 if t in new_targets.keys():
170 contents.append(Keywords.target_variable_assignment(t, new_targets[t].value()))
171 rem_lines.add(new_targets[t].line())
173 contents.append(include_common_mk.include_line())
174 # Write lines after common.mk
175 for idx, line in enumerate(mk.contents[include_common_mk.line()+1:]):
176 if (include_common_mk.line()+1+idx) in rem_lines:
178 contents.append(line)
182 #-----------------------------------------------------------------------------
183 # 002: Indent COMPONENT_ variables
185 for k,i in iter(mk.variables.items()):
186 if re.match("^COMPONENT_", k):
188 lines = i.variable_assignment(k)
189 for i in range(0, i.length()):
190 mk.contents[idx + i] = lines[i]
195 #-----------------------------------------------------------------------------
196 # U000: Update to default OpenSSL
197 # If openssl is a dependency and the openssl package version is not set
198 # 1. update the dependency to the next openssl X.Y
199 # 2. add macros USE_OPENSSLXY to the makefile
203 curr_macro = 'USE_OPENSSL'+curr_version.replace('.','')
204 next_macro = 'USE_OPENSSL'+next_version.replace('.','')
205 curr_openssl_pkg = 'library/security/openssl'
206 next_openssl_pkg = 'library/security/openssl-11'
207 reqs = mk.required_packages()
208 has_openssl_deps=False
209 for p in reqs.split():
210 if p == curr_openssl_pkg:
211 has_openssl_deps=True
212 if not has_openssl_deps:
214 # Check whether current version is enforced
215 for line in iter(mk.contents):
216 if re.match("^"+curr_macro+"[\s]*=[\s]*yes", line):
218 print("U000: update to next openssl")
220 for idx, line in enumerate(mk.contents):
221 if re.match(r"REQUIRED_PACKAGES(.*)"+curr_openssl_pkg+"[\s]*$", line):
222 mk.contents[idx] = line.replace(curr_openssl_pkg, next_openssl_pkg)
224 # Add macro before shared-macros
225 include_shared_macros_mk = mk.get_mk_include('shared-macros')
226 if not include_shared_macros_mk:
227 raise ValueError('include shared_macros.mk not found')
228 mk.set_variable(next_macro, 'yes', include_shared_macros_mk.line())
232 #-----------------------------------------------------------------------------
233 # Update component makefile for revision or version bump
234 def update_component(path, version, verbose):
235 format_component(path, verbose)
236 # Nothing to bump, just update the Makefile to current format
240 # Apply default update rules
242 # Check current version
243 if not mk.has_variable('COMPONENT_VERSION'):
244 raise ValueError('COMPONENT_VERSION not found')
245 newvers = str(version)
246 current = mk.variable('COMPONENT_VERSION').value()
247 version_has_changed = False
249 if newvers == '0' or newvers == current:
250 print("Bump COMPONENT_REVISION")
251 if mk.has_variable('COMPONENT_REVISION'):
253 component_revision = int(mk.variable('COMPONENT_REVISION').value())
255 print('COMPONENT_REVISION field malformed: {}'.format(component_revision))
257 mk.set_variable('COMPONENT_REVISION', str(component_revision+1))
259 # Add value set to 1 after COMPONENT_VERSION
260 mk.set_variable('COMPONENT_REVISION', str(1), line=mk.variable('COMPONENT_VERSION').line()+1)
261 # Update to given version and remove revision
263 if newvers == 'latest':
264 if mk.build_style() == 'setup.py':
265 print("Trying to get latest version from PyPI")
266 js = mk.get_pypi_data()
268 newvers = js['info']['version']
270 print("Unable to find version")
272 print("Bump COMPONENT_VERSION to " + newvers)
273 version_has_changed = True
274 mk.set_variable('COMPONENT_VERSION', newvers)
275 if mk.has_variable('COMPONENT_REVISION'):
276 mk.remove_variable('COMPONENT_REVISION')
280 if not version_has_changed:
283 # Try to update archive checksum
285 print("Trying to get checksum from PyPI")
286 js = mk.get_pypi_data()
288 verblock = js['releases'][newvers]
290 print("Unknown version '%s'" % newvers)
292 # Index 0 is for the pypi package and index 1 for the source archive
293 sha256 = verblock[1]['digests']['sha256']
294 print("Found: "+str(sha256))
295 mk.set_archive_hash(sha256)
301 parser = argparse.ArgumentParser()
302 parser.add_argument('--path', default='components',
303 help='Directory holding components')
304 parser.add_argument('--bump', nargs='?', default=None, const=0,
305 help='Bump component to given version')
306 parser.add_argument('-v', '--verbose', action='store_true',
307 default=False, help='Verbose output')
308 args = parser.parse_args()
312 verbose = args.verbose
314 update_component(path=path, version=version, verbose=verbose)
317 if __name__ == '__main__':