u_boot_pylib: Add a function to run a single command

Add a helper to avoid needing to use a list within a list for this
simple case.

Update existing users of runpipe() to use this where possible.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2025-02-03 09:26:45 -07:00 committed by Tom Rini
parent f8456c91aa
commit 3d094ce28a
11 changed files with 84 additions and 75 deletions

View file

@ -345,8 +345,9 @@ class TestFunctional(unittest.TestCase):
Arguments to pass, as a list of strings Arguments to pass, as a list of strings
kwargs: Arguments to pass to Command.RunPipe() kwargs: Arguments to pass to Command.RunPipe()
""" """
result = command.run_pipe([[self._binman_pathname] + list(args)], all_args = [self._binman_pathname] + list(args)
capture=True, capture_stderr=True, raise_on_error=False) result = command.run_one(*all_args, capture=True, capture_stderr=True,
raise_on_error=False)
if result.return_code and kwargs.get('raise_on_error', True): if result.return_code and kwargs.get('raise_on_error', True):
raise Exception("Error running '%s': %s" % (' '.join(args), raise Exception("Error running '%s': %s" % (' '.join(args),
result.stdout + result.stderr)) result.stdout + result.stderr))

View file

@ -251,9 +251,9 @@ class KconfigScanner:
'-undef', '-undef',
'-x', 'assembler-with-cpp', '-x', 'assembler-with-cpp',
defconfig] defconfig]
result = command.run_pipe([cmd], capture=True, capture_stderr=True) stdout = command.output(*cmd, capture_stderr=True)
temp = tempfile.NamedTemporaryFile(prefix='buildman-') temp = tempfile.NamedTemporaryFile(prefix='buildman-')
tools.write_file(temp.name, result.stdout, False) tools.write_file(temp.name, stdout, False)
fname = temp.name fname = temp.name
tout.info(f'Processing #include to produce {defconfig}') tout.info(f'Processing #include to produce {defconfig}')
else: else:

View file

@ -510,7 +510,7 @@ class Builder:
stage: Stage that we are at (mrproper, config, oldconfig, build) stage: Stage that we are at (mrproper, config, oldconfig, build)
cwd: Directory where make should be run cwd: Directory where make should be run
args: Arguments to pass to make args: Arguments to pass to make
kwargs: Arguments to pass to command.run_pipe() kwargs: Arguments to pass to command.run_one()
""" """
def check_output(stream, data): def check_output(stream, data):
@ -531,11 +531,12 @@ class Builder:
return False return False
self._restarting_config = False self._restarting_config = False
self._terminated = False self._terminated = False
cmd = [self.gnu_make] + list(args) cmd = [self.gnu_make] + list(args)
result = command.run_pipe([cmd], capture=True, capture_stderr=True, result = command.run_one(*cmd, capture=True, capture_stderr=True,
cwd=cwd, raise_on_error=False, infile='/dev/null', cwd=cwd, raise_on_error=False,
output_func=check_output, **kwargs) infile='/dev/null', output_func=check_output,
**kwargs)
if self._terminated: if self._terminated:
# Try to be helpful # Try to be helpful

View file

