aboutsummaryrefslogtreecommitdiff
path: root/pre-upload.py
diff options
context:
space:
mode:
Diffstat (limited to 'pre-upload.py')
-rwxr-xr-xpre-upload.py116
1 files changed, 71 insertions, 45 deletions
diff --git a/pre-upload.py b/pre-upload.py
index 7eb11b8..0109133 100755
--- a/pre-upload.py
+++ b/pre-upload.py
@@ -94,7 +94,7 @@ class Output(object):
commit: commit hash.
commit_summary: commit summary.
"""
- status_line = '[%s %s] %s' % (self.COMMIT, commit[0:12], commit_summary)
+ status_line = f'[{self.COMMIT} {commit[0:12]}] {commit_summary}'
rh.terminal.print_status_line(status_line, print_newline=True)
self.hook_index = 1
@@ -106,8 +106,8 @@ class Output(object):
"""
self._curr_hook_name = hook_name
self.hook_start_time = datetime.datetime.now()
- status_line = '[%s %d/%d] %s' % (self.RUNNING, self.hook_index,
- self.num_hooks, hook_name)
+ status_line = (f'[{self.RUNNING} {self.hook_index}/{self.num_hooks}] '
+ f'{hook_name}')
self.hook_index += 1
rh.terminal.print_status_line(status_line)
@@ -115,11 +115,11 @@ class Output(object):
"""Finish processing any per-hook state."""
duration = datetime.datetime.now() - self.hook_start_time
if duration >= self._SLOW_HOOK_DURATION:
+ d = rh.utils.timedelta_str(duration)
self.hook_warning(
- 'This hook took %s to finish which is fairly slow for '
+ f'This hook took {d} to finish which is fairly slow for '
'developers.\nPlease consider moving the check to the '
- 'server/CI system instead.' %
- (rh.utils.timedelta_str(duration),))
+ 'server/CI system instead.')
def hook_error(self, error):
"""Print an error for a single hook.
@@ -135,7 +135,7 @@ class Output(object):
Args:
warning: warning string.
"""
- status_line = '[%s] %s' % (self.WARNING, self._curr_hook_name)
+ status_line = f'[{self.WARNING}] {self._curr_hook_name}'
rh.terminal.print_status_line(status_line, print_newline=True)
print(warning, file=sys.stderr)
@@ -146,19 +146,19 @@ class Output(object):
header: A unique identifier for the source of this error.
error: error string.
"""
- status_line = '[%s] %s' % (self.FAILED, header)
+ status_line = f'[{self.FAILED}] {header}'
rh.terminal.print_status_line(status_line, print_newline=True)
print(error, file=sys.stderr)
self.success = False
def finish(self):
"""Print summary for all the hooks."""
- status_line = '[%s] repohooks for %s %s in %s' % (
- self.PASSED if self.success else self.FAILED,
- self.project_name,
- 'passed' if self.success else 'failed',
- rh.utils.timedelta_str(datetime.datetime.now() - self.start_time))
- rh.terminal.print_status_line(status_line, print_newline=True)
+ header = self.PASSED if self.success else self.FAILED
+ status = 'passed' if self.success else 'failed'
+ d = rh.utils.timedelta_str(datetime.datetime.now() - self.start_time)
+ rh.terminal.print_status_line(
+ f'[{header}] repohooks for {self.project_name} {status} in {d}',
+ print_newline=True)
def _process_hook_results(results):
@@ -185,9 +185,9 @@ def _process_hook_results(results):
if result:
ret = ''
if result.files:
- ret += ' FILES: %s' % (result.files,)
+ ret += f' FILES: {result.files}'
lines = result.error.splitlines()
- ret += '\n'.join(' %s' % (x,) for x in lines)
+ ret += '\n'.join(f' {x}' for x in lines)
if result.is_warning():
has_warning = True
warning_ret += ret
@@ -199,17 +199,24 @@ def _process_hook_results(results):
warning_ret if has_warning else None)
-def _get_project_config():
+def _get_project_config(from_git=False):
"""Returns the configuration for a project.
+ Args:
+ from_git: If true, we are called from git directly and repo should not be
+ used.
Expects to be called from within the project root.
"""
- global_paths = (
- # Load the global config found in the manifest repo.
- os.path.join(rh.git.find_repo_root(), '.repo', 'manifests'),
- # Load the global config found in the root of the repo checkout.
- rh.git.find_repo_root(),
- )
+ if from_git:
+ global_paths = (rh.git.find_repo_root(),)
+ else:
+ global_paths = (
+ # Load the global config found in the manifest repo.
+ (os.path.join(rh.git.find_repo_root(), '.repo', 'manifests')),
+ # Load the global config found in the root of the repo checkout.
+ rh.git.find_repo_root(),
+ )
+
paths = (
# Load the config for this git repo.
'.',
@@ -233,28 +240,30 @@ def _attempt_fixes(fixup_func_list, commit_list):
# merge conflict resolution). Refuse to run the fix in those cases.
return
- prompt = ('An automatic fix can be attempted for the "%s" hook. '
- 'Do you want to run it?' % hook_name)
+ prompt = (f'An automatic fix can be attempted for the "{hook_name}" hook. '
+ 'Do you want to run it?')
if not rh.terminal.boolean_prompt(prompt):
return
result = fixup_func()
if result:
- print('Attempt to fix "%s" for commit "%s" failed: %s' %
- (hook_name, commit, result),
+ print(f'Attempt to fix "{hook_name}" for commit "{commit}" failed: '
+ f'{result}',
file=sys.stderr)
else:
print('Fix successfully applied. Amend the current commit before '
'attempting to upload again.\n', file=sys.stderr)
-def _run_project_hooks_in_cwd(project_name, proj_dir, output, commit_list=None):
+def _run_project_hooks_in_cwd(project_name, proj_dir, output, from_git=False, commit_list=None):
"""Run the project-specific hooks in the cwd.
Args:
project_name: The name of this project.
proj_dir: The directory for this project (for passing on in metadata).
output: Helper for summarizing output/errors to the user.
+ from_git: If true, we are called from git directly and repo should not be
+ used.
commit_list: A list of commits to run hooks against. If None or empty
list then we'll automatically get the list of commits that would be
uploaded.
@@ -263,7 +272,7 @@ def _run_project_hooks_in_cwd(project_name, proj_dir, output, commit_list=None):
False if any errors were found, else True.
"""
try:
- config = _get_project_config()
+ config = _get_project_config(from_git)
except rh.config.ValidationError as e:
output.error('Loading config files', str(e))
return False
@@ -281,8 +290,7 @@ def _run_project_hooks_in_cwd(project_name, proj_dir, output, commit_list=None):
upstream_branch = rh.git.get_upstream_branch()
except rh.utils.CalledProcessError as e:
output.error('Upstream remote/tracking branch lookup',
- '%s\nDid you run repo start? Is your HEAD detached?' %
- (e,))
+ f'{e}\nDid you run repo start? Is your HEAD detached?')
return False
project = rh.Project(name=project_name, dir=proj_dir, remote=remote)
@@ -337,13 +345,15 @@ def _run_project_hooks_in_cwd(project_name, proj_dir, output, commit_list=None):
return ret
-def _run_project_hooks(project_name, proj_dir=None, commit_list=None):
+def _run_project_hooks(project_name, proj_dir=None, from_git=False, commit_list=None):
"""Run the project-specific hooks in |proj_dir|.
Args:
project_name: The name of project to run hooks for.
proj_dir: If non-None, this is the directory the project is in. If None,
we'll ask repo.
+ from_git: If true, we are called from git directly and repo should not be
+ used.
commit_list: A list of commits to run hooks against. If None or empty
list then we'll automatically get the list of commits that would be
uploaded.
@@ -358,11 +368,11 @@ def _run_project_hooks(project_name, proj_dir=None, commit_list=None):
result = rh.utils.run(cmd, capture_output=True)
proj_dirs = result.stdout.split()
if not proj_dirs:
- print('%s cannot be found.' % project_name, file=sys.stderr)
+ print(f'{project_name} cannot be found.', file=sys.stderr)
print('Please specify a valid project.', file=sys.stderr)
return False
if len(proj_dirs) > 1:
- print('%s is associated with multiple directories.' % project_name,
+ print(f'{project_name} is associated with multiple directories.',
file=sys.stderr)
print('Please specify a directory to help disambiguate.',
file=sys.stderr)
@@ -374,6 +384,7 @@ def _run_project_hooks(project_name, proj_dir=None, commit_list=None):
# Hooks assume they are run from the root of the project.
os.chdir(proj_dir)
return _run_project_hooks_in_cwd(project_name, proj_dir, output,
+ from_git=from_git,
commit_list=commit_list)
finally:
output.finish()
@@ -409,22 +420,35 @@ def main(project_list, worktree_list=None, **_kwargs):
if found_error:
color = rh.terminal.Color()
- print('%s: Preupload failed due to above error(s).\n'
- 'For more info, please see:\n%s' %
- (color.color(color.RED, 'FATAL'), REPOHOOKS_URL),
+ print(color.color(color.RED, 'FATAL') +
+ ': Preupload failed due to above error(s).\n'
+ f'For more info, please see:\n{REPOHOOKS_URL}',
file=sys.stderr)
sys.exit(1)
-def _identify_project(path):
+def _identify_project(path, from_git=False):
"""Identify the repo project associated with the given path.
Returns:
A string indicating what project is associated with the path passed in or
a blank string upon failure.
"""
- cmd = ['repo', 'forall', '.', '-c', 'echo ${REPO_PROJECT}']
- return rh.utils.run(cmd, capture_output=True, cwd=path).stdout.strip()
+ if from_git:
+ cmd = ['git', 'rev-parse', '--show-toplevel']
+ project_path = rh.utils.run(cmd, capture_output=True).stdout.strip()
+ cmd = ['git', 'rev-parse', '--show-superproject-working-tree']
+ superproject_path = rh.utils.run(cmd, capture_output=True).stdout.strip()
+ module_path = project_path[len(superproject_path) + 1:]
+ cmd = ['git', 'config', '-f', '.gitmodules',
+ '--name-only', '--get-regexp', '^submodule\..*\.path$',
+ f"^{module_path}$"]
+ module_name = rh.utils.run(cmd, cwd=superproject_path,
+ capture_output=True).stdout.strip()
+ return module_name[len('submodule.'):-len(".path")]
+ else:
+ cmd = ['repo', 'forall', '.', '-c', 'echo ${REPO_PROJECT}']
+ return rh.utils.run(cmd, capture_output=True, cwd=path).stdout.strip()
def direct_main(argv):
@@ -440,6 +464,8 @@ def direct_main(argv):
BadInvocation: On some types of invocation errors.
"""
parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('--git', action='store_true',
+ help='This hook is called from git instead of repo')
parser.add_argument('--dir', default=None,
help='The directory that the project lives in. If not '
'specified, use the git project root based on the cwd.')
@@ -461,18 +487,18 @@ def direct_main(argv):
parser.error('The current directory is not part of a git project.')
opts.dir = os.path.dirname(os.path.abspath(git_dir))
elif not os.path.isdir(opts.dir):
- parser.error('Invalid dir: %s' % opts.dir)
+ parser.error(f'Invalid dir: {opts.dir}')
elif not rh.git.is_git_repository(opts.dir):
- parser.error('Not a git repository: %s' % opts.dir)
+ parser.error(f'Not a git repository: {opts.dir}')
# Identify the project if it wasn't specified; this _requires_ the repo
# tool to be installed and for the project to be part of a repo checkout.
if not opts.project:
- opts.project = _identify_project(opts.dir)
+ opts.project = _identify_project(opts.dir, opts.git)
if not opts.project:
- parser.error("Repo couldn't identify the project of %s" % opts.dir)
+ parser.error(f"Couldn't identify the project of {opts.dir}")
- if _run_project_hooks(opts.project, proj_dir=opts.dir,
+ if _run_project_hooks(opts.project, proj_dir=opts.dir, from_git=opts.git,
commit_list=opts.commits):
return 0
return 1