summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile4
-rw-r--r--tools/binman/control.py6
-rw-r--r--tools/binman/elf.py2
-rw-r--r--tools/binman/ftest.py7
-rw-r--r--tools/binman/test/346_remove_template.dts49
-rw-r--r--tools/buildman/func_test.py4
-rw-r--r--tools/docker/Dockerfile23
-rw-r--r--tools/patman/control.py3
-rw-r--r--tools/patman/func_test.py49
-rw-r--r--tools/patman/patchstream.py43
-rw-r--r--tools/patman/series.py2
-rw-r--r--tools/u_boot_pylib/gitutil.py267
12 files changed, 320 insertions, 139 deletions
diff --git a/tools/Makefile b/tools/Makefile
index 53b87d22a80..d0e4d2d16c3 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -169,6 +169,8 @@ fit_check_sign-objs := $(dumpimage-mkimage-objs) fit_check_sign.o
fdt_add_pubkey-objs := $(dumpimage-mkimage-objs) fdt_add_pubkey.o
file2include-objs := file2include.o
preload_check_sign-objs := $(dumpimage-mkimage-objs) $(PRELOAD_OBJS-y) preload_check_sign.o
+HOSTCFLAGS_preload_check_sign.o += \
+ $(shell pkg-config --cflags libssl libcrypto 2> /dev/null || echo "")
ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_TOOLS_LIBCRYPTO),)
# Add CFG_MXS into host CFLAGS, so we can check whether or not register
@@ -207,6 +209,8 @@ HOSTLDLIBS_fit_info := $(HOSTLDLIBS_mkimage)
HOSTLDLIBS_fit_check_sign := $(HOSTLDLIBS_mkimage)
HOSTLDLIBS_fdt_add_pubkey := $(HOSTLDLIBS_mkimage)
HOSTLDLIBS_preload_check_sign := $(HOSTLDLIBS_mkimage)
+HOSTLDLIBS_preload_check_sign += \
+ $(shell pkg-config --libs libssl libcrypto 2> /dev/null || echo "-lssl -lcrypto")
hostprogs-$(CONFIG_EXYNOS5250) += mkexynosspl
hostprogs-$(CONFIG_EXYNOS5420) += mkexynosspl
diff --git a/tools/binman/control.py b/tools/binman/control.py
index e73c598298c..81f61e3e152 100644
--- a/tools/binman/control.py
+++ b/tools/binman/control.py
@@ -522,9 +522,13 @@ def _ProcessTemplates(parent):
def _RemoveTemplates(parent):
"""Remove any templates in the binman description
"""
+ del_nodes = []
for node in parent.subnodes:
if node.name.startswith('template'):
- node.Delete()
+ del_nodes.append(node)
+
+ for node in del_nodes:
+ node.Delete()
def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt, use_expanded, indir):
"""Prepare the images to be processed and select the device tree
diff --git a/tools/binman/elf.py b/tools/binman/elf.py
index c75f4478813..6ac960e0419 100644
--- a/tools/binman/elf.py
+++ b/tools/binman/elf.py
@@ -28,7 +28,7 @@ except: # pragma: no cover
# BSYM in little endian, keep in sync with include/binman_sym.h
BINMAN_SYM_MAGIC_VALUE = 0x4d595342
-# Information about an EFL symbol:
+# Information about an ELF symbol:
# section (str): Name of the section containing this symbol
# address (int): Address of the symbol (its value)
# size (int): Size of the symbol in bytes
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 1a92a99b511..948fcc02259 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -7990,5 +7990,12 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
"""Test an image with an FIT with multiple FDT images using NAME"""
self.CheckFitFdt('345_fit_fdt_name.dts', use_seq_num=False)
+ def testRemoveTemplate(self):
+ """Test whether template is removed"""
+ TestFunctional._MakeInputFile('my-blob.bin', b'blob')
+ TestFunctional._MakeInputFile('my-blob2.bin', b'other')
+ self._DoTestFile('346_remove_template.dts',
+ force_missing_bintools='openssl',)
+
if __name__ == "__main__":
unittest.main()
diff --git a/tools/binman/test/346_remove_template.dts b/tools/binman/test/346_remove_template.dts
new file mode 100644
index 00000000000..e05229f3ebc
--- /dev/null
+++ b/tools/binman/test/346_remove_template.dts
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+/ {
+ binman: binman {
+ multiple-images;
+
+ template_1: template-1 {
+ section {
+ phandle1: my-blob.bin {
+ filename = "my-blob.bin";
+ type = "blob-ext";
+ };
+ };
+ };
+ template_2: template-2 {
+ section {
+ ti-secure {
+ content = <&phandle2>;
+ keyfile = "key.pem";
+ };
+ phandle2: my-blob.bin {
+ filename = "my-blob.bin";
+ type = "blob-ext";
+ };
+ };
+ };
+ template_3: template-3 {
+ section {
+ phandle3: my-blob.bin {
+ filename = "my-blob.bin";
+ type = "blob-ext";
+ };
+ };
+ };
+
+ file1 {
+ insert-template = <&template_1>;
+ };
+
+ file2 {
+ insert-template = <&template_2>;
+ };
+
+ file3 {
+ insert-template = <&template_3>;
+ };
+ };
+};
diff --git a/tools/buildman/func_test.py b/tools/buildman/func_test.py
index d779040c74e..b45eb95a1e6 100644
--- a/tools/buildman/func_test.py
+++ b/tools/buildman/func_test.py
@@ -288,11 +288,11 @@ class TestFunctional(unittest.TestCase):
"""Test gitutils.Setup(), from outside the module itself"""
command.TEST_RESULT = command.CommandResult(return_code=1)
gitutil.setup()
- self.assertEqual(gitutil.use_no_decorate, False)
+ self.assertEqual(gitutil.USE_NO_DECORATE, False)
command.TEST_RESULT = command.CommandResult(return_code=0)
gitutil.setup()
- self.assertEqual(gitutil.use_no_decorate, True)
+ self.assertEqual(gitutil.USE_NO_DECORATE, True)
def _HandleCommandGitLog(self, args):
if args[-1] == '--':
diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile
index 569912303fc..a0fd174ff60 100644
--- a/tools/docker/Dockerfile
+++ b/tools/docker/Dockerfile
@@ -2,7 +2,7 @@
# This Dockerfile is used to build an image containing basic stuff to be used
# to build U-Boot and run our test suites.
-FROM ubuntu:jammy-20240911.1
+FROM ubuntu:jammy-20250404
LABEL org.opencontainers.image.authors="Tom Rini <trini@konsulko.com>"
LABEL org.opencontainers.image.description=" This image is for building U-Boot inside a container"
@@ -23,7 +23,7 @@ ENV ARCHS="aarch64 arc i386 m68k mips microblaze nios2 powerpc riscv64 riscv32 s
ENV MIRROR=https://mirrors.edge.kernel.org/pub/tools/crosstool/files/bin
# Toolchain version
-ENV TCVER=13.2.0
+ENV TCVER=14.2.0
RUN echo "Building on $BUILDPLATFORM, for target $TARGETPLATFORM"
@@ -32,7 +32,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update && apt-get install -y gnupg2 wget xz-utils
RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
-RUN echo deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main | tee /etc/apt/sources.list.d/llvm.list
+RUN echo deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-18 main | tee /etc/apt/sources.list.d/llvm.list
# Create a list of URLs to process, then pass them into a 'while read' loop
RUN if [ "$TARGETPLATFORM" = "linux/amd64" ]; then HOSTARCH=x86_64; else HOSTARCH=arm64; fi; ( \
@@ -64,8 +64,9 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
binutils-dev \
bison \
build-essential \
+ byacc \
cgpt \
- clang-17 \
+ clang-18 \
coreutils \
cpio \
curl \
@@ -74,8 +75,10 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
e2fsprogs \
efitools \
erofs-utils \
+ exfatprogs \
expect \
fakeroot \
+ fdisk \
flex \
gawk \
gdisk \
@@ -91,7 +94,6 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
libconfuse-dev \
libgit2-dev \
libjson-glib-dev \
- libguestfs-tools \
libgnutls28-dev \
libgnutls30 \
liblz4-tool \
@@ -105,7 +107,6 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
libtool \
libudev-dev \
libusb-1.0-0-dev \
- linux-image-generic \
lzma-alone \
lzop \
mount \
@@ -142,9 +143,6 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
xxd \
zip
-# Make kernels readable for libguestfs tools to work correctly
-RUN chmod +r /boot/vmlinu*
-
# Build GRUB UEFI targets for ARM & RISC-V, 32-bit and 64-bit
RUN git clone git://git.savannah.gnu.org/grub.git /tmp/grub && \
cd /tmp/grub && \
@@ -181,7 +179,7 @@ RUN git clone git://git.savannah.gnu.org/grub.git /tmp/grub && \
search search_fs_file search_fs_uuid search_label serial sleep test \
true && \
make clean && \
- ./configure --target=riscv64 --with-platform=efi \
+ grub_cv_cc_mcmodel=no ./configure --target=riscv64 --with-platform=efi \
CC=gcc \
TARGET_CC=/opt/gcc-${TCVER}-nolibc/riscv64-linux/bin/riscv64-linux-gcc \
TARGET_OBJCOPY=/opt/gcc-${TCVER}-nolibc/riscv64-linux/bin/riscv64-linux-objcopy \
@@ -234,13 +232,16 @@ RUN git clone https://gitlab.com/qemu-project/qemu.git /tmp/qemu && \
# Build fiptool
RUN git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git /tmp/tf-a && \
cd /tmp/tf-a/ && \
- git checkout v2.10.0 && \
+ git checkout v2.12.0 && \
cd tools/fiptool && \
make -j$(nproc) && \
mkdir -p /usr/local/bin && \
cp fiptool /usr/local/bin && \
rm -rf /tmp/tf-a
+# Download the Arm Architecture FVP platform. This file is double compressed.
+RUN wget -O - https://developer.arm.com/-/cdn-downloads/permalink/FVPs-Architecture/FM-11.28/FVP_Base_RevC-2xAEMvA_11.28_23_Linux64.tgz | gunzip -dc | tar -C /opt -x
+
# Build genimage (required by some targets to generate disk images)
RUN wget -O - https://github.com/pengutronix/genimage/releases/download/v14/genimage-14.tar.xz | tar -C /tmp -xJ && \
cd /tmp/genimage-14 && \
diff --git a/tools/patman/control.py b/tools/patman/control.py
index fb5a4246ced..b8a45912058 100644
--- a/tools/patman/control.py
+++ b/tools/patman/control.py
@@ -63,7 +63,8 @@ def prepare_patches(col, branch, count, start, end, ignore_binary, signoff,
branch, start, to_do, ignore_binary, series, signoff)
# Fix up the patch files to our liking, and insert the cover letter
- patchstream.fix_patches(series, patch_files, keep_change_id)
+ patchstream.fix_patches(series, patch_files, keep_change_id,
+ insert_base_commit=not cover_fname)
if cover_fname and series.get('cover'):
patchstream.insert_cover_letter(cover_fname, series, to_do)
return series, cover_fname, patch_files
diff --git a/tools/patman/func_test.py b/tools/patman/func_test.py
index bf333dc557b..720746e21f5 100644
--- a/tools/patman/func_test.py
+++ b/tools/patman/func_test.py
@@ -216,6 +216,8 @@ class TestFunctional(unittest.TestCase):
text = self._get_text('test01.txt')
series = patchstream.get_metadata_for_test(text)
+ series.base_commit = Commit('1a44532')
+ series.branch = 'mybranch'
cover_fname, args = self._create_patches_for_test(series)
get_maintainer_script = str(pathlib.Path(__file__).parent.parent.parent
/ 'get_maintainer.pl') + ' --norolestats'
@@ -308,6 +310,8 @@ Simon Glass (2):
--\x20
2.7.4
+base-commit: 1a44532
+branch: mybranch
'''
lines = open(cover_fname, encoding='utf-8').read().splitlines()
self.assertEqual(
@@ -353,6 +357,31 @@ Changes in v2:
expected = expected.splitlines()
self.assertEqual(expected, lines[start:(start+len(expected))])
+ def test_base_commit(self):
+ """Test adding a base commit with no cover letter"""
+ orig_text = self._get_text('test01.txt')
+ pos = orig_text.index('commit 5ab48490f03051875ab13d288a4bf32b507d76fd')
+ text = orig_text[:pos]
+ series = patchstream.get_metadata_for_test(text)
+ series.base_commit = Commit('1a44532')
+ series.branch = 'mybranch'
+ cover_fname, args = self._create_patches_for_test(series)
+ self.assertFalse(cover_fname)
+ with capture_sys_output() as out:
+ patchstream.fix_patches(series, args, insert_base_commit=True)
+ self.assertEqual('Cleaned 1 patch\n', out[0].getvalue())
+ lines = tools.read_file(args[0], binary=False).splitlines()
+ pos = lines.index('-- ')
+
+ # We expect these lines at the end:
+ # -- (with trailing space)
+ # 2.7.4
+ # (empty)
+ # base-commit: xxx
+ # branch: xxx
+ self.assertEqual('base-commit: 1a44532', lines[pos + 3])
+ self.assertEqual('branch: mybranch', lines[pos + 4])
+
def make_commit_with_file(self, subject, body, fname, text):
"""Create a file and add it to the git repo with a new commit
@@ -511,12 +540,23 @@ complicated as possible''')
# Check that it can detect a different branch
self.assertEqual(3, gitutil.count_commits_to_branch('second'))
with capture_sys_output() as _:
- _, cover_fname, patch_files = control.prepare_patches(
+ series, cover_fname, patch_files = control.prepare_patches(
col, branch='second', count=-1, start=0, end=0,
ignore_binary=False, signoff=True)
self.assertIsNotNone(cover_fname)
self.assertEqual(3, len(patch_files))
+ cover = tools.read_file(cover_fname, binary=False)
+ lines = cover.splitlines()[-2:]
+ base = repo.lookup_reference('refs/heads/base').target
+ self.assertEqual(f'base-commit: {base}', lines[0])
+ self.assertEqual('branch: second', lines[1])
+
+ # Make sure that the base-commit is not present when it is in the
+ # cover letter
+ for fname in patch_files:
+ self.assertNotIn(b'base-commit:', tools.read_file(fname))
+
# Check that it can skip patches at the end
with capture_sys_output() as _:
_, cover_fname, patch_files = control.prepare_patches(
@@ -524,6 +564,13 @@ complicated as possible''')
ignore_binary=False, signoff=True)
self.assertIsNotNone(cover_fname)
self.assertEqual(2, len(patch_files))
+
+ cover = tools.read_file(cover_fname, binary=False)
+ lines = cover.splitlines()[-2:]
+ base2 = repo.lookup_reference('refs/heads/second')
+ ref = base2.peel(pygit2.GIT_OBJ_COMMIT).parents[0].parents[0].id
+ self.assertEqual(f'base-commit: {ref}', lines[0])
+ self.assertEqual('branch: second', lines[1])
finally:
os.chdir(orig_dir)
diff --git a/tools/patman/patchstream.py b/tools/patman/patchstream.py
index 490d382045b..7a695c37c27 100644
--- a/tools/patman/patchstream.py
+++ b/tools/patman/patchstream.py
@@ -76,8 +76,13 @@ class PatchStream:
are interested in. We can also process a patch file in order to remove
unwanted tags or inject additional ones. These correspond to the two
phases of processing.
+
+ Args:
+ keep_change_id (bool): Keep the Change-Id tag
+ insert_base_commit (bool): True to add the base commit to the end
"""
- def __init__(self, series, is_log=False, keep_change_id=False):
+ def __init__(self, series, is_log=False, keep_change_id=False,
+ insert_base_commit=False):
self.skip_blank = False # True to skip a single blank line
self.found_test = False # Found a TEST= line
self.lines_after_test = 0 # Number of lines found after TEST=
@@ -103,6 +108,7 @@ class PatchStream:
self.recent_quoted = collections.deque([], 5)
self.recent_unquoted = queue.Queue()
self.was_quoted = None
+ self.insert_base_commit = insert_base_commit
@staticmethod
def process_text(text, is_comment=False):
@@ -658,6 +664,13 @@ class PatchStream:
outfd.write(line + '\n')
self.blank_count = 0
self.finalise()
+ if self.insert_base_commit:
+ if self.series.base_commit:
+ print(f'base-commit: {self.series.base_commit.hash}',
+ file=outfd)
+ if self.series.branch:
+ print(f'branch: {self.series.branch}', file=outfd)
+
def insert_tags(msg, tags_to_emit):
"""Add extra tags to a commit message
@@ -755,8 +768,12 @@ def get_metadata(branch, start, count):
Returns:
Series: Object containing information about the commits.
"""
- return get_metadata_for_list(
- '%s~%d' % (branch if branch else 'HEAD', start), None, count)
+ top = f"{branch if branch else 'HEAD'}~{start}"
+ series = get_metadata_for_list(top, None, count)
+ series.base_commit = commit.Commit(gitutil.get_hash(f'{top}~{count}'))
+ series.branch = branch or gitutil.get_branch()
+ series.top = top
+ return series
def get_metadata_for_test(text):
"""Process metadata from a file containing a git log. Used for tests
@@ -774,7 +791,8 @@ def get_metadata_for_test(text):
pst.finalise()
return series
-def fix_patch(backup_dir, fname, series, cmt, keep_change_id=False):
+def fix_patch(backup_dir, fname, series, cmt, keep_change_id=False,
+ insert_base_commit=False):
"""Fix up a patch file, by adding/removing as required.
We remove our tags from the patch file, insert changes lists, etc.
@@ -788,6 +806,7 @@ def fix_patch(backup_dir, fname, series, cmt, keep_change_id=False):
series (Series): Series information about this patch set
cmt (Commit): Commit object for this patch file
keep_change_id (bool): Keep the Change-Id tag.
+ insert_base_commit (bool): True to add the base commit to the end
Return:
list: A list of errors, each str, or [] if all ok.
@@ -795,7 +814,8 @@ def fix_patch(backup_dir, fname, series, cmt, keep_change_id=False):
handle, tmpname = tempfile.mkstemp()
outfd = os.fdopen(handle, 'w', encoding='utf-8')
infd = open(fname, 'r', encoding='utf-8')
- pst = PatchStream(series, keep_change_id=keep_change_id)
+ pst = PatchStream(series, keep_change_id=keep_change_id,
+ insert_base_commit=insert_base_commit)
pst.commit = cmt
pst.process_stream(infd, outfd)
infd.close()
@@ -807,7 +827,7 @@ def fix_patch(backup_dir, fname, series, cmt, keep_change_id=False):
shutil.move(tmpname, fname)
return cmt.warn
-def fix_patches(series, fnames, keep_change_id=False):
+def fix_patches(series, fnames, keep_change_id=False, insert_base_commit=False):
"""Fix up a list of patches identified by filenames
The patch files are processed in place, and overwritten.
@@ -816,6 +836,7 @@ def fix_patches(series, fnames, keep_change_id=False):
series (Series): The Series object
fnames (:type: list of str): List of patch files to process
keep_change_id (bool): Keep the Change-Id tag.
+ insert_base_commit (bool): True to add the base commit to the end
"""
# Current workflow creates patches, so we shouldn't need a backup
backup_dir = None #tempfile.mkdtemp('clean-patch')
@@ -825,7 +846,8 @@ def fix_patches(series, fnames, keep_change_id=False):
cmt.patch = fname
cmt.count = count
result = fix_patch(backup_dir, fname, series, cmt,
- keep_change_id=keep_change_id)
+ keep_change_id=keep_change_id,
+ insert_base_commit=insert_base_commit)
if result:
print('%d warning%s for %s:' %
(len(result), 's' if len(result) > 1 else '', fname))
@@ -868,4 +890,11 @@ def insert_cover_letter(fname, series, count):
out = series.MakeChangeLog(None)
line += '\n' + '\n'.join(out)
fil.write(line)
+
+ # Insert the base commit and branch
+ if series.base_commit:
+ print(f'base-commit: {series.base_commit.hash}', file=fil)
+ if series.branch:
+ print(f'branch: {series.branch}', file=fil)
+
fil.close()
diff --git a/tools/patman/series.py b/tools/patman/series.py
index d7f2f010f5d..b73e9c58de4 100644
--- a/tools/patman/series.py
+++ b/tools/patman/series.py
@@ -42,6 +42,8 @@ class Series(dict):
self.notes = []
self.changes = {}
self.allow_overwrite = False
+ self.base_commit = None
+ self.branch = None
# Written in MakeCcFile()
# key: name of patch file
diff --git a/tools/u_boot_pylib/gitutil.py b/tools/u_boot_pylib/gitutil.py
index 6d6a7eedecc..0376bece3e6 100644
--- a/tools/u_boot_pylib/gitutil.py
+++ b/tools/u_boot_pylib/gitutil.py
@@ -10,7 +10,7 @@ from u_boot_pylib import command
from u_boot_pylib import terminal
# True to use --no-decorate - we check this in setup()
-use_no_decorate = True
+USE_NO_DECORATE = True
def log_cmd(commit_range, git_dir=None, oneline=False, reverse=False,
@@ -18,11 +18,11 @@ def log_cmd(commit_range, git_dir=None, oneline=False, reverse=False,
"""Create a command to perform a 'git log'
Args:
- commit_range: Range expression to use for log, None for none
- git_dir: Path to git repository (None to use default)
- oneline: True to use --oneline, else False
- reverse: True to reverse the log (--reverse)
- count: Number of commits to list, or None for no limit
+ commit_range (str): Range expression to use for log, None for none
+ git_dir (str): Path to git repository (None to use default)
+ 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
Return:
List containing command and arguments to run
"""
@@ -32,12 +32,12 @@ 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:
cmd.append('--no-decorate')
if reverse:
cmd.append('--reverse')
if count is not None:
- cmd.append('-n%d' % count)
+ cmd.append(f'-n{count}')
if commit_range:
cmd.append(commit_range)
@@ -55,22 +55,22 @@ def count_commits_to_branch(branch):
since then.
Args:
- branch: Branch to count from (None for current branch)
+ branch (str or None): Branch to count from (None for current branch)
Return:
Number of patches that exist on top of the branch
"""
if branch:
- us, msg = get_upstream('.git', branch)
- rev_range = '%s..%s' % (us, branch)
+ us, _ = get_upstream('.git', branch)
+ rev_range = f'{us}..{branch}'
else:
rev_range = '@{upstream}..'
cmd = log_cmd(rev_range, oneline=True)
result = command.run_one(*cmd, capture=True, capture_stderr=True,
oneline=True, raise_on_error=False)
if result.return_code:
- raise ValueError('Failed to determine upstream: %s' %
- result.stderr.strip())
+ raise ValueError(
+ f'Failed to determine upstream: {result.stderr.strip()}')
patch_count = len(result.stdout.splitlines())
return patch_count
@@ -79,7 +79,7 @@ def name_revision(commit_hash):
"""Gets the revision name for a commit
Args:
- commit_hash: Commit hash to look up
+ commit_hash (str): Commit hash to look up
Return:
Name of revision, if any, else None
@@ -99,8 +99,8 @@ def guess_upstream(git_dir, branch):
'git name-rev' returns a plain branch name, with no ! or ^ modifiers.
Args:
- git_dir: Git directory containing repo
- branch: Name of branch
+ git_dir (str): Git directory containing repo
+ branch (str): Name of branch
Returns:
Tuple:
@@ -111,23 +111,23 @@ def guess_upstream(git_dir, branch):
result = command.run_one(*cmd, capture=True, capture_stderr=True,
raise_on_error=False)
if result.return_code:
- return None, "Branch '%s' not found" % branch
+ 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, "Guessing upstream as '%s'" % name
- return None, "Cannot find a suitable upstream for branch '%s'" % branch
+ return name, f"Guessing upstream as '{name}'"
+ return None, f"Cannot find a suitable upstream for branch '{branch}'"
def get_upstream(git_dir, branch):
"""Returns the name of the upstream for a branch
Args:
- git_dir: Git directory containing repo
- branch: Name of branch
+ git_dir (str): Git directory containing repo
+ branch (str): Name of branch
Returns:
Tuple:
@@ -136,31 +136,30 @@ def get_upstream(git_dir, branch):
"""
try:
remote = command.output_one_line('git', '--git-dir', git_dir, 'config',
- 'branch.%s.remote' % branch)
+ f'branch.{branch}.remote')
merge = command.output_one_line('git', '--git-dir', git_dir, 'config',
- 'branch.%s.merge' % branch)
+ f'branch.{branch}.merge')
except command.CommandExc:
upstream, msg = guess_upstream(git_dir, branch)
return upstream, msg
if remote == '.':
return merge, None
- elif remote and merge:
+ if remote and merge:
# Drop the initial refs/heads from merge
leaf = merge.split('/', maxsplit=2)[2:]
- return '%s/%s' % (remote, '/'.join(leaf)), None
- else:
- raise ValueError("Cannot determine upstream branch for branch "
- "'%s' remote='%s', merge='%s'"
- % (branch, remote, merge))
+ return f'{remote}/{"/".join(leaf)}', None
+ raise ValueError("Cannot determine upstream branch for branch "
+ f"'{branch}' remote='{remote}', merge='{merge}'")
def get_range_in_branch(git_dir, branch, include_upstream=False):
"""Returns an expression for the commits in the given branch.
Args:
- git_dir: Directory containing git repo
- branch: Name of branch
+ git_dir (str): Directory containing git repo
+ branch (str): Name of branch
+ include_upstream (bool): Include the upstream commit as well
Return:
Expression in the form 'upstream..branch' which can be used to
access the commits. If the branch does not exist, returns None.
@@ -168,7 +167,7 @@ def get_range_in_branch(git_dir, branch, include_upstream=False):
upstream, msg = get_upstream(git_dir, branch)
if not upstream:
return None, msg
- rstr = '%s%s..%s' % (upstream, '~' if include_upstream else '', branch)
+ rstr = f"{upstream}{'~' if include_upstream else ''}..{branch}"
return rstr, msg
@@ -176,8 +175,8 @@ def count_commits_in_range(git_dir, range_expr):
"""Returns the number of commits in the given range.
Args:
- git_dir: Directory containing git repo
- range_expr: Range to check
+ git_dir (str): Directory containing git repo
+ range_expr (str): Range to check
Return:
Number of patches that exist in the supplied range or None if none
were found
@@ -186,7 +185,7 @@ def count_commits_in_range(git_dir, range_expr):
result = command.run_one(*cmd, capture=True, capture_stderr=True,
raise_on_error=False)
if result.return_code:
- return None, "Range '%s' not found or is invalid" % range_expr
+ return None, f"Range '{range_expr}' not found or is invalid"
patch_count = len(result.stdout.splitlines())
return patch_count, None
@@ -195,8 +194,9 @@ def count_commits_in_branch(git_dir, branch, include_upstream=False):
"""Returns the number of commits in the given branch.
Args:
- git_dir: Directory containing git repo
- branch: Name of branch
+ git_dir (str): Directory containing git repo
+ branch (str): Name of branch
+ include_upstream (bool): Include the upstream commit as well
Return:
Number of patches that exist on top of the branch, or None if the
branch does not exist.
@@ -211,7 +211,7 @@ def count_commits(commit_range):
"""Returns the number of commits in the given range.
Args:
- commit_range: Range of commits to count (e.g. 'HEAD..base')
+ commit_range (str): Range of commits to count (e.g. 'HEAD..base')
Return:
Number of patches that exist on top of the branch
"""
@@ -226,7 +226,10 @@ def checkout(commit_hash, git_dir=None, work_tree=None, force=False):
"""Checkout the selected commit for this build
Args:
- commit_hash: Commit hash to check out
+ commit_hash (str): Commit hash to check out
+ git_dir (str): Directory containing git repo, or None for current dir
+ work_tree (str): Git worktree to use, or None if none
+ force (bool): True to force the checkout (git checkout -f)
"""
pipe = ['git']
if git_dir:
@@ -240,26 +243,28 @@ def checkout(commit_hash, git_dir=None, work_tree=None, force=False):
result = command.run_pipe([pipe], capture=True, raise_on_error=False,
capture_stderr=True)
if result.return_code != 0:
- raise OSError('git checkout (%s): %s' % (pipe, result.stderr))
+ raise OSError(f'git checkout ({pipe}): {result.stderr}')
-def clone(git_dir, output_dir):
- """Checkout the selected commit for this build
+def clone(repo, output_dir):
+ """Clone a repo
Args:
- commit_hash: Commit hash to check out
+ repo (str): Repo to clone (e.g. web address)
+ output_dir (str): Directory to close into
"""
- result = command.run_one('git', 'clone', git_dir, '.', capture=True,
+ result = command.run_one('git', 'clone', repo, '.', capture=True,
cwd=output_dir, capture_stderr=True)
if result.return_code != 0:
- raise OSError('git clone: %s' % result.stderr)
+ raise OSError(f'git clone: {result.stderr}')
def fetch(git_dir=None, work_tree=None):
"""Fetch from the origin repo
Args:
- commit_hash: Commit hash to check out
+ git_dir (str): Directory containing git repo, or None for current dir
+ work_tree (str or None): Git worktree to use, or None if none
"""
cmd = ['git']
if git_dir:
@@ -269,14 +274,14 @@ def fetch(git_dir=None, work_tree=None):
cmd.append('fetch')
result = command.run_one(*cmd, capture=True, capture_stderr=True)
if result.return_code != 0:
- raise OSError('git fetch: %s' % result.stderr)
+ raise OSError(f'git fetch: {result.stderr}')
def check_worktree_is_available(git_dir):
"""Check if git-worktree functionality is available
Args:
- git_dir: The repository to test in
+ git_dir (str): The repository to test in
Returns:
True if git-worktree commands will work, False otherwise.
@@ -291,9 +296,9 @@ def add_worktree(git_dir, output_dir, commit_hash=None):
"""Create and checkout a new git worktree for this build
Args:
- git_dir: The repository to checkout the worktree from
- output_dir: Path for the new worktree
- commit_hash: Commit hash to checkout
+ git_dir (str): The repository to checkout the worktree from
+ output_dir (str): Path for the new worktree
+ commit_hash (str): Commit hash to checkout
"""
# We need to pass --detach to avoid creating a new branch
cmd = ['git', '--git-dir', git_dir, 'worktree', 'add', '.', '--detach']
@@ -302,19 +307,19 @@ def add_worktree(git_dir, output_dir, commit_hash=None):
result = command.run_one(*cmd, capture=True, cwd=output_dir,
capture_stderr=True)
if result.return_code != 0:
- raise OSError('git worktree add: %s' % result.stderr)
+ raise OSError(f'git worktree add: {result.stderr}')
def prune_worktrees(git_dir):
"""Remove administrative files for deleted worktrees
Args:
- git_dir: The repository whose deleted worktrees should be pruned
+ git_dir (str): The repository whose deleted worktrees should be pruned
"""
result = command.run_one('git', '--git-dir', git_dir, 'worktree', 'prune',
capture=True, capture_stderr=True)
if result.return_code != 0:
- raise OSError('git worktree prune: %s' % result.stderr)
+ raise OSError(f'git worktree prune: {result.stderr}')
def create_patches(branch, start, count, ignore_binary, series, signoff=True):
@@ -324,11 +329,12 @@ def create_patches(branch, start, count, ignore_binary, series, signoff=True):
git format-patch.
Args:
- branch: Branch to create patches from (None for current branch)
- start: Commit to start from: 0=HEAD, 1=next one, etc.
- count: number of commits to include
- ignore_binary: Don't generate patches for binary files
- series: Series object for this series (set of patches)
+ branch (str): Branch to create patches from (None for current branch)
+ start (int): Commit to start from: 0=HEAD, 1=next one, etc.
+ count (int): number of commits to include
+ 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
Return:
Filename of cover letter (None if none)
List of filenames of patch files
@@ -342,9 +348,9 @@ def create_patches(branch, start, count, ignore_binary, series, signoff=True):
cmd.append('--cover-letter')
prefix = series.GetPatchPrefix()
if prefix:
- cmd += ['--subject-prefix=%s' % prefix]
+ cmd += [f'--subject-prefix={prefix}']
brname = branch or 'HEAD'
- cmd += ['%s~%d..%s~%d' % (brname, start + count, brname, start)]
+ cmd += [f'{brname}~{start + count}..{brname}~{start}']
stdout = command.run_list(cmd)
files = stdout.splitlines()
@@ -352,8 +358,7 @@ def create_patches(branch, start, count, ignore_binary, series, signoff=True):
# We have an extra file if there is a cover letter
if series.get('cover'):
return files[0], files[1:]
- else:
- return None, files
+ return None, files
def build_email_list(in_list, tag=None, alias=None, warn_on_error=True):
@@ -367,11 +372,13 @@ def build_email_list(in_list, tag=None, alias=None, warn_on_error=True):
command line parameter) then the email address is quoted.
Args:
- in_list: List of aliases/email addresses
- tag: Text to put before each address
- alias: Alias dictionary
- warn_on_error: True to raise an error when an alias fails to match,
- False to just print a message.
+ 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
+ warn_on_error (bool): True to raise an error when an alias fails to
+ match, False to just print a message.
Returns:
List of email addresses
@@ -399,7 +406,7 @@ def build_email_list(in_list, tag=None, alias=None, warn_on_error=True):
if item not in result:
result.append(item)
if tag:
- return ['%s %s%s%s' % (tag, quote, email, quote) for email in result]
+ return [f'{tag} {quote}{email}{quote}' for email in result]
return result
@@ -407,24 +414,23 @@ def check_suppress_cc_config():
"""Check if sendemail.suppresscc is configured correctly.
Returns:
- True if the option is configured correctly, False otherwise.
+ bool: True if the option is configured correctly, False otherwise.
"""
suppresscc = command.output_one_line(
'git', 'config', 'sendemail.suppresscc', raise_on_error=False)
# Other settings should be fine.
- if suppresscc == 'all' or suppresscc == 'cccmd':
+ if suppresscc in ('all', 'cccmd'):
col = terminal.Color()
- print((col.build(col.RED, "error") +
- ": git config sendemail.suppresscc set to %s\n"
- % (suppresscc)) +
- " patman needs --cc-cmd to be run to set the cc list.\n" +
- " Please run:\n" +
- " git config --unset sendemail.suppresscc\n" +
- " Or read the man page:\n" +
- " git send-email --help\n" +
- " and set an option that runs --cc-cmd\n")
+ print(col.build(col.RED, 'error') +
+ f': git config sendemail.suppresscc set to {suppresscc}\n' +
+ ' patman needs --cc-cmd to be run to set the cc list.\n' +
+ ' Please run:\n' +
+ ' git config --unset sendemail.suppresscc\n' +
+ ' Or read the man page:\n' +
+ ' git send-email --help\n' +
+ ' and set an option that runs --cc-cmd\n')
return False
return True
@@ -432,24 +438,26 @@ 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,
- smtp_server=None, get_maintainer_script=None):
+ smtp_server=None):
"""Email a patch series.
Args:
- series: Series object containing destination info
- cover_fname: filename of cover letter
- args: list of filenames of patch files
- dry_run: Just return the command that would be run
- warn_on_error: True to print a warning when an alias fails to match,
- False to ignore it.
- cc_fname: Filename of Cc file for per-commit Cc
- self_only: True to just email to yourself as a test
- in_reply_to: If set we'll pass this to git as --in-reply-to.
- Should be a message ID that this is in reply to.
- thread: True to add --thread to git send-email (make
+ series (Series): Series object containing destination info
+ cover_fname (str or None): filename of cover letter
+ args (list of str): list of filenames of patch files
+ dry_run (bool): Just return the command that would be run
+ 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)
+ key: alias
+ value: list of aliases or email addresses
+ 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
all patches reply to cover-letter or first patch in series)
- smtp_server: SMTP server to use to send patches
- get_maintainer_script: File name of script to get maintainers emails
+ smtp_server (str or None): SMTP server to use to send patches
Returns:
Git command that was/would be run
@@ -500,7 +508,7 @@ send --cc-cmd cc-fname" cover p1 p2'
"Series-to: Fred Bloggs <f.blogs@napier.co.nz>\n"
"Or do something like this\n"
"git config sendemail.to u-boot@lists.denx.de")
- return
+ return None
cc = build_email_list(list(set(series.get('cc')) - set(series.get('to'))),
'--cc', alias, warn_on_error)
if self_only:
@@ -509,15 +517,15 @@ send --cc-cmd cc-fname" cover p1 p2'
cc = []
cmd = ['git', 'send-email', '--annotate']
if smtp_server:
- cmd.append('--smtp-server=%s' % smtp_server)
+ cmd.append(f'--smtp-server={smtp_server}')
if in_reply_to:
- cmd.append('--in-reply-to="%s"' % in_reply_to)
+ cmd.append(f'--in-reply-to="{in_reply_to}"')
if thread:
cmd.append('--thread')
cmd += to
cmd += cc
- cmd += ['--cc-cmd', '"%s send --cc-cmd %s"' % (sys.argv[0], cc_fname)]
+ cmd += ['--cc-cmd', f'"{sys.argv[0]} send --cc-cmd {cc_fname}"']
if cover_fname:
cmd.append(cover_fname)
cmd += args
@@ -533,10 +541,13 @@ def lookup_email(lookup_name, alias=None, warn_on_error=True, level=0):
TODO: Why not just use git's own alias feature?
Args:
- lookup_name: Alias or email address to look up
- alias: Dictionary containing aliases (None to use settings default)
- warn_on_error: True to print a warning when an alias fails to match,
- False to ignore it.
+ lookup_name (str): Alias or email address to look up
+ alias (dict or None): Alias dictionary: (None to use settings default)
+ key: alias
+ value: list of aliases or email addresses
+ warn_on_error (bool): True to print a warning when an alias fails to
+ match, False to ignore it.
+ level (int): Depth of alias stack, used to detect recusion/loops
Returns:
tuple:
@@ -589,16 +600,15 @@ def lookup_email(lookup_name, alias=None, warn_on_error=True, level=0):
out_list = []
if level > 10:
- msg = "Recursive email alias at '%s'" % lookup_name
+ msg = f"Recursive email alias at '{lookup_name}'"
if warn_on_error:
raise OSError(msg)
- else:
- print(col.build(col.RED, msg))
- return out_list
+ print(col.build(col.RED, msg))
+ return out_list
if lookup_name:
if lookup_name not in alias:
- msg = "Alias '%s' not found" % lookup_name
+ msg = f"Alias '{lookup_name}' not found"
if warn_on_error:
print(col.build(col.RED, msg))
return out_list
@@ -615,7 +625,7 @@ def get_top_level():
"""Return name of top-level directory for this git repo.
Returns:
- Full path to git top-level directory
+ str: Full path to git top-level directory
This test makes sure that we are running tests in the right subdir
@@ -630,7 +640,7 @@ def get_alias_file():
"""Gets the name of the git alias file.
Returns:
- Filename of git alias file, or None if none
+ str: Filename of git alias file, or None if none
"""
fname = command.output_one_line('git', 'config', 'sendemail.aliasesfile',
raise_on_error=False)
@@ -650,7 +660,8 @@ def get_default_user_name():
Returns:
User name found in .gitconfig file, or None if none
"""
- uname = command.output_one_line('git', 'config', '--global', '--includes', 'user.name')
+ uname = command.output_one_line('git', 'config', '--global', '--includes',
+ 'user.name')
return uname
@@ -660,7 +671,8 @@ def get_default_user_email():
Returns:
User's email found in .gitconfig file, or None if none
"""
- uemail = command.output_one_line('git', 'config', '--global', '--includes', 'user.email')
+ uemail = command.output_one_line('git', 'config', '--global', '--includes',
+ 'user.email')
return uemail
@@ -677,25 +689,50 @@ def get_default_subject_prefix():
def setup():
- """Set up git utils, by reading the alias files."""
+ """setup() - Set up git utils, by reading the alias files."""
# Check for a git alias file also
- global use_no_decorate
+ 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)
+ USE_NO_DECORATE = (command.run_one(*cmd, raise_on_error=False)
.return_code == 0)
+def get_hash(spec):
+ """Get the hash of a commit
+
+ Args:
+ spec (str): Git commit to show, e.g. 'my-branch~12'
+
+ Returns:
+ str: Hash of commit
+ """
+ return command.output_one_line('git', 'show', '-s', '--pretty=format:%H',
+ spec)
+
+
def get_head():
"""Get the hash of the current HEAD
Returns:
Hash of HEAD
"""
- return command.output_one_line('git', 'show', '-s', '--pretty=format:%H')
+ return get_hash('HEAD')
+
+
+def get_branch():
+ """Get the branch we are currently on
+
+ Return:
+ str: branch name, or None if none
+ """
+ out = command.output_one_line('git', 'rev-parse', '--abbrev-ref', 'HEAD')
+ if out == 'HEAD':
+ return None
+ return out
if __name__ == "__main__":