diff --git a/common.json b/common.json index 8b3f5ced..56e5ef00 100644 --- a/common.json +++ b/common.json @@ -4,7 +4,7 @@ "Jsonnet files should not include this file directly but use ci/common.jsonnet instead." ], - "mx_version": "6.44.2", + "mx_version": "6.45.0", "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { diff --git a/mx.py b/mx.py index dc58272a..fe12b916 100755 --- a/mx.py +++ b/mx.py @@ -18783,7 +18783,7 @@ def alarm_handler(signum, frame): abort(1, killsig=signal.SIGINT) # The version must be updated for every PR (checked in CI) and the comment should reflect the PR's issue -version = VersionSpec("6.45.0") # multi-arch layout dirs +version = VersionSpec("6.45.1") # GR-48321 Fix JARDistribution exclude list not triggering rebuild _mx_start_datetime = datetime.utcnow() _last_timestamp = _mx_start_datetime diff --git a/mx_jardistribution.py b/mx_jardistribution.py index 7578761a..0316338e 100644 --- a/mx_jardistribution.py +++ b/mx_jardistribution.py @@ -210,7 +210,8 @@ def paths_to_clean(self): self.original_path() + _staging_dir_suffix, self.sourcesPath + _staging_dir_suffix, self._stripped_path(), - self.strip_mapping_file() + self.strip_mapping_file(), + self._config_save_file(), ] jdk = mx.get_jdk(tag='default') if jdk.javaCompliance >= '9': @@ -323,6 +324,9 @@ def make_archive(self, javac_daemon=None): latest_bin_archive = join(self.suite.get_output_root(False, False), "dists", os.path.basename(bin_archive.path)) _stage_file_impl(bin_archive.path, latest_bin_archive) + with mx.open(self._config_save_file(), 'w') as fp: + fp.write(self._config_as_json()) + self.notify_updated() compliance = self._compliance_for_build() if compliance is not None and compliance >= '9': @@ -330,12 +334,6 @@ def make_archive(self, javac_daemon=None): jmd = mx.make_java_module(self, jdk, stager.bin_archive, javac_daemon=javac_daemon) if jmd: setattr(self, '.javaModule', jmd) - mi_file = self._module_info_save_file() - with mx.open(mi_file, 'w') as fp: - fp.write(self._module_info_as_json()) - dependency_file = self._jmod_build_jdk_dependency_file() - with mx.open(dependency_file, 'w') as fp: - fp.write(jdk.home) if self.is_stripped(): self.strip_jar() @@ -570,26 +568,44 @@ def getArchivableResults(self, use_relpath=True, single=False): if self.is_stripped(): yield self.strip_mapping_file(), self.default_filename() + JARDistribution._strip_map_file_suffix - def _jmod_build_jdk_dependency_file(self): + def _config_save_file(self) -> str: """ - Gets the path to the file recording the JAVA_HOME of the JDK last used to - build the modular jar for this distribution. + Gets the path to the file saving :meth:`_config_as_json`. """ - return self.original_path() + '.jdk' + return self.original_path() + ".json" - def _module_info_save_file(self): + def _config_as_json(self) -> str: """ - Gets the path to the file saving `_module_info_as_json()`. + Creates a sorted json dump of attributes that trigger a rebuild when they're changed (see :meth:`needsUpdate`). """ - return self.original_path() + '.module-info' + config = {} + + def add_attribute(key, value): + """ + Adds an attribute to the config dict and makes sure no entry is + overwritten, because otherwise attributes are ignored when checking + for updated. + """ + assert key not in config, f"Duplicate value in distribution config: {key}" + config[key] = value + + # The `exclude` list can change the jar file contents and needs to trigger a rebuild + add_attribute("excludedLibs", list(map(str, self.excludedLibs))) + + compliance = self._compliance_for_build() + if compliance is not None and compliance >= '9': + if mx.get_java_module_info(self): + # Module info change triggers a rebuild. + for name in dir(self): + if name == 'moduleInfo' or name.startswith('moduleInfo:'): + add_attribute(name, getattr(self, name)) + + # The jmod file needs to be rebuilt if a different JDK was used previously + jdk = mx.get_jdk(compliance) + add_attribute("jdk", str(jdk.home)) - def _module_info_as_json(self): - """ - Gets the moduleInfo attribute(s) as sorted json. - """ import json - module_infos = {name:getattr(self, name) for name in dir(self) if name == 'moduleInfo' or name.startswith('moduleInfo:')} - return json.dumps(module_infos, sort_keys=True, indent=2) + return json.dumps(config, sort_keys=True, indent=2) def needsUpdate(self, newestInput): res = mx._needsUpdate(newestInput, self.path) @@ -619,31 +635,26 @@ def needsUpdate(self, newestInput): res = mx._needsUpdate(self.original_path(), pickle_path) if res: return res - jdk = mx.get_jdk(compliance) - # Rebuild if module info changed - mi_file = self._module_info_save_file() - if exists(mi_file): - module_info = self._module_info_as_json() - with mx.open(mi_file) as fp: - saved_module_info = fp.read() - if module_info != saved_module_info: - import difflib - mx.log(f'{self} module info changed:' + os.linesep + ''.join(difflib.unified_diff(saved_module_info.splitlines(1), module_info.splitlines(1)))) - return 'module-info changed' - - # Rebuild the jmod file if different JDK used previously - dependency_file = self._jmod_build_jdk_dependency_file() - if exists(dependency_file): - with mx.open(dependency_file) as fp: - last_build_jdk = fp.read() - if last_build_jdk != jdk.home: - return f'build JDK changed from {last_build_jdk} to {jdk.home}' try: with open(pickle_path, 'rb') as fp: pickle.load(fp) except ValueError as e: return f'Bad or incompatible module pickle: {e}' + + # Rebuild if the saved config file changed or doesn't exist + config_file = self._config_save_file() + if exists(config_file): + current_config = self._config_as_json() + with mx.open(config_file) as fp: + saved_config = fp.read() + if current_config != saved_config: + import difflib + mx.log(f'{self} distribution config changed:' + os.linesep + ''.join(difflib.unified_diff(saved_config.splitlines(True), current_config.splitlines(True)))) + return f'{config_file} changed' + else: + return f'{config_file} does not exist' + if self.is_stripped(): previous_strip_configs = [] dependency_file = self.strip_config_dependency_file()