From a50bc6fddd4c8d5f32a4f94d5e1f75f799651845 Mon Sep 17 00:00:00 2001 From: jj Date: Sat, 2 May 2026 08:50:40 +0000 Subject: [PATCH] devutils/platform_patches: preserve generic series changes on unmerge (#1550) now if we add some patch to the middle of generic series, it should be moved to generic repo instead of staying at the top of the series file --- devutils/update_platform_patches.py | 107 +++++++++++++++++++--------- 1 file changed, 72 insertions(+), 35 deletions(-) diff --git a/devutils/update_platform_patches.py b/devutils/update_platform_patches.py index eecd98d0..9f52a128 100755 --- a/devutils/update_platform_patches.py +++ b/devutils/update_platform_patches.py @@ -1,6 +1,10 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- +# Copyright (c) 2026 The Helium Authors +# You can use, redistribute, and/or modify this source code under +# the terms of the GPL-3.0 license that can be found in the LICENSE file. + # Copyright (c) 2019 The ungoogled-chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE.ungoogled_chromium file. @@ -73,6 +77,7 @@ def _rename_files_with_dirs(root_dir, source_dir, sorted_file_iter): complete_path = Path(root_dir, partial_path) complete_source_path = Path(source_dir, partial_path) try: + complete_source_path.parent.mkdir(parents=True, exist_ok=True) complete_path.rename(complete_source_path) except FileNotFoundError: get_logger().warning('Could not move prepended patch: %s', complete_path) @@ -87,6 +92,44 @@ def _rename_files_with_dirs(root_dir, source_dir, sorted_file_iter): complete_path = complete_path.parent +def _series_path(series_line): + return series_line.split(' #', maxsplit=1)[0] + + +def _parse_series_metadata(series_lines): + paths = set() + # patch path -> list of lines after patch path and before next patch path + path_comments = {} + # patch path -> inline comment for patch + path_inline_comments = {} + previous_path = None + for partial_path in series_lines: + if not partial_path or partial_path.startswith('#'): + if previous_path not in path_comments: + path_comments[previous_path] = [] + path_comments[previous_path].append(partial_path) + else: + previous_path = _series_path(partial_path) + paths.add(previous_path) + path_parts = partial_path.split(' #', maxsplit=1) + if len(path_parts) == 2: + path_inline_comments[previous_path] = path_parts[1] + return paths, path_comments, path_inline_comments + + +def _restore_series_metadata(series, path_comments, path_inline_comments): + series_index = 0 + while series_index < len(series): + current_path = series[series_index] + clean_path = _series_path(current_path) + if clean_path in path_inline_comments: + series[series_index] = clean_path + ' #' + path_inline_comments[clean_path] + if clean_path in path_comments: + series.insert(series_index + 1, '\n'.join(path_comments[clean_path])) + series_index += 1 + series_index += 1 + + def unmerge_platform_patches(platform_patches_dir, prepend_patches_dir): ''' Undo merge_platform_patches(), adding any new patches from series.merged as necessary @@ -97,54 +140,48 @@ def unmerge_platform_patches(platform_patches_dir, prepend_patches_dir): get_logger().error('Unable to find series.prepend at: %s', platform_patches_dir / _SERIES_PREPEND) return False - prepend_series = set( - filter(len, - (platform_patches_dir / _SERIES_PREPEND).read_text(encoding=ENCODING).splitlines())) - - # Move prepended files back to original location, preserving changes - _rename_files_with_dirs(platform_patches_dir, prepend_patches_dir, sorted(prepend_series)) + prepend_series, prepend_path_comments, prepend_path_inline_comments = _parse_series_metadata( + (platform_patches_dir / _SERIES_PREPEND).read_text(encoding=ENCODING).splitlines()) # Determine positions of blank spaces in series.orig if not (platform_patches_dir / _SERIES_ORIG).exists(): get_logger().error('Unable to find series.orig at: %s', platform_patches_dir / _SERIES_ORIG) return False - orig_series = (platform_patches_dir / _SERIES_ORIG).read_text(encoding=ENCODING).splitlines() - # patch path -> list of lines after patch path and before next patch path - path_comments = {} - # patch path -> inline comment for patch - path_inline_comments = {} - previous_path = None - for partial_path in orig_series: - if not partial_path or partial_path.startswith('#'): - if partial_path not in path_comments: - path_comments[previous_path] = [] - path_comments[previous_path].append(partial_path) - else: - path_parts = partial_path.split(' #', maxsplit=1) - previous_path = path_parts[0] - if len(path_parts) == 2: - path_inline_comments[path_parts[0]] = path_parts[1] + orig_series_paths, path_comments, path_inline_comments = _parse_series_metadata( + (platform_patches_dir / _SERIES_ORIG).read_text(encoding=ENCODING).splitlines()) # Apply changes on series.merged into a modified version of series.orig if not (platform_patches_dir / _SERIES_MERGED).exists(): get_logger().error('Unable to find series.merged at: %s', platform_patches_dir / _SERIES_MERGED) return False - new_series = filter(len, (platform_patches_dir / - _SERIES_MERGED).read_text(encoding=ENCODING).splitlines()) - new_series = filter((lambda x: x not in prepend_series), new_series) - new_series = list(new_series) - series_index = 0 - while series_index < len(new_series): - current_path = new_series[series_index] - if current_path in path_inline_comments: - new_series[series_index] = current_path + ' #' + path_inline_comments[current_path] - if current_path in path_comments: - new_series.insert(series_index + 1, '\n'.join(path_comments[current_path])) - series_index += 1 - series_index += 1 + merged_series = filter(len, (platform_patches_dir / + _SERIES_MERGED).read_text(encoding=ENCODING).splitlines()) + generic_series = [] + new_series = [] + in_platform_series = False + for current_path in merged_series: + clean_path = _series_path(current_path) + if clean_path in orig_series_paths: + in_platform_series = True + if clean_path in prepend_series or not in_platform_series: + generic_series.append(current_path) + else: + new_series.append(current_path) + + # Move prepended files back to original location, preserving changes + # including any new patches added before the platform patch block. + _rename_files_with_dirs( + platform_patches_dir, prepend_patches_dir, + sorted(prepend_series.union(_series_path(patch_path) for patch_path in generic_series))) + + _restore_series_metadata(generic_series, prepend_path_comments, prepend_path_inline_comments) + _restore_series_metadata(new_series, path_comments, path_inline_comments) # Write series file + with (prepend_patches_dir / _SERIES).open('w', encoding=ENCODING) as series_file: + series_file.write('\n'.join(generic_series)) + series_file.write('\n') with (platform_patches_dir / _SERIES).open('w', encoding=ENCODING) as series_file: series_file.write('\n'.join(new_series)) series_file.write('\n')