From e70fdbd7e49327d4db24e7b2208da87278070d73 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 7 Apr 2025 22:51:43 +1200 Subject: patman: Untangle settings from gitutil The gitutil module is supposed to be independent from patman but one piece was missed in the series which separated them. Move the settings setup out of gitutil Signed-off-by: Simon Glass --- tools/u_boot_pylib/gitutil.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'tools/u_boot_pylib/gitutil.py') diff --git a/tools/u_boot_pylib/gitutil.py b/tools/u_boot_pylib/gitutil.py index 0376bece3e6..8935b6cc847 100644 --- a/tools/u_boot_pylib/gitutil.py +++ b/tools/u_boot_pylib/gitutil.py @@ -693,9 +693,6 @@ def setup(): # Check for a git alias file also global USE_NO_DECORATE - alias_fname = get_alias_file() - if alias_fname: - settings.ReadGitAliases(alias_fname) cmd = log_cmd(None, count=0) USE_NO_DECORATE = (command.run_one(*cmd, raise_on_error=False) .return_code == 0) -- cgit v1.2.3 From 7dc55435b2e869e26ab28926b92a7dc6620e2108 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 7 Apr 2025 22:51:44 +1200 Subject: patman: Pass the alias dict into gitutil.build_email_list() Rather than accessing the settings module in this function, require the alias dict to be passed in. Signed-off-by: Simon Glass --- tools/u_boot_pylib/gitutil.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'tools/u_boot_pylib/gitutil.py') diff --git a/tools/u_boot_pylib/gitutil.py b/tools/u_boot_pylib/gitutil.py index 8935b6cc847..7c9d0deecbb 100644 --- a/tools/u_boot_pylib/gitutil.py +++ b/tools/u_boot_pylib/gitutil.py @@ -361,7 +361,7 @@ def create_patches(branch, start, count, ignore_binary, series, signoff=True): return None, files -def build_email_list(in_list, tag=None, alias=None, warn_on_error=True): +def build_email_list(in_list, alias, tag=None, warn_on_error=True): """Build a list of email addresses based on an input list. Takes a list of email addresses and aliases, and turns this into a list @@ -373,10 +373,10 @@ def build_email_list(in_list, tag=None, alias=None, warn_on_error=True): Args: in_list (list of str): List of aliases/email addresses - tag (str): Text to put before each address alias (dict): Alias dictionary: key: alias value: list of aliases or email addresses + tag (str): Text to put before each address warn_on_error (bool): True to raise an error when an alias fails to match, False to just print a message. @@ -389,12 +389,12 @@ def build_email_list(in_list, tag=None, alias=None, warn_on_error=True): >>> alias['mary'] = ['Mary Poppins '] >>> alias['boys'] = ['fred', ' john'] >>> alias['all'] = ['fred ', 'john', ' mary '] - >>> build_email_list(['john', 'mary'], None, alias) + >>> build_email_list(['john', 'mary'], alias, None) ['j.bloggs@napier.co.nz', 'Mary Poppins '] - >>> build_email_list(['john', 'mary'], '--to', alias) + >>> build_email_list(['john', 'mary'], alias, '--to') ['--to "j.bloggs@napier.co.nz"', \ '--to "Mary Poppins "'] - >>> build_email_list(['john', 'mary'], 'Cc', alias) + >>> build_email_list(['john', 'mary'], alias, 'Cc') ['Cc j.bloggs@napier.co.nz', 'Cc Mary Poppins '] """ quote = '"' if tag and tag[0] == '-' else '' @@ -498,7 +498,7 @@ send --cc-cmd cc-fname" cover p1 p2' # Restore argv[0] since we clobbered it. >>> sys.argv[0] = _old_argv0 """ - to = build_email_list(series.get('to'), '--to', alias, warn_on_error) + to = build_email_list(series.get('to'), settings.alias, '--to', warn_on_error) if not to: git_config_to = command.output('git', 'config', 'sendemail.to', raise_on_error=False) @@ -510,10 +510,10 @@ send --cc-cmd cc-fname" cover p1 p2' "git config sendemail.to u-boot@lists.denx.de") return None cc = build_email_list(list(set(series.get('cc')) - set(series.get('to'))), - '--cc', alias, warn_on_error) + settings.alias, '--cc', warn_on_error) if self_only: - to = build_email_list([os.getenv('USER')], '--to', - alias, warn_on_error) + to = build_email_list([os.getenv('USER')], '--to', settings.alias, + warn_on_error) cc = [] cmd = ['git', 'send-email', '--annotate'] if smtp_server: -- cgit v1.2.3 From e10201aa8ccb1fb681cafab4225399f4fdb8497d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 7 Apr 2025 22:51:45 +1200 Subject: patman: Pass the alias dict into gitutil.email_patches() Rather than accessing the settings module in this function, require the alias dict to be passed in. Signed-off-by: Simon Glass --- tools/u_boot_pylib/gitutil.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'tools/u_boot_pylib/gitutil.py') diff --git a/tools/u_boot_pylib/gitutil.py b/tools/u_boot_pylib/gitutil.py index 7c9d0deecbb..7d3a0b68c53 100644 --- a/tools/u_boot_pylib/gitutil.py +++ b/tools/u_boot_pylib/gitutil.py @@ -5,7 +5,6 @@ import os import sys -from patman import settings from u_boot_pylib import command from u_boot_pylib import terminal @@ -437,7 +436,7 @@ def check_suppress_cc_config(): def email_patches(series, cover_fname, args, dry_run, warn_on_error, cc_fname, - self_only=False, alias=None, in_reply_to=None, thread=False, + alias, self_only=False, in_reply_to=None, thread=False, smtp_server=None): """Email a patch series. @@ -449,10 +448,10 @@ def email_patches(series, cover_fname, args, dry_run, warn_on_error, cc_fname, warn_on_error (bool): True to print a warning when an alias fails to match, False to ignore it. cc_fname (str): Filename of Cc file for per-commit Cc - self_only (bool): True to just email to yourself as a test - alias (dict or None): Alias dictionary: (None to use settings default) + alias (dict): Alias dictionary: key: alias value: list of aliases or email addresses + self_only (bool): True to just email to yourself as a test in_reply_to (str or None): If set we'll pass this to git as --in-reply-to - should be a message ID that this is in reply to. thread (bool): True to add --thread to git send-email (make @@ -498,7 +497,7 @@ send --cc-cmd cc-fname" cover p1 p2' # Restore argv[0] since we clobbered it. >>> sys.argv[0] = _old_argv0 """ - to = build_email_list(series.get('to'), settings.alias, '--to', warn_on_error) + to = build_email_list(series.get('to'), alias, '--to', warn_on_error) if not to: git_config_to = command.output('git', 'config', 'sendemail.to', raise_on_error=False) @@ -510,9 +509,9 @@ send --cc-cmd cc-fname" cover p1 p2' "git config sendemail.to u-boot@lists.denx.de") return None cc = build_email_list(list(set(series.get('cc')) - set(series.get('to'))), - settings.alias, '--cc', warn_on_error) + alias, '--cc', warn_on_error) if self_only: - to = build_email_list([os.getenv('USER')], '--to', settings.alias, + to = build_email_list([os.getenv('USER')], '--to', alias, warn_on_error) cc = [] cmd = ['git', 'send-email', '--annotate'] @@ -535,14 +534,14 @@ send --cc-cmd cc-fname" cover p1 p2' return cmdstr -def lookup_email(lookup_name, alias=None, warn_on_error=True, level=0): +def lookup_email(lookup_name, alias, warn_on_error=True, level=0): """If an email address is an alias, look it up and return the full name TODO: Why not just use git's own alias feature? Args: lookup_name (str): Alias or email address to look up - alias (dict or None): Alias dictionary: (None to use settings default) + alias (dict): Alias dictionary key: alias value: list of aliases or email addresses warn_on_error (bool): True to print a warning when an alias fails to @@ -589,8 +588,6 @@ def lookup_email(lookup_name, alias=None, warn_on_error=True, level=0): Recursive email alias at 'mary' ['j.bloggs@napier.co.nz', 'm.poppins@cloud.net'] """ - if not alias: - alias = settings.alias lookup_name = lookup_name.strip() if '@' in lookup_name: # Perhaps a real email address return [lookup_name] -- cgit v1.2.3 From 0664a956e674027a1383c8c114377dcdf5b86e41 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 8 May 2025 04:38:30 +0200 Subject: u_boot_pylib: Tidy up quoting of cc and to The current approach to calling 'git send-email' puts double quotes around each email address to ensure that it will pass the shell correctly. This is a bit cumbersome and requires using a shell to sort it all out. Drop the quotes and use command.run() instead, to simplify things. This will also make it possible to (later) set the current directory. Signed-off-by: Simon Glass --- tools/u_boot_pylib/gitutil.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'tools/u_boot_pylib/gitutil.py') diff --git a/tools/u_boot_pylib/gitutil.py b/tools/u_boot_pylib/gitutil.py index 7d3a0b68c53..e5a466c8cc6 100644 --- a/tools/u_boot_pylib/gitutil.py +++ b/tools/u_boot_pylib/gitutil.py @@ -396,7 +396,6 @@ def build_email_list(in_list, alias, tag=None, warn_on_error=True): >>> build_email_list(['john', 'mary'], alias, 'Cc') ['Cc j.bloggs@napier.co.nz', 'Cc Mary Poppins '] """ - quote = '"' if tag and tag[0] == '-' else '' raw = [] for item in in_list: raw += lookup_email(item, alias, warn_on_error=warn_on_error) @@ -405,7 +404,7 @@ def build_email_list(in_list, alias, tag=None, warn_on_error=True): if item not in result: result.append(item) if tag: - return [f'{tag} {quote}{email}{quote}' for email in result] + return [x for email in result for x in (tag, email)] return result @@ -524,13 +523,14 @@ send --cc-cmd cc-fname" cover p1 p2' cmd += to cmd += cc - cmd += ['--cc-cmd', f'"{sys.argv[0]} send --cc-cmd {cc_fname}"'] + cmd += ['--cc-cmd', f'{sys.argv[0]} send --cc-cmd {cc_fname}'] if cover_fname: cmd.append(cover_fname) cmd += args - cmdstr = ' '.join(cmd) if not dry_run: - os.system(cmdstr) + command.run(*cmd, capture=False, capture_stderr=False) + cmdstr = ' '.join([f'"{x}"' if ' ' in x and not '"' in x else x + for x in cmd]) return cmdstr -- cgit v1.2.3 From c885917c712b9f9c8a6016411ac44d148dea7854 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 8 May 2025 04:22:18 +0200 Subject: u_boot_pylib: Provide directories to gitutil functions For testing it is useful to be able to set the current directory used for git operations, as well as the git-repo directory. Update some of the functions to support this. Signed-off-by: Simon Glass --- tools/u_boot_pylib/gitutil.py | 49 ++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 14 deletions(-) (limited to 'tools/u_boot_pylib/gitutil.py') diff --git a/tools/u_boot_pylib/gitutil.py b/tools/u_boot_pylib/gitutil.py index e5a466c8cc6..f89576ef3b9 100644 --- a/tools/u_boot_pylib/gitutil.py +++ b/tools/u_boot_pylib/gitutil.py @@ -47,7 +47,7 @@ def log_cmd(commit_range, git_dir=None, oneline=False, reverse=False, return cmd -def count_commits_to_branch(branch): +def count_commits_to_branch(branch, git_dir=None, end=None): """Returns number of commits between HEAD and the tracking branch. This looks back to the tracking branch and works out the number of commits @@ -55,16 +55,22 @@ def count_commits_to_branch(branch): Args: branch (str or None): Branch to count from (None for current branch) + git_dir (str): Path to git repository (None to use default) + end (str): End commit to stop before Return: Number of patches that exist on top of the branch """ - if branch: - us, _ = get_upstream('.git', branch) + if end: + rev_range = f'{end}..{branch}' + elif branch: + us, msg = get_upstream(git_dir or '.git', branch) + if not us: + raise ValueError(msg) rev_range = f'{us}..{branch}' else: rev_range = '@{upstream}..' - cmd = log_cmd(rev_range, oneline=True) + cmd = log_cmd(rev_range, git_dir=git_dir, oneline=True) result = command.run_one(*cmd, capture=True, capture_stderr=True, oneline=True, raise_on_error=False) if result.return_code: @@ -321,7 +327,8 @@ def prune_worktrees(git_dir): raise OSError(f'git worktree prune: {result.stderr}') -def create_patches(branch, start, count, ignore_binary, series, signoff=True): +def create_patches(branch, start, count, ignore_binary, series, signoff=True, + git_dir=None, cwd=None): """Create a series of patches from the top of the current branch. The patch files are written to the current directory using @@ -334,11 +341,16 @@ def create_patches(branch, start, count, ignore_binary, series, signoff=True): ignore_binary (bool): Don't generate patches for binary files series (Series): Series object for this series (set of patches) signoff (bool): True to add signoff lines automatically + git_dir (str): Path to git repository (None to use default) + cwd (str): Path to use for git operations Return: Filename of cover letter (None if none) List of filenames of patch files """ - cmd = ['git', 'format-patch', '-M'] + cmd = ['git'] + if git_dir: + cmd += ['--git-dir', git_dir] + cmd += ['format-patch', '-M'] if signoff: cmd.append('--signoff') if ignore_binary: @@ -351,7 +363,7 @@ def create_patches(branch, start, count, ignore_binary, series, signoff=True): brname = branch or 'HEAD' cmd += [f'{brname}~{start + count}..{brname}~{start}'] - stdout = command.run_list(cmd) + stdout = command.run_list(cmd, cwd=cwd) files = stdout.splitlines() # We have an extra file if there is a cover letter @@ -436,7 +448,7 @@ def check_suppress_cc_config(): def email_patches(series, cover_fname, args, dry_run, warn_on_error, cc_fname, alias, self_only=False, in_reply_to=None, thread=False, - smtp_server=None): + smtp_server=None, cwd=None): """Email a patch series. Args: @@ -456,6 +468,7 @@ def email_patches(series, cover_fname, args, dry_run, warn_on_error, cc_fname, thread (bool): True to add --thread to git send-email (make all patches reply to cover-letter or first patch in series) smtp_server (str or None): SMTP server to use to send patches + cwd (str): Path to use for patch files (None to use current dir) Returns: Git command that was/would be run @@ -528,7 +541,7 @@ send --cc-cmd cc-fname" cover p1 p2' cmd.append(cover_fname) cmd += args if not dry_run: - command.run(*cmd, capture=False, capture_stderr=False) + command.run(*cmd, capture=False, capture_stderr=False, cwd=cwd) cmdstr = ' '.join([f'"{x}"' if ' ' in x and not '"' in x else x for x in cmd]) return cmdstr @@ -695,7 +708,7 @@ def setup(): .return_code == 0) -def get_hash(spec): +def get_hash(spec, git_dir=None): """Get the hash of a commit Args: @@ -704,8 +717,11 @@ def get_hash(spec): Returns: str: Hash of commit """ - return command.output_one_line('git', 'show', '-s', '--pretty=format:%H', - spec) + cmd = ['git'] + if git_dir: + cmd += ['--git-dir', git_dir] + cmd += ['show', '-s', '--pretty=format:%H', spec] + return command.output_one_line(*cmd) def get_head(): @@ -717,13 +733,18 @@ def get_head(): return get_hash('HEAD') -def get_branch(): +def get_branch(git_dir=None): """Get the branch we are currently on Return: str: branch name, or None if none + git_dir (str): Path to git repository (None to use default) """ - out = command.output_one_line('git', 'rev-parse', '--abbrev-ref', 'HEAD') + cmd = ['git'] + if git_dir: + cmd += ['--git-dir', git_dir] + cmd += ['rev-parse', '--abbrev-ref', 'HEAD'] + out = command.output_one_line(*cmd, raise_on_error=False) if out == 'HEAD': return None return out -- cgit v1.2.3 From afea95f65380b4f0e98db33252c1bdcc04cc972a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 8 May 2025 04:30:55 +0200 Subject: u_boot_pylib: Speed up determining the upstream branch Use --decorate to quickly detect the upstream branch, since this is much faster than using 'git name-rev' on every possible commit. Signed-off-by: Simon Glass --- tools/u_boot_pylib/gitutil.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'tools/u_boot_pylib/gitutil.py') diff --git a/tools/u_boot_pylib/gitutil.py b/tools/u_boot_pylib/gitutil.py index f89576ef3b9..cc57e7b7f73 100644 --- a/tools/u_boot_pylib/gitutil.py +++ b/tools/u_boot_pylib/gitutil.py @@ -13,7 +13,7 @@ USE_NO_DECORATE = True def log_cmd(commit_range, git_dir=None, oneline=False, reverse=False, - count=None): + count=None, decorate=False): """Create a command to perform a 'git log' Args: @@ -31,8 +31,10 @@ def log_cmd(commit_range, git_dir=None, oneline=False, reverse=False, cmd += ['--no-pager', 'log', '--no-color'] if oneline: cmd.append('--oneline') - if USE_NO_DECORATE: + if USE_NO_DECORATE and not decorate: cmd.append('--no-decorate') + if decorate: + cmd.append('--decorate') if reverse: cmd.append('--reverse') if count is not None: @@ -90,9 +92,11 @@ def name_revision(commit_hash): Name of revision, if any, else None """ stdout = command.output_one_line('git', 'name-rev', commit_hash) + if not stdout: + return None # We expect a commit, a space, then a revision name - name = stdout.split(' ')[1].strip() + name = stdout.split()[1].strip() return name @@ -112,18 +116,21 @@ def guess_upstream(git_dir, branch): Name of upstream branch (e.g. 'upstream/master') or None if none Warning/error message, or None if none """ - cmd = log_cmd(branch, git_dir=git_dir, oneline=True, count=100) + cmd = log_cmd(branch, git_dir=git_dir, oneline=True, count=100, + decorate=True) result = command.run_one(*cmd, capture=True, capture_stderr=True, raise_on_error=False) if result.return_code: return None, f"Branch '{branch}' not found" for line in result.stdout.splitlines()[1:]: - commit_hash = line.split(' ')[0] - name = name_revision(commit_hash) - if '~' not in name and '^' not in name: - if name.startswith('remotes/'): - name = name[8:] - return name, f"Guessing upstream as '{name}'" + parts = line.split(maxsplit=1) + if len(parts) >= 2 and parts[1].startswith('('): + commit_hash = parts[0] + name = name_revision(commit_hash) + if '~' not in name and '^' not in name: + if name.startswith('remotes/'): + name = name[8:] + return name, f"Guessing upstream as '{name}'" return None, f"Cannot find a suitable upstream for branch '{branch}'" -- cgit v1.2.3 From 3724cbade41a1dd0ec94cd9b511afe005ebf4804 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 8 May 2025 05:23:41 +0200 Subject: patman: Clean up creation of the git tree The test starts with the HEAD pointing to the wrong place, so that the created files appear to be deleted. Fix this by resetting the tree before tests start. Add a check that the tree is clean. Update pygit2 so that the enums are available. --- tools/u_boot_pylib/gitutil.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'tools/u_boot_pylib/gitutil.py') diff --git a/tools/u_boot_pylib/gitutil.py b/tools/u_boot_pylib/gitutil.py index cc57e7b7f73..3c52cce232c 100644 --- a/tools/u_boot_pylib/gitutil.py +++ b/tools/u_boot_pylib/gitutil.py @@ -757,6 +757,24 @@ def get_branch(git_dir=None): return out +def check_dirty(git_dir=None, work_tree=None): + """Check if the tree is dirty + + Args: + git_dir (str): Path to git repository (None to use default) + + Return: + str: List of dirty filenames and state + """ + cmd = ['git'] + if git_dir: + cmd += ['--git-dir', git_dir] + if work_tree: + cmd += ['--work-tree', work_tree] + cmd += ['status', '--porcelain', '--untracked-files=no'] + return command.output(*cmd).splitlines() + + if __name__ == "__main__": import doctest -- cgit v1.2.3 From 45f239afa1f85fdc6700d8e088e179024c6c21b0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 10 May 2025 13:04:54 +0200 Subject: u_boot_pylib: Correct pylint warnings in gitutil Correct various pylint warnings in this file. The remaining ones are three functions with too many arguments (R0913 and R0918) and use of global (W0603). Signed-off-by: Simon Glass --- tools/u_boot_pylib/gitutil.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'tools/u_boot_pylib/gitutil.py') diff --git a/tools/u_boot_pylib/gitutil.py b/tools/u_boot_pylib/gitutil.py index 3c52cce232c..cfcfeffe2f4 100644 --- a/tools/u_boot_pylib/gitutil.py +++ b/tools/u_boot_pylib/gitutil.py @@ -2,6 +2,8 @@ # Copyright (c) 2011 The Chromium OS Authors. # +"""Basic utilities for running the git command-line tool from Python""" + import os import sys @@ -22,6 +24,8 @@ def log_cmd(commit_range, git_dir=None, oneline=False, reverse=False, oneline (bool): True to use --oneline, else False reverse (bool): True to reverse the log (--reverse) count (int or None): Number of commits to list, or None for no limit + decorate (bool): True to use --decorate + Return: List containing command and arguments to run """ @@ -518,9 +522,8 @@ send --cc-cmd cc-fname" cover p1 p2' """ to = build_email_list(series.get('to'), alias, '--to', warn_on_error) if not to: - git_config_to = command.output('git', 'config', 'sendemail.to', - raise_on_error=False) - if not git_config_to: + if not command.output('git', 'config', 'sendemail.to', + raise_on_error=False): print("No recipient.\n" "Please add something like this to a commit\n" "Series-to: Fred Bloggs \n" @@ -549,9 +552,8 @@ send --cc-cmd cc-fname" cover p1 p2' cmd += args if not dry_run: command.run(*cmd, capture=False, capture_stderr=False, cwd=cwd) - cmdstr = ' '.join([f'"{x}"' if ' ' in x and not '"' in x else x - for x in cmd]) - return cmdstr + return' '.join([f'"{x}"' if ' ' in x and '"' not in x else x + for x in cmd]) def lookup_email(lookup_name, alias, warn_on_error=True, level=0): @@ -720,6 +722,7 @@ def get_hash(spec, git_dir=None): Args: spec (str): Git commit to show, e.g. 'my-branch~12' + git_dir (str): Path to git repository (None to use default) Returns: str: Hash of commit @@ -762,6 +765,7 @@ def check_dirty(git_dir=None, work_tree=None): Args: git_dir (str): Path to git repository (None to use default) + work_tree (str): Git worktree to use, or None if none Return: str: List of dirty filenames and state -- cgit v1.2.3 From 212ed6bdb73d7999c8a25ad0c55a5358c0b44f03 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 10 May 2025 13:04:55 +0200 Subject: patman: Deal with git safe-directory warning When running tests where the .git directory is not owned by the current user, various warnings are produced and the tests fail. This happens in CI. For patman itself, modify the gitutil.get_top_level() function to return None in this case. Ensure that the warning is not shown, since it creates about 1000 lines of output. For checkpatch, the same warning is produced even though --no-tree is given. Suppress that as well. Signed-off-by: Simon Glass --- tools/u_boot_pylib/gitutil.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'tools/u_boot_pylib/gitutil.py') diff --git a/tools/u_boot_pylib/gitutil.py b/tools/u_boot_pylib/gitutil.py index cfcfeffe2f4..7d001d03bed 100644 --- a/tools/u_boot_pylib/gitutil.py +++ b/tools/u_boot_pylib/gitutil.py @@ -644,7 +644,7 @@ def get_top_level(): """Return name of top-level directory for this git repo. Returns: - str: Full path to git top-level directory + str: Full path to git top-level directory, or None if not found This test makes sure that we are running tests in the right subdir @@ -652,7 +652,12 @@ def get_top_level(): os.path.join(get_top_level(), 'tools', 'patman') True """ - return command.output_one_line('git', 'rev-parse', '--show-toplevel') + result = command.run_one( + 'git', 'rev-parse', '--show-toplevel', oneline=True, capture=True, + capture_stderr=True, raise_on_error=False) + if result.return_code: + return None + return result.stdout.strip() def get_alias_file(): @@ -670,7 +675,7 @@ def get_alias_file(): if os.path.isabs(fname): return fname - return os.path.join(get_top_level(), fname) + return os.path.join(get_top_level() or '', fname) def get_default_user_name(): -- cgit v1.2.3 From 31a1c4c9d840d4a311c8a7499a18861d351c80ac Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 10 May 2025 13:04:56 +0200 Subject: u_boot_pylib: Add more functions to gitutil Add functions for checking a branch, showing a commit, etc. to support the new functionality. Git version 2.34.1 ignores --stat if --quiet is given, so adjust the args so that this performs as expected. Signed-off-by: Simon Glass --- tools/u_boot_pylib/gitutil.py | 96 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) (limited to 'tools/u_boot_pylib/gitutil.py') diff --git a/tools/u_boot_pylib/gitutil.py b/tools/u_boot_pylib/gitutil.py index 7d001d03bed..34b4dbb4839 100644 --- a/tools/u_boot_pylib/gitutil.py +++ b/tools/u_boot_pylib/gitutil.py @@ -784,6 +784,102 @@ def check_dirty(git_dir=None, work_tree=None): return command.output(*cmd).splitlines() +def check_branch(name, git_dir=None): + """Check if a branch exists + + Args: + name (str): Name of the branch to check + git_dir (str): Path to git repository (None to use default) + """ + cmd = ['git'] + if git_dir: + cmd += ['--git-dir', git_dir] + cmd += ['branch', '--list', name] + + # This produces ' ' or '* ' + out = command.output(*cmd).rstrip() + return out[2:] == name + + +def rename_branch(old_name, name, git_dir=None): + """Check if a branch exists + + Args: + old_name (str): Name of the branch to rename + name (str): New name for the branch + git_dir (str): Path to git repository (None to use default) + + Return: + str: Output from command + """ + cmd = ['git'] + if git_dir: + cmd += ['--git-dir', git_dir] + cmd += ['branch', '--move', old_name, name] + + # This produces ' ' or '* ' + return command.output(*cmd).rstrip() + + +def get_commit_message(commit, git_dir=None): + """Gets the commit message for a commit + + Args: + commit (str): commit to check + git_dir (str): Path to git repository (None to use default) + + Return: + list of str: Lines from the commit message + """ + cmd = ['git'] + if git_dir: + cmd += ['--git-dir', git_dir] + cmd += ['show', '--quiet', commit] + + out = command.output(*cmd) + # the header is followed by a blank line + lines = out.splitlines() + empty = lines.index('') + msg = lines[empty + 1:] + unindented = [line[4:] for line in msg] + + return unindented + + +def show_commit(commit, msg=True, diffstat=False, patch=False, colour=True, + git_dir=None): + """Runs 'git show' and returns the output + + Args: + commit (str): commit to check + msg (bool): Show the commit message + diffstat (bool): True to include the diffstat + patch (bool): True to include the patch + colour (bool): True to force use of colour + git_dir (str): Path to git repository (None to use default) + + Return: + list of str: Lines from the commit message + """ + cmd = ['git'] + if git_dir: + cmd += ['--git-dir', git_dir] + cmd += ['show'] + if colour: + cmd.append('--color') + if not msg: + cmd.append('--oneline') + if diffstat: + cmd.append('--stat') + else: + cmd.append('--quiet') + if patch: + cmd.append('--patch') + cmd.append(commit) + + return command.output(*cmd) + + if __name__ == "__main__": import doctest -- cgit v1.2.3