mirror of
https://github.com/morgan9e/helium
synced 2026-04-14 00:14:20 +09:00
devutils: Add update_platform_patches.py
This commit is contained in:
178
devutils/update_platform_patches.py
Executable file
178
devutils/update_platform_patches.py
Executable file
@@ -0,0 +1,178 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# 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 file.
|
||||
"""
|
||||
Utility to ease the updating of platform patches against ungoogled-chromium's patches
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent / 'utils'))
|
||||
from _common import ENCODING, get_logger
|
||||
from patches import merge_patches
|
||||
sys.path.pop(0)
|
||||
|
||||
_SERIES = 'series'
|
||||
_SERIES_ORIG = 'series.orig'
|
||||
_SERIES_PREPEND = 'series.prepend'
|
||||
_SERIES_MERGED = 'series.merged'
|
||||
|
||||
|
||||
def merge_platform_patches(platform_patches_dir, prepend_patches_dir):
|
||||
'''
|
||||
Prepends prepend_patches_dir into platform_patches_dir
|
||||
|
||||
Returns True if successful, False otherwise
|
||||
'''
|
||||
if not (platform_patches_dir / _SERIES).exists():
|
||||
get_logger().error('Unable to find platform series file: %s',
|
||||
platform_patches_dir / _SERIES)
|
||||
return False
|
||||
|
||||
# Make series.orig file
|
||||
shutil.copyfile(str(platform_patches_dir / _SERIES), str(platform_patches_dir / _SERIES_ORIG))
|
||||
|
||||
# Make series.prepend
|
||||
shutil.copyfile(str(prepend_patches_dir / _SERIES), str(platform_patches_dir / _SERIES_PREPEND))
|
||||
|
||||
# Merge patches
|
||||
merge_patches([prepend_patches_dir], platform_patches_dir, prepend=True)
|
||||
(platform_patches_dir / _SERIES).replace(platform_patches_dir / _SERIES_MERGED)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def _dir_empty(path):
|
||||
'''
|
||||
Returns True if the directory exists and is empty; False otherwise
|
||||
'''
|
||||
try:
|
||||
next(os.scandir(str(path)))
|
||||
except StopIteration:
|
||||
return True
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
return False
|
||||
|
||||
|
||||
def _remove_files_with_dirs(root_dir, sorted_file_iter):
|
||||
'''
|
||||
Deletes a list of sorted files relative to root_dir, removing empty directories along the way
|
||||
'''
|
||||
past_parent = None
|
||||
for partial_path in sorted_file_iter:
|
||||
complete_path = Path(root_dir, partial_path)
|
||||
try:
|
||||
complete_path.unlink()
|
||||
except FileNotFoundError:
|
||||
get_logger().warning('Could not remove prepended patch: %s', complete_path)
|
||||
if past_parent != complete_path.parent:
|
||||
while past_parent and _dir_empty(past_parent):
|
||||
past_parent.rmdir()
|
||||
past_parent = past_parent.parent
|
||||
past_parent = complete_path.parent
|
||||
# Handle last path's directory
|
||||
while _dir_empty(complete_path.parent):
|
||||
complete_path.parent.rmdir()
|
||||
complete_path = complete_path.parent
|
||||
|
||||
|
||||
def unmerge_platform_patches(platform_patches_dir):
|
||||
'''
|
||||
Undo merge_platform_patches(), adding any new patches from series.merged as necessary
|
||||
|
||||
Returns True if successful, False otherwise
|
||||
'''
|
||||
if not (platform_patches_dir / _SERIES_PREPEND).exists():
|
||||
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()))
|
||||
|
||||
# Remove prepended files with directories
|
||||
_remove_files_with_dirs(platform_patches_dir, sorted(prepend_series))
|
||||
|
||||
# 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 -> number of following blank lines
|
||||
path_spaces = dict()
|
||||
previous_path = None
|
||||
for partial_path in orig_series:
|
||||
if partial_path:
|
||||
previous_path = partial_path
|
||||
elif previous_path in path_spaces:
|
||||
path_spaces[previous_path] += 1
|
||||
else:
|
||||
path_spaces[previous_path] = 1
|
||||
|
||||
# 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):
|
||||
if new_series[series_index] in path_spaces:
|
||||
new_series.insert(series_index + 1, '\n' * (path_spaces[new_series[series_index]] - 1))
|
||||
series_index += 1
|
||||
series_index += 1
|
||||
|
||||
# Write series file
|
||||
with (platform_patches_dir / _SERIES).open('w', encoding=ENCODING) as series_file:
|
||||
series_file.write('\n'.join(new_series))
|
||||
series_file.write('\n')
|
||||
|
||||
# All other operations are successful; remove merging intermediates
|
||||
(platform_patches_dir / _SERIES_MERGED).unlink()
|
||||
(platform_patches_dir / _SERIES_ORIG).unlink()
|
||||
(platform_patches_dir / _SERIES_PREPEND).unlink()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
"""CLI Entrypoint"""
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
'command',
|
||||
choices=('merge', 'unmerge'),
|
||||
help='Merge or unmerge ungoogled-chromium patches with platform patches')
|
||||
parser.add_argument(
|
||||
'platform_patches',
|
||||
type=Path,
|
||||
help='The path to the platform patches in GNU Quilt format to merge into')
|
||||
args = parser.parse_args()
|
||||
|
||||
repo_dir = Path(__file__).resolve().parent.parent
|
||||
|
||||
success = False
|
||||
if args.command == 'merge':
|
||||
success = merge_platform_patches(args.platform_patches, repo_dir / 'patches')
|
||||
elif args.command == 'unmerge':
|
||||
success = unmerge_platform_patches(args.platform_patches)
|
||||
else:
|
||||
raise NotImplementedError(args.command)
|
||||
|
||||
if success:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
exit(main())
|
||||
Reference in New Issue
Block a user