@ -179,13 +179,12 @@ class BuilderThread(threading.Thread):
cwd (str): Working directory to set, or None to leave it alone cwd (str): Working directory to set, or None to leave it alone
*args (list of str): Arguments to pass to 'make' *args (list of str): Arguments to pass to 'make'
**kwargs (dict): A list of keyword arguments to pass to **kwargs (dict): A list of keyword arguments to pass to
command.run_pipe() command.run_one()
Returns: Returns:
CommandResult object CommandResult object
""" """
return self.builder.do_make(commit, brd, stage, cwd, *args, return self.builder.do_make(commit, brd, stage, cwd, *args, **kwargs)
**kwargs)
def _build_args(self, brd, out_dir, out_rel_dir, work_dir, commit_upto): def _build_args(self, brd, out_dir, out_rel_dir, work_dir, commit_upto):
"""Set up arguments to the args list based on the settings """Set up arguments to the args list based on the settings
@ -588,9 +587,10 @@ class BuilderThread(threading.Thread):
lines = [] lines = []
for fname in BASE_ELF_FILENAMES: for fname in BASE_ELF_FILENAMES:
cmd = [f'{self.toolchain.cross}nm', '--size-sort', fname] cmd = [f'{self.toolchain.cross}nm', '--size-sort', fname]
nm_result = command.run_pipe([cmd], capture=True, nm_result = command.run_one(*cmd, capture=True,
capture_stderr=True, cwd=result.out_dir, capture_stderr=True,
raise_on_error=False, env=env) cwd=result.out_dir,
raise_on_error=False, env=env)
if nm_result.stdout: if nm_result.stdout:
nm_fname = self.builder.get_func_sizes_file( nm_fname = self.builder.get_func_sizes_file(
result.commit_upto, result.brd.target, fname) result.commit_upto, result.brd.target, fname)
@ -598,9 +598,10 @@ class BuilderThread(threading.Thread):
print(nm_result.stdout, end=' ', file=outf) print(nm_result.stdout, end=' ', file=outf)
cmd = [f'{self.toolchain.cross}objdump', '-h', fname] cmd = [f'{self.toolchain.cross}objdump', '-h', fname]
dump_result = command.run_pipe([cmd], capture=True, dump_result = command.run_one(*cmd, capture=True,
capture_stderr=True, cwd=result.out_dir, capture_stderr=True,
raise_on_error=False, env=env) cwd=result.out_dir,
raise_on_error=False, env=env)
rodata_size = '' rodata_size = ''
if dump_result.stdout: if dump_result.stdout:
objdump = self.builder.get_objdump_file(result.commit_upto, objdump = self.builder.get_objdump_file(result.commit_upto,
@ -613,9 +614,10 @@ class BuilderThread(threading.Thread):
rodata_size = fields[2] rodata_size = fields[2]
cmd = [f'{self.toolchain.cross}size', fname] cmd = [f'{self.toolchain.cross}size', fname]
size_result = command.run_pipe([cmd], capture=True, size_result = command.run_one(*cmd, capture=True,
capture_stderr=True, cwd=result.out_dir, capture_stderr=True,
raise_on_error=False, env=env) cwd=result.out_dir,
raise_on_error=False, env=env)
if size_result.stdout: if size_result.stdout:
lines.append(size_result.stdout.splitlines()[1] + ' ' + lines.append(size_result.stdout.splitlines()[1] + ' ' +
rodata_size) rodata_size)
@ -624,9 +626,8 @@ class BuilderThread(threading.Thread):
cmd = [f'{self.toolchain.cross}objcopy', '-O', 'binary', cmd = [f'{self.toolchain.cross}objcopy', '-O', 'binary',
'-j', '.rodata.default_environment', '-j', '.rodata.default_environment',
'env/built-in.o', 'uboot.env'] 'env/built-in.o', 'uboot.env']
command.run_pipe([cmd], capture=True, command.run_one(*cmd, capture=True, capture_stderr=True,
capture_stderr=True, cwd=result.out_dir, cwd=result.out_dir, raise_on_error=False, env=env)
raise_on_error=False, env=env)
if not work_in_output: if not work_in_output:
copy_files(result.out_dir, build_dir, '', ['uboot.env']) copy_files(result.out_dir, build_dir, '', ['uboot.env'])

View file

@ -232,8 +232,8 @@ class TestFunctional(unittest.TestCase):
self._toolchains.Add('gcc', test=False) self._toolchains.Add('gcc', test=False)
def _RunBuildman(self, *args): def _RunBuildman(self, *args):
return command.run_pipe([[self._buildman_pathname] + list(args)], all_args = [self._buildman_pathname] + list(args)
capture=True, capture_stderr=True) return command.run_one(*all_args, capture=True, capture_stderr=True)
def _RunControl(self, *args, brds=False, clean_dir=False, def _RunControl(self, *args, brds=False, clean_dir=False,
test_thread_exceptions=False, get_builder=True): test_thread_exceptions=False, get_builder=True):
@ -445,7 +445,7 @@ class TestFunctional(unittest.TestCase):
stage: Stage that we are at (mrproper, config, build) stage: Stage that we are at (mrproper, config, build)
cwd: Directory where make should be run cwd: Directory where make should be run
args: Arguments to pass to make args: Arguments to pass to make
kwargs: Arguments to pass to command.run_pipe() kwargs: Arguments to pass to command.run_one()
""" """
self._make_calls += 1 self._make_calls += 1
out_dir = '' out_dir = ''

View file

@ -100,7 +100,7 @@ class Toolchain:
else: else:
self.priority = priority self.priority = priority
if test: if test:
result = command.run_pipe([cmd], capture=True, env=env, result = command.run_one(*cmd, capture=True, env=env,
raise_on_error=False) raise_on_error=False)
self.ok = result.return_code == 0 self.ok = result.return_code == 0
if verbose: if verbose:

View file

@ -65,9 +65,9 @@ def count_commits_to_branch(branch):
rev_range = '%s..%s' % (us, branch) rev_range = '%s..%s' % (us, branch)
else: else:
rev_range = '@{upstream}..' rev_range = '@{upstream}..'
pipe = [log_cmd(rev_range, oneline=True)] cmd = log_cmd(rev_range, oneline=True)
result = command.run_pipe(pipe, capture=True, capture_stderr=True, result = command.run_one(*cmd, capture=True, capture_stderr=True,
oneline=True, raise_on_error=False) oneline=True, raise_on_error=False)
if result.return_code: if result.return_code:
raise ValueError('Failed to determine upstream: %s' % raise ValueError('Failed to determine upstream: %s' %
result.stderr.strip()) result.stderr.strip())
@ -84,8 +84,7 @@ def name_revision(commit_hash):
Return: Return:
Name of revision, if any, else None Name of revision, if any, else None
""" """
pipe = ['git', 'name-rev', commit_hash] stdout = command.output_one_line('git', 'name-rev', commit_hash)
stdout = command.run_pipe([pipe], capture=True, oneline=True).stdout
# We expect a commit, a space, then a revision name # We expect a commit, a space, then a revision name
name = stdout.split(' ')[1].strip() name = stdout.split(' ')[1].strip()
@ -108,9 +107,9 @@ def guess_upstream(git_dir, branch):
Name of upstream branch (e.g. 'upstream/master') or None if none Name of upstream branch (e.g. 'upstream/master') or None if none
Warning/error message, or None if none Warning/error message, or None if none
""" """
pipe = [log_cmd(branch, git_dir=git_dir, oneline=True, count=100)] cmd = log_cmd(branch, git_dir=git_dir, oneline=True, count=100)
result = command.run_pipe(pipe, capture=True, capture_stderr=True, result = command.run_one(*cmd, capture=True, capture_stderr=True,
raise_on_error=False) raise_on_error=False)
if result.return_code: if result.return_code:
return None, "Branch '%s' not found" % branch return None, "Branch '%s' not found" % branch
for line in result.stdout.splitlines()[1:]: for line in result.stdout.splitlines()[1:]:
@ -183,9 +182,9 @@ def count_commits_in_range(git_dir, range_expr):
Number of patches that exist in the supplied range or None if none Number of patches that exist in the supplied range or None if none
were found were found
""" """
pipe = [log_cmd(range_expr, git_dir=git_dir, oneline=True)] cmd = log_cmd(range_expr, git_dir=git_dir, oneline=True)
result = command.run_pipe(pipe, capture=True, capture_stderr=True, result = command.run_one(*cmd, capture=True, capture_stderr=True,
raise_on_error=False) raise_on_error=False)
if result.return_code: if result.return_code:
return None, "Range '%s' not found or is invalid" % range_expr return None, "Range '%s' not found or is invalid" % range_expr
patch_count = len(result.stdout.splitlines()) patch_count = len(result.stdout.splitlines())
@ -250,9 +249,8 @@ def clone(git_dir, output_dir):
Args: Args:
commit_hash: Commit hash to check out commit_hash: Commit hash to check out
""" """
pipe = ['git', 'clone', git_dir, '.'] result = command.run_one('git', 'clone', git_dir, '.', capture=True,
result = command.run_pipe([pipe], capture=True, cwd=output_dir, cwd=output_dir, capture_stderr=True)
capture_stderr=True)
if result.return_code != 0: if result.return_code != 0:
raise OSError('git clone: %s' % result.stderr) raise OSError('git clone: %s' % result.stderr)
@ -263,13 +261,13 @@ def fetch(git_dir=None, work_tree=None):
Args: Args:
commit_hash: Commit hash to check out commit_hash: Commit hash to check out
""" """
pipe = ['git'] cmd = ['git']
if git_dir: if git_dir:
pipe.extend(['--git-dir', git_dir]) cmd.extend(['--git-dir', git_dir])
if work_tree: if work_tree:
pipe.extend(['--work-tree', work_tree]) cmd.extend(['--work-tree', work_tree])
pipe.append('fetch') cmd.append('fetch')
result = command.run_pipe([pipe], capture=True, capture_stderr=True) result = command.run_one(*cmd, capture=True, capture_stderr=True)
if result.return_code != 0: if result.return_code != 0:
raise OSError('git fetch: %s' % result.stderr) raise OSError('git fetch: %s' % result.stderr)
@ -283,9 +281,9 @@ def check_worktree_is_available(git_dir):
Returns: Returns:
True if git-worktree commands will work, False otherwise. True if git-worktree commands will work, False otherwise.
""" """
pipe = ['git', '--git-dir', git_dir, 'worktree', 'list'] result = command.run_one('git', '--git-dir', git_dir, 'worktree', 'list',
result = command.run_pipe([pipe], capture=True, capture_stderr=True, capture=True, capture_stderr=True,
raise_on_error=False) raise_on_error=False)
return result.return_code == 0 return result.return_code == 0
@ -298,11 +296,11 @@ def add_worktree(git_dir, output_dir, commit_hash=None):
commit_hash: Commit hash to checkout commit_hash: Commit hash to checkout
""" """
# We need to pass --detach to avoid creating a new branch # We need to pass --detach to avoid creating a new branch
pipe = ['git', '--git-dir', git_dir, 'worktree', 'add', '.', '--detach'] cmd = ['git', '--git-dir', git_dir, 'worktree', 'add', '.', '--detach']
if commit_hash: if commit_hash:
pipe.append(commit_hash) cmd.append(commit_hash)
result = command.run_pipe([pipe], capture=True, cwd=output_dir, result = command.run_one(*cmd, capture=True, cwd=output_dir,
capture_stderr=True) capture_stderr=True)
if result.return_code != 0: if result.return_code != 0:
raise OSError('git worktree add: %s' % result.stderr) raise OSError('git worktree add: %s' % result.stderr)
@ -313,8 +311,8 @@ def prune_worktrees(git_dir):
Args: Args:
git_dir: The repository whose deleted worktrees should be pruned git_dir: The repository whose deleted worktrees should be pruned
""" """
pipe = ['git', '--git-dir', git_dir, 'worktree', 'prune'] result = command.run_one('git', '--git-dir', git_dir, 'worktree', 'prune',
result = command.run_pipe([pipe], capture=True, capture_stderr=True) capture=True, capture_stderr=True)
if result.return_code != 0: if result.return_code != 0:
raise OSError('git worktree prune: %s' % result.stderr) raise OSError('git worktree prune: %s' % result.stderr)
@ -687,7 +685,7 @@ def setup():
if alias_fname: if alias_fname:
settings.ReadGitAliases(alias_fname) settings.ReadGitAliases(alias_fname)
cmd = log_cmd(None, count=0) cmd = log_cmd(None, count=0)
use_no_decorate = (command.run_pipe([cmd], raise_on_error=False) use_no_decorate = (command.run_one(*cmd, raise_on_error=False)
.return_code == 0) .return_code == 0)

View file

@ -711,7 +711,7 @@ def get_list(commit_range, git_dir=None, count=None):
""" """
params = gitutil.log_cmd(commit_range, reverse=True, count=count, params = gitutil.log_cmd(commit_range, reverse=True, count=count,
git_dir=git_dir) git_dir=git_dir)
return command.run_pipe([params], capture=True).stdout return command.run_one(*params, capture=True).stdout
def get_metadata_for_list(commit_range, git_dir=None, count=None, def get_metadata_for_list(commit_range, git_dir=None, count=None,
series=None, allow_overwrite=False): series=None, allow_overwrite=False):

View file

@ -43,18 +43,16 @@ def rm_kconfig_include(path):
Args: Args:
path: Path to search for and remove path: Path to search for and remove
""" """
cmd = ['git', 'grep', path] stdout = command.output('git', 'grep', path, raise_on_error=False)
stdout = command.run_pipe([cmd], capture=True, raise_on_error=False).stdout
if not stdout: if not stdout:
return return
fname = stdout.split(':')[0] fname = stdout.split(':')[0]
print("Fixing up '%s' to remove reference to '%s'" % (fname, path)) print("Fixing up '%s' to remove reference to '%s'" % (fname, path))
cmd = ['sed', '-i', '\|%s|d' % path, fname] stdout = command.run_one('sed', '-i', rf'\|{path}|d', fname,
stdout = command.run_pipe([cmd], capture=True).stdout capture=True).stdout
cmd = ['git', 'add', fname] stdout = command.output('git', 'add', fname)
stdout = command.run_pipe([cmd], capture=True).stdout
def rm_board(board): def rm_board(board):
"""Create a commit which removes a single board """Create a commit which removes a single board
@ -68,8 +66,7 @@ def rm_board(board):
""" """
# Find all MAINTAINERS and Kconfig files which mention the board # Find all MAINTAINERS and Kconfig files which mention the board
cmd = ['git', 'grep', '-l', board] stdout = command.output('git', 'grep', '-l', board)
stdout = command.run_pipe([cmd], capture=True).stdout
maintain = [] maintain = []
kconfig = [] kconfig = []
for line in stdout.splitlines(): for line in stdout.splitlines():
@ -109,16 +106,14 @@ def rm_board(board):
# Search for Kconfig files in the resulting list. Remove any 'source' lines # Search for Kconfig files in the resulting list. Remove any 'source' lines
# which reference Kconfig files we want to remove # which reference Kconfig files we want to remove
for path in real: for path in real:
cmd = ['find', path] stdout = command.output('find', path, raise_on_error=False)
stdout = (command.run_pipe([cmd], capture=True, raise_on_error=False).
stdout)
for fname in stdout.splitlines(): for fname in stdout.splitlines():
if fname.endswith('Kconfig'): if fname.endswith('Kconfig'):
rm_kconfig_include(fname) rm_kconfig_include(fname)
# Remove unwanted files # Remove unwanted files
cmd = ['git', 'rm', '-r'] + real cmd = ['git', 'rm', '-r'] + real
stdout = command.run_pipe([cmd], capture=True).stdout stdout = command.output(*cmd, capture=True)
## Change the messages as needed ## Change the messages as needed
msg = '''arm: Remove %s board msg = '''arm: Remove %s board
@ -131,13 +126,11 @@ Remove it.
msg += 'Patch-cc: %s\n' % name msg += 'Patch-cc: %s\n' % name
# Create the commit # Create the commit
cmd = ['git', 'commit', '-s', '-m', msg] stdout = command.output('git', 'commit', '-s', '-m', msg)
stdout = command.run_pipe([cmd], capture=True).stdout
# Check if the board is mentioned anywhere else. The user will need to deal # Check if the board is mentioned anywhere else. The user will need to deal
# with this # with this
cmd = ['git', 'grep', '-il', board] print(command.output('git', 'grep', '-il', board, raise_on_error=False))
print(command.run_pipe([cmd], capture=True, raise_on_error=False).stdout)
print(' '.join(cmd)) print(' '.join(cmd))
for board in sys.argv[1:]: for board in sys.argv[1:]:

View file

@ -188,6 +188,21 @@ def run(*cmd, **kwargs):
return run_pipe([cmd], **kwargs).stdout return run_pipe([cmd], **kwargs).stdout
def run_one(*cmd, **kwargs):
"""Run a single command
Note that you must add 'capture' to kwargs to obtain non-empty output
Args:
*cmd (list of str): Command to run
**kwargs (dict of args): Extra arguments to pass in
Returns:
CommandResult: output of command
"""
return run_pipe([cmd], **kwargs)
def run_list(cmd): def run_list(cmd):
"""Run a command and return its output """Run a command and return its output

View file

@ -376,7 +376,7 @@ def run_result(name, *args, **kwargs):
args = tuple(extra_args) + args args = tuple(extra_args) + args
name = os.path.expanduser(name) # Expand paths containing ~ name = os.path.expanduser(name) # Expand paths containing ~
all_args = (name,) + args all_args = (name,) + args
result = command.run_pipe([all_args], capture=True, capture_stderr=True, result = command.run_one(*all_args, capture=True, capture_stderr=True,
env=env, raise_on_error=False, binary=binary) env=env, raise_on_error=False, binary=binary)
if result.return_code: if result.return_code:
if raise_on_error: if raise_on_error: