Add an option to commit patches after they have been applied
This commit is contained in:
Родитель
f3e36be426
Коммит
ea761327d7
|
@ -20,7 +20,7 @@ def main():
|
|||
args = parse_args()
|
||||
|
||||
for folder in args.folders:
|
||||
error = apply_patches_for_dir(folder)
|
||||
error = apply_patches_for_dir(folder, args.commit)
|
||||
if error:
|
||||
sys.stderr.write(error + '\n')
|
||||
sys.stderr.flush()
|
||||
|
@ -29,14 +29,14 @@ def main():
|
|||
return 0
|
||||
|
||||
|
||||
def apply_patches_for_dir(directory):
|
||||
def apply_patches_for_dir(directory, commit):
|
||||
for root, dirs, files in os.walk(directory):
|
||||
config = PatchesConfig.from_directory(root)
|
||||
patches_list = config.get_patches_list()
|
||||
if patches_list is None:
|
||||
continue
|
||||
|
||||
(success, failed_patches) = patches_list.apply()
|
||||
(success, failed_patches) = patches_list.apply(commit=commit)
|
||||
if not success:
|
||||
patch_path = failed_patches[0].get_file_path()
|
||||
return '{0} failed to apply'.format(os.path.basename(patch_path))
|
||||
|
@ -45,6 +45,8 @@ def apply_patches_for_dir(directory):
|
|||
def parse_args():
|
||||
parser = argparse.ArgumentParser(description='Apply all required patches.')
|
||||
|
||||
parser.add_argument('--commit', default=False, action='store_true',
|
||||
help='Commit a patch after it has been applied')
|
||||
parser.add_argument('-t', '--target_arch',
|
||||
help='Target architecture')
|
||||
|
||||
|
|
|
@ -4,26 +4,60 @@ Everything in here should be project agnostic, shouldn't rely on project's struc
|
|||
and make any assumptions about the passed arguments or calls outcomes.
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from util import scoped_cwd
|
||||
|
||||
|
||||
def apply(repo, patch_path, reverse=False):
|
||||
def is_repo_root(path):
|
||||
path_exists = os.path.exists(path)
|
||||
if not path_exists:
|
||||
return False
|
||||
|
||||
git_folder_path = os.path.join(path, '.git')
|
||||
git_folder_exists = os.path.exists(git_folder_path)
|
||||
|
||||
return git_folder_exists
|
||||
|
||||
|
||||
def get_repo_root(path):
|
||||
"""Finds a closest ancestor folder which is a repo root."""
|
||||
norm_path = os.path.normpath(path)
|
||||
norm_path_exists = os.path.exists(norm_path)
|
||||
if not norm_path_exists:
|
||||
return None
|
||||
|
||||
if is_repo_root(norm_path):
|
||||
return norm_path
|
||||
|
||||
parent_path = os.path.dirname(norm_path)
|
||||
|
||||
# Check if we're in the root folder already.
|
||||
if parent_path == norm_path:
|
||||
return None
|
||||
|
||||
return get_repo_root(parent_path)
|
||||
|
||||
|
||||
def apply(repo, patch_path, directory=None, index=False, reverse=False):
|
||||
args = ['git', 'apply',
|
||||
'--directory', repo,
|
||||
'--ignore-space-change',
|
||||
'--ignore-whitespace',
|
||||
'--whitespace', 'fix'
|
||||
]
|
||||
if directory:
|
||||
args += ['--directory', directory]
|
||||
if index:
|
||||
args += ['--index']
|
||||
if reverse:
|
||||
args += ['--reverse']
|
||||
args += ['--', patch_path]
|
||||
|
||||
return_code = subprocess.call(args)
|
||||
applied_successfully = (return_code == 0)
|
||||
|
||||
return applied_successfully
|
||||
with scoped_cwd(repo):
|
||||
return_code = subprocess.call(args)
|
||||
applied_successfully = (return_code == 0)
|
||||
return applied_successfully
|
||||
|
||||
|
||||
def get_patch(repo, commit_hash):
|
||||
|
@ -42,3 +76,23 @@ def get_head_commit(repo):
|
|||
|
||||
with scoped_cwd(repo):
|
||||
return subprocess.check_output(args).strip()
|
||||
|
||||
|
||||
def commit(repo, author, message):
|
||||
""" Commit whatever in the index is now."""
|
||||
|
||||
# Let's setup committer info so git won't complain about it being missing.
|
||||
# TODO: Is there a better way to set committer's name and email?
|
||||
env = os.environ.copy()
|
||||
env['GIT_COMMITTER_NAME'] = 'Anonymous Committer'
|
||||
env['GIT_COMMITTER_EMAIL'] = 'anonymous@electronjs.org'
|
||||
|
||||
args = ['git', 'commit',
|
||||
'--author', author,
|
||||
'--message', message
|
||||
]
|
||||
|
||||
with scoped_cwd(repo):
|
||||
return_code = subprocess.call(args, env=env)
|
||||
committed_successfully = (return_code == 0)
|
||||
return committed_successfully
|
||||
|
|
|
@ -1,22 +1,46 @@
|
|||
import os
|
||||
import sys
|
||||
|
||||
import git
|
||||
from config import VENDOR_DIR
|
||||
|
||||
PYYAML_LIB_DIR = os.path.join(VENDOR_DIR, 'pyyaml', 'lib')
|
||||
sys.path.append(PYYAML_LIB_DIR)
|
||||
import yaml
|
||||
|
||||
from git import apply as git_apply
|
||||
|
||||
|
||||
class Patch:
|
||||
def __init__(self, file_path, repo_path):
|
||||
def __init__(self, file_path, repo_path, paths_prefix=None, author='Anonymous <anonymous@electronjs.org>', description=None):
|
||||
self.author = author
|
||||
self.description = description
|
||||
self.file_path = file_path
|
||||
self.paths_prefix = paths_prefix
|
||||
self.repo_path = repo_path
|
||||
|
||||
def apply(self, reverse=False):
|
||||
return git_apply(self.repo_path, self.file_path, reverse=reverse)
|
||||
def apply(self, reverse=False, commit=False):
|
||||
# Add the change to index only if we're going to commit it later.
|
||||
patch_applied = git.apply(self.repo_path, self.file_path, directory=self.paths_prefix, index=commit, reverse=reverse)
|
||||
|
||||
if not patch_applied:
|
||||
return False
|
||||
|
||||
if commit:
|
||||
message = self.__get_commit_message(reverse)
|
||||
patch_committed = git.commit(self.repo_path, author=self.author, message=message)
|
||||
return patch_committed
|
||||
|
||||
return True
|
||||
|
||||
def __get_commit_message(self, reverse):
|
||||
message = self.description
|
||||
|
||||
if message is None:
|
||||
message = os.path.basename(self.file_path)
|
||||
|
||||
if reverse:
|
||||
message = 'Revert: ' + message
|
||||
|
||||
return message
|
||||
|
||||
def reverse(self):
|
||||
return self.apply(reverse=True)
|
||||
|
@ -32,12 +56,12 @@ class PatchesList:
|
|||
def __len__(self):
|
||||
return len(self.patches)
|
||||
|
||||
def apply(self, reverse=False, stop_on_error=True):
|
||||
def apply(self, reverse=False, stop_on_error=True, commit=False):
|
||||
all_patches_applied = True
|
||||
failed_patches = []
|
||||
|
||||
for patch in self.patches:
|
||||
applied_successfully = patch.apply(reverse=reverse)
|
||||
applied_successfully = patch.apply(reverse=reverse, commit=commit)
|
||||
|
||||
if not applied_successfully:
|
||||
all_patches_applied = False
|
||||
|
@ -74,25 +98,44 @@ class PatchesConfig:
|
|||
|
||||
return contents
|
||||
|
||||
def __create_patch(self, raw_data, base_directory, repo_path):
|
||||
def __create_patch(self, raw_data, base_directory, repo_path, paths_prefix):
|
||||
author = raw_data['author']
|
||||
if author is None: # Shouldn't actually happen.
|
||||
author = 'Anonymous <anonymous@electronjs.org>'
|
||||
|
||||
relative_file_path = raw_data['file']
|
||||
absolute_file_path = os.path.join(base_directory, relative_file_path)
|
||||
|
||||
return Patch(absolute_file_path, repo_path)
|
||||
# Use a patch file path as a commit summary
|
||||
# and optional description as a commit body.
|
||||
description = relative_file_path
|
||||
if raw_data['description'] is not None:
|
||||
description += '\n\n' + raw_data['description']
|
||||
|
||||
return Patch(absolute_file_path, repo_path, paths_prefix=paths_prefix, author=author, description=description)
|
||||
|
||||
def get_patches_list(self):
|
||||
config_contents = self.__parse()
|
||||
if config_contents is None:
|
||||
return None
|
||||
|
||||
repo_path = config_contents['repo']
|
||||
if sys.platform == 'win32':
|
||||
repo_path = repo_path.replace('/', '\\')
|
||||
project_root = git.get_repo_root(self.path)
|
||||
assert(project_root)
|
||||
|
||||
relative_repo_path = os.path.normpath(config_contents['repo'])
|
||||
absolute_repo_path = os.path.join(project_root, relative_repo_path)
|
||||
|
||||
# If the 'repo' path is not really a git repository,
|
||||
# then use that path as a prefix for patched files.
|
||||
paths_prefix = None
|
||||
if not git.is_repo_root(absolute_repo_path):
|
||||
absolute_repo_path = project_root
|
||||
paths_prefix = relative_repo_path
|
||||
|
||||
patches_data = config_contents['patches']
|
||||
base_directory = os.path.dirname(self.path)
|
||||
|
||||
patches = [self.__create_patch(data, base_directory, repo_path) for data in patches_data]
|
||||
patches = [self.__create_patch(data, base_directory, absolute_repo_path, paths_prefix) for data in patches_data]
|
||||
patches_list = PatchesList(patches)
|
||||
|
||||
return patches_list
|
||||
|
|
|
@ -38,7 +38,7 @@ def main():
|
|||
|
||||
|
||||
def apply_patches(repo_path, patches_paths, force=False, reverse=False):
|
||||
patches = [Patch(patch_path, repo_path) for patch_path in patches_paths]
|
||||
patches = [Patch(os.path.abspath(patch_path), os.path.abspath(repo_path)) for patch_path in patches_paths]
|
||||
patches_list = PatchesList(patches)
|
||||
stop_on_error = not force
|
||||
return patches_list.apply(reverse=reverse, stop_on_error=stop_on_error)
|
||||
|
|
Загрузка…
Ссылка в новой задаче