mirror of
https://github.com/AsahiLinux/u-boot
synced 2025-02-26 20:37:16 +00:00
patman correct import of u_boot_pylib
correct long-standing EFI framebuffer bug minor test refactor -----BEGIN PGP SIGNATURE----- iQFFBAABCgAvFiEEslwAIq+Gp8wWVbYnfxc6PpAIreYFAmVUxF0RHHNqZ0BjaHJv bWl1bS5vcmcACgkQfxc6PpAIreandwgAkAhSYyADGMtGzbGbWK1t4EvYryaRCKvk KwbAWjbAfK3xOr8lUviRDDNEn2T1UQKYLPf64h6e1ivMrpS1M9JW8N0dEttagk1R O4KLMFkbBZXbbVA/ovhBvEDSBVWCnj0bRSq5nKnoCRCZAtQJnRpQXAZlUz9WT+js zJqgVoNua44akYtqulpgX4O6/8SvecQBJoP0yIyQCbXSNSOr7zcADIxq9yJJ0KrC 4nFQ/qCvLsfrfeRX/NoSbEftX480fjyzpTFsp9XqvJPvtFQbzDUSaXSQ5QSUWNNl DrjNjUElqJv7cGSj73mm6yarVyRDygNyu49T/vgAvq3LwgNwdLuUqA== =tbfh -----END PGP SIGNATURE----- Merge tag 'dm-pull-15nov23' of https://source.denx.de/u-boot/custodians/u-boot-dm patman correct import of u_boot_pylib correct long-standing EFI framebuffer bug minor test refactor
This commit is contained in:
commit
169c3cc49e
12 changed files with 402 additions and 208 deletions
|
@ -219,7 +219,7 @@ int os_map_file(const char *pathname, int os_flags, void **bufp, int *sizep)
|
|||
{
|
||||
void *ptr;
|
||||
off_t size;
|
||||
int ifd;
|
||||
int ifd, ret = 0;
|
||||
|
||||
ifd = os_open(pathname, os_flags);
|
||||
if (ifd < 0) {
|
||||
|
@ -229,23 +229,28 @@ int os_map_file(const char *pathname, int os_flags, void **bufp, int *sizep)
|
|||
size = os_filesize(ifd);
|
||||
if (size < 0) {
|
||||
printf("Cannot get file size of '%s'\n", pathname);
|
||||
return -EIO;
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
if ((unsigned long long)size > (unsigned long long)SIZE_MAX) {
|
||||
printf("File '%s' too large to map\n", pathname);
|
||||
return -EIO;
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, ifd, 0);
|
||||
if (ptr == MAP_FAILED) {
|
||||
printf("Can't map file '%s': %s\n", pathname, strerror(errno));
|
||||
return -EPERM;
|
||||
ret = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*bufp = ptr;
|
||||
*sizep = size;
|
||||
|
||||
return 0;
|
||||
out:
|
||||
os_close(ifd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int os_unmap(void *buf, int size)
|
||||
|
|
|
@ -190,10 +190,12 @@ int expo_render(struct expo *exp)
|
|||
struct udevice *dev = exp->display;
|
||||
struct video_priv *vid_priv = dev_get_uclass_priv(dev);
|
||||
struct scene *scn = NULL;
|
||||
enum colour_idx back;
|
||||
u32 colour;
|
||||
int ret;
|
||||
|
||||
colour = video_index_to_colour(vid_priv, VID_WHITE);
|
||||
back = CONFIG_IS_ENABLED(SYS_WHITE_ON_BLACK) ? VID_BLACK : VID_WHITE;
|
||||
colour = video_index_to_colour(vid_priv, back);
|
||||
ret = video_fill(dev, colour);
|
||||
if (ret)
|
||||
return log_msg_ret("fill", ret);
|
||||
|
|
|
@ -89,6 +89,44 @@ static void show_footer(int count, int num_valid)
|
|||
num_valid);
|
||||
}
|
||||
|
||||
/**
|
||||
* bootflow_handle_menu() - Handle running the menu and updating cur bootflow
|
||||
*
|
||||
* This shows the menu, allows the user to select something and then prints
|
||||
* what happened
|
||||
*
|
||||
* @std: bootstd information
|
||||
* @text_mode: true to run the menu in text mode
|
||||
* @bflowp: Returns selected bootflow, on success
|
||||
* Return: 0 on success (a bootflow was selected), -EAGAIN if nothing was
|
||||
* chosen, other -ve value on other error
|
||||
*/
|
||||
__maybe_unused static int bootflow_handle_menu(struct bootstd_priv *std,
|
||||
bool text_mode,
|
||||
struct bootflow **bflowp)
|
||||
{
|
||||
struct bootflow *bflow;
|
||||
int ret;
|
||||
|
||||
ret = bootflow_menu_run(std, text_mode, &bflow);
|
||||
if (ret) {
|
||||
if (ret == -EAGAIN) {
|
||||
printf("Nothing chosen\n");
|
||||
std->cur_bootflow = NULL;
|
||||
} else {
|
||||
printf("Menu failed (err=%d)\n", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
printf("Selected: %s\n", bflow->os_name ? bflow->os_name : bflow->name);
|
||||
std->cur_bootflow = bflow;
|
||||
*bflowp = bflow;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc,
|
||||
char *const argv[])
|
||||
{
|
||||
|
@ -455,18 +493,9 @@ static int do_bootflow_menu(struct cmd_tbl *cmdtp, int flag, int argc,
|
|||
if (ret)
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
ret = bootflow_menu_run(std, text_mode, &bflow);
|
||||
if (ret) {
|
||||
if (ret == -EAGAIN)
|
||||
printf("Nothing chosen\n");
|
||||
else {
|
||||
printf("Menu failed (err=%d)\n", ret);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Selected: %s\n", bflow->os_name ? bflow->os_name : bflow->name);
|
||||
std->cur_bootflow = bflow;
|
||||
ret = bootflow_handle_menu(std, text_mode, &bflow);
|
||||
if (ret)
|
||||
return CMD_RET_FAILURE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@ ulong bootstage_add_record(enum bootstage_id id, const char *name,
|
|||
rec->flags = flags;
|
||||
rec->id = id;
|
||||
} else {
|
||||
log_warning("Bootstage space exhasuted\n");
|
||||
log_warning("Bootstage space exhausted\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ Synopis
|
|||
bootflow read
|
||||
bootflow boot
|
||||
bootflow cmdline [set|get|clear|delete|auto] <param> [<value>]
|
||||
bootfloe menu [-t]
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
@ -24,6 +25,9 @@ locate bootflows, list them and boot them.
|
|||
|
||||
See :doc:`../../develop/bootstd` for more information.
|
||||
|
||||
Note that `CONFIG_BOOTSTD_FULL` (which enables `CONFIG_CMD_BOOTFLOW_FULL) must
|
||||
be enabled to obtain full functionality with this command. Otherwise, it only
|
||||
supports `bootflow scan` which scans and boots the first available bootflow.
|
||||
|
||||
bootflow scan
|
||||
~~~~~~~~~~~~~
|
||||
|
@ -247,6 +251,16 @@ can be used to set the early console (or console) to a suitable value so that
|
|||
output appears on the serial port. This is only supported by the 16550 serial
|
||||
driver so far.
|
||||
|
||||
bootflow menu
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
This shows a menu with available bootflows. The user can select a particular
|
||||
bootflow, which then becomes the current one.
|
||||
|
||||
The `-t` flag requests a text menu. Otherwise, if a display is available, a
|
||||
graphical menu is shown.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
|
@ -658,6 +672,56 @@ Now the buffer can be accessed::
|
|||
77b7e4e0: 320fc000 08e8ba0f c031300f b8d0000f ...2.....01.....
|
||||
77b7e4f0: 00000020 6ad8000f 00858d10 50000002 ......j.......P
|
||||
|
||||
This shows using a text menu to boot an OS::
|
||||
|
||||
=> bootflow scan
|
||||
=> bootfl list
|
||||
=> bootfl menu -t
|
||||
U-Boot : Boot Menu
|
||||
|
||||
UP and DOWN to choose, ENTER to select
|
||||
|
||||
> 0 mmc1 mmc1.bootdev.whole
|
||||
1 mmc1 Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl)
|
||||
2 mmc1 mmc1.bootdev.part_1
|
||||
3 mmc4 mmc4.bootdev.whole
|
||||
4 mmc4 Armbian
|
||||
5 mmc4 mmc4.bootdev.part_1
|
||||
6 mmc5 mmc5.bootdev.whole
|
||||
7 mmc5 ChromeOS
|
||||
8 mmc5 ChromeOS
|
||||
U-Boot : Boot Menu
|
||||
|
||||
UP and DOWN to choose, ENTER to select
|
||||
|
||||
0 mmc1 mmc1.bootdev.whole
|
||||
> 1 mmc1 Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl)
|
||||
2 mmc1 mmc1.bootdev.part_1
|
||||
3 mmc4 mmc4.bootdev.whole
|
||||
4 mmc4 Armbian
|
||||
5 mmc4 mmc4.bootdev.part_1
|
||||
6 mmc5 mmc5.bootdev.whole
|
||||
7 mmc5 ChromeOS
|
||||
8 mmc5 ChromeOS
|
||||
U-Boot : Boot Menu
|
||||
|
||||
Selected: Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl)
|
||||
=> bootfl boot
|
||||
** Booting bootflow 'mmc1.bootdev.part_1' with extlinux
|
||||
Ignoring unknown command: ui
|
||||
Ignoring malformed menu command: autoboot
|
||||
Ignoring malformed menu command: hidden
|
||||
Ignoring unknown command: totaltimeout
|
||||
Fedora-Workstation-armhfp-31-1.9 Boot Options.
|
||||
1: Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl)
|
||||
Enter choice: 1
|
||||
1: Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl)
|
||||
Retrieving file: /vmlinuz-5.3.7-301.fc31.armv7hl
|
||||
Retrieving file: /initramfs-5.3.7-301.fc31.armv7hl.img
|
||||
append: ro root=UUID=9732b35b-4cd5-458b-9b91-80f7047e0b8a rhgb quiet LANG=en_US.UTF-8 cma=192MB cma=256MB
|
||||
Retrieving file: /dtb-5.3.7-301.fc31.armv7hl/sandbox.dtb
|
||||
...
|
||||
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
@ -667,6 +731,9 @@ return to U-Boot. If something about the U-Boot processing fails, then the
|
|||
return value $? is 1. If the boot succeeds but for some reason the Operating
|
||||
System returns, then $? is 0, indicating success.
|
||||
|
||||
For `bootflow menu` the return value is $? is 0 (true) if an option was choses,
|
||||
else 1.
|
||||
|
||||
For other subcommands, the return value $? is always 0 (true).
|
||||
|
||||
|
||||
|
|
|
@ -48,7 +48,6 @@ config VPL_DM
|
|||
config DM_WARN
|
||||
bool "Enable warnings in driver model"
|
||||
depends on DM
|
||||
default y
|
||||
help
|
||||
Enable this to see warnings related to driver model.
|
||||
|
||||
|
|
|
@ -11,9 +11,7 @@ struct dm_stats;
|
|||
#if CONFIG_IS_ENABLED(DM_WARN)
|
||||
#define dm_warn(fmt...) log(LOGC_DM, LOGL_WARNING, ##fmt)
|
||||
#else
|
||||
static inline void dm_warn(const char *fmt, ...)
|
||||
{
|
||||
}
|
||||
#define dm_warn(fmt...) log(LOGC_DM, LOGL_DEBUG, ##fmt)
|
||||
#endif
|
||||
|
||||
struct list_head;
|
||||
|
|
|
@ -21,9 +21,12 @@ struct udevice;
|
|||
* @align: Frame-buffer alignment, indicating the memory boundary the frame
|
||||
* buffer should start on. If 0, 1MB is assumed
|
||||
* @size: Frame-buffer size, in bytes
|
||||
* @base: Base address of frame buffer, 0 if not yet known
|
||||
* @copy_base: Base address of a hardware copy of the frame buffer. See
|
||||
* CONFIG_VIDEO_COPY.
|
||||
* @base: Base address of frame buffer, 0 if not yet known. If CONFIG_VIDEO_COPY
|
||||
* is enabled, this is the software copy, so writes to this will not be
|
||||
* visible until vidconsole_sync_copy() is called. If CONFIG_VIDEO_COPY is
|
||||
* disabled, this is the hardware framebuffer.
|
||||
* @copy_base: Base address of a hardware copy of the frame buffer. If
|
||||
* CONFIG_VIDEO_COPY is disabled, this is not used.
|
||||
* @copy_size: Size of copy framebuffer, used if @size is 0
|
||||
* @hide_logo: Hide the logo (used for testing)
|
||||
*/
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <efi_loader.h>
|
||||
#include <log.h>
|
||||
#include <malloc.h>
|
||||
#include <mapmem.h>
|
||||
#include <video.h>
|
||||
#include <asm/global_data.h>
|
||||
|
||||
|
@ -467,10 +468,10 @@ efi_status_t efi_gop_register(void)
|
|||
struct efi_gop_obj *gopobj;
|
||||
u32 bpix, format, col, row;
|
||||
u64 fb_base, fb_size;
|
||||
void *fb;
|
||||
efi_status_t ret;
|
||||
struct udevice *vdev;
|
||||
struct video_priv *priv;
|
||||
struct video_uc_plat *plat;
|
||||
|
||||
/* We only support a single video output device for now */
|
||||
if (uclass_first_device_err(UCLASS_VIDEO, &vdev)) {
|
||||
|
@ -483,9 +484,10 @@ efi_status_t efi_gop_register(void)
|
|||
format = priv->format;
|
||||
col = video_get_xsize(vdev);
|
||||
row = video_get_ysize(vdev);
|
||||
fb_base = (uintptr_t)priv->fb;
|
||||
fb_size = priv->fb_size;
|
||||
fb = priv->fb;
|
||||
|
||||
plat = dev_get_uclass_plat(vdev);
|
||||
fb_base = IS_ENABLED(CONFIG_VIDEO_COPY) ? plat->copy_base : plat->base;
|
||||
fb_size = plat->size;
|
||||
|
||||
switch (bpix) {
|
||||
case VIDEO_BPP16:
|
||||
|
@ -547,7 +549,7 @@ efi_status_t efi_gop_register(void)
|
|||
}
|
||||
gopobj->info.pixels_per_scanline = col;
|
||||
gopobj->bpix = bpix;
|
||||
gopobj->fb = fb;
|
||||
gopobj->fb = map_sysmem(fb_base, fb_size);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -511,19 +511,27 @@ BOOTSTD_TEST(bootflow_cmd_boot, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
|
|||
/**
|
||||
* prep_mmc_bootdev() - Set up an mmc bootdev so we can access other distros
|
||||
*
|
||||
* After calling this function, set std->bootdev_order to *@old_orderp to
|
||||
* restore normal operation of bootstd (i.e. with the original bootdev order)
|
||||
*
|
||||
* @uts: Unit test state
|
||||
* @mmc_dev: MMC device to use, e.g. "mmc4"
|
||||
* @mmc_dev: MMC device to use, e.g. "mmc4". Note that this must remain valid
|
||||
* in the caller until
|
||||
* @bind_cros: true to bind the ChromiumOS bootmeth
|
||||
* @old_orderp: Returns the original bootdev order, which must be restored
|
||||
* Returns 0 on success, -ve on failure
|
||||
*/
|
||||
static int prep_mmc_bootdev(struct unit_test_state *uts, const char *mmc_dev,
|
||||
bool bind_cros)
|
||||
bool bind_cros, const char ***old_orderp)
|
||||
{
|
||||
const char *order[] = {"mmc2", "mmc1", mmc_dev, NULL};
|
||||
static const char *order[] = {"mmc2", "mmc1", NULL, NULL};
|
||||
struct udevice *dev, *bootstd;
|
||||
struct bootstd_priv *std;
|
||||
const char **old_order;
|
||||
ofnode root, node;
|
||||
|
||||
order[2] = mmc_dev;
|
||||
|
||||
/* Enable the mmc4 node since we need a second bootflow */
|
||||
root = oftree_root(oftree_default());
|
||||
node = ofnode_find_subnode(root, mmc_dev);
|
||||
|
@ -546,26 +554,49 @@ static int prep_mmc_bootdev(struct unit_test_state *uts, const char *mmc_dev,
|
|||
std = dev_get_priv(bootstd);
|
||||
old_order = std->bootdev_order;
|
||||
std->bootdev_order = order;
|
||||
*old_orderp = old_order;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* scan_mmc_bootdev() - Set up an mmc bootdev so we can access other distros
|
||||
*
|
||||
* @uts: Unit test state
|
||||
* @mmc_dev: MMC device to use, e.g. "mmc4"
|
||||
* @bind_cros: true to bind the ChromiumOS bootmeth
|
||||
* Returns 0 on success, -ve on failure
|
||||
*/
|
||||
static int scan_mmc_bootdev(struct unit_test_state *uts, const char *mmc_dev,
|
||||
bool bind_cros)
|
||||
{
|
||||
struct bootstd_priv *std;
|
||||
struct udevice *bootstd;
|
||||
const char **old_order;
|
||||
|
||||
ut_assertok(prep_mmc_bootdev(uts, mmc_dev, bind_cros, &old_order));
|
||||
|
||||
console_record_reset_enable();
|
||||
ut_assertok(run_command("bootflow scan", 0));
|
||||
ut_assert_console_end();
|
||||
|
||||
/* Restore the order used by the device tree */
|
||||
ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd));
|
||||
std = dev_get_priv(bootstd);
|
||||
std->bootdev_order = old_order;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* prep_mmc4_bootdev() - Set up the mmc4 bootdev so we can access a fake Armbian
|
||||
* scan_mmc4_bootdev() - Set up the mmc4 bootdev so we can access a fake Armbian
|
||||
*
|
||||
* @uts: Unit test state
|
||||
* Returns 0 on success, -ve on failure
|
||||
*/
|
||||
static int prep_mmc4_bootdev(struct unit_test_state *uts)
|
||||
static int scan_mmc4_bootdev(struct unit_test_state *uts)
|
||||
{
|
||||
ut_assertok(prep_mmc_bootdev(uts, "mmc4", false));
|
||||
ut_assertok(scan_mmc_bootdev(uts, "mmc4", false));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -573,9 +604,13 @@ static int prep_mmc4_bootdev(struct unit_test_state *uts)
|
|||
/* Check 'bootflow menu' to select a bootflow */
|
||||
static int bootflow_cmd_menu(struct unit_test_state *uts)
|
||||
{
|
||||
struct bootstd_priv *std;
|
||||
char prev[3];
|
||||
|
||||
ut_assertok(prep_mmc4_bootdev(uts));
|
||||
/* get access to the current bootflow */
|
||||
ut_assertok(bootstd_get_priv(&std));
|
||||
|
||||
ut_assertok(scan_mmc4_bootdev(uts));
|
||||
|
||||
/* Add keypresses to move to and select the second one in the list */
|
||||
prev[0] = CTL_CH('n');
|
||||
|
@ -585,6 +620,17 @@ static int bootflow_cmd_menu(struct unit_test_state *uts)
|
|||
|
||||
ut_assertok(run_command("bootflow menu", 0));
|
||||
ut_assert_nextline("Selected: Armbian");
|
||||
ut_assertnonnull(std->cur_bootflow);
|
||||
ut_assert_console_end();
|
||||
|
||||
/* Check not selecting anything */
|
||||
prev[0] = '\e';
|
||||
prev[1] = '\0';
|
||||
ut_asserteq(1, console_in_puts(prev));
|
||||
|
||||
ut_asserteq(1, run_command("bootflow menu", 0));
|
||||
ut_assertnull(std->cur_bootflow);
|
||||
ut_assert_nextline("Nothing chosen");
|
||||
ut_assert_console_end();
|
||||
|
||||
return 0;
|
||||
|
@ -681,7 +727,7 @@ static int bootflow_menu_theme(struct unit_test_state *uts)
|
|||
ofnode node;
|
||||
int i;
|
||||
|
||||
ut_assertok(prep_mmc4_bootdev(uts));
|
||||
ut_assertok(scan_mmc4_bootdev(uts));
|
||||
|
||||
ut_assertok(bootflow_menu_new(&exp));
|
||||
node = ofnode_path("/bootstd/theme");
|
||||
|
@ -996,7 +1042,7 @@ BOOTSTD_TEST(bootflow_cmdline_special, 0);
|
|||
/* Test ChromiumOS bootmeth */
|
||||
static int bootflow_cros(struct unit_test_state *uts)
|
||||
{
|
||||
ut_assertok(prep_mmc_bootdev(uts, "mmc5", true));
|
||||
ut_assertok(scan_mmc_bootdev(uts, "mmc5", true));
|
||||
ut_assertok(run_command("bootflow list", 0));
|
||||
|
||||
ut_assert_nextlinen("Showing all");
|
||||
|
|
|
@ -6,197 +6,93 @@
|
|||
|
||||
"""See README for more information"""
|
||||
|
||||
from argparse import ArgumentParser
|
||||
try:
|
||||
import importlib.resources
|
||||
from importlib import resources
|
||||
except ImportError:
|
||||
# for Python 3.6
|
||||
import importlib_resources
|
||||
import importlib_resources as resources
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Allow 'from patman import xxx to work'
|
||||
our_path = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.append(os.path.join(our_path, '..'))
|
||||
# Allow 'from patman import xxx to work'
|
||||
# pylint: disable=C0413
|
||||
our_path = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.append(os.path.join(our_path, '..'))
|
||||
|
||||
# Our modules
|
||||
from patman import cmdline
|
||||
from patman import control
|
||||
from patman import func_test
|
||||
from patman import gitutil
|
||||
from patman import project
|
||||
from patman import settings
|
||||
from u_boot_pylib import terminal
|
||||
from u_boot_pylib import test_util
|
||||
from u_boot_pylib import tools
|
||||
|
||||
epilog = '''Create patches from commits in a branch, check them and email them
|
||||
as specified by tags you place in the commits. Use -n to do a dry run first.'''
|
||||
|
||||
parser = ArgumentParser(epilog=epilog)
|
||||
parser.add_argument('-b', '--branch', type=str,
|
||||
help="Branch to process (by default, the current branch)")
|
||||
parser.add_argument('-c', '--count', dest='count', type=int,
|
||||
default=-1, help='Automatically create patches from top n commits')
|
||||
parser.add_argument('-e', '--end', type=int, default=0,
|
||||
help='Commits to skip at end of patch list')
|
||||
parser.add_argument('-D', '--debug', action='store_true',
|
||||
help='Enabling debugging (provides a full traceback on error)')
|
||||
parser.add_argument('-p', '--project', default=project.detect_project(),
|
||||
help="Project name; affects default option values and "
|
||||
"aliases [default: %(default)s]")
|
||||
parser.add_argument('-P', '--patchwork-url',
|
||||
default='https://patchwork.ozlabs.org',
|
||||
help='URL of patchwork server [default: %(default)s]')
|
||||
parser.add_argument('-s', '--start', dest='start', type=int,
|
||||
default=0, help='Commit to start creating patches from (0 = HEAD)')
|
||||
parser.add_argument('-v', '--verbose', action='store_true', dest='verbose',
|
||||
default=False, help='Verbose output of errors and warnings')
|
||||
parser.add_argument('-H', '--full-help', action='store_true', dest='full_help',
|
||||
default=False, help='Display the README file')
|
||||
def run_patman():
|
||||
"""Run patamn
|
||||
|
||||
subparsers = parser.add_subparsers(dest='cmd')
|
||||
send = subparsers.add_parser(
|
||||
'send', help='Format, check and email patches (default command)')
|
||||
send.add_argument('-i', '--ignore-errors', action='store_true',
|
||||
dest='ignore_errors', default=False,
|
||||
help='Send patches email even if patch errors are found')
|
||||
send.add_argument('-l', '--limit-cc', dest='limit', type=int, default=None,
|
||||
help='Limit the cc list to LIMIT entries [default: %(default)s]')
|
||||
send.add_argument('-m', '--no-maintainers', action='store_false',
|
||||
dest='add_maintainers', default=True,
|
||||
help="Don't cc the file maintainers automatically")
|
||||
send.add_argument(
|
||||
'--get-maintainer-script', dest='get_maintainer_script', type=str,
|
||||
action='store',
|
||||
default=os.path.join(gitutil.get_top_level(), 'scripts',
|
||||
'get_maintainer.pl') + ' --norolestats',
|
||||
help='File name of the get_maintainer.pl (or compatible) script.')
|
||||
send.add_argument('-n', '--dry-run', action='store_true', dest='dry_run',
|
||||
default=False, help="Do a dry run (create but don't email patches)")
|
||||
send.add_argument('-r', '--in-reply-to', type=str, action='store',
|
||||
help="Message ID that this series is in reply to")
|
||||
send.add_argument('-t', '--ignore-bad-tags', action='store_true',
|
||||
default=False,
|
||||
help='Ignore bad tags / aliases (default=warn)')
|
||||
send.add_argument('-T', '--thread', action='store_true', dest='thread',
|
||||
default=False, help='Create patches as a single thread')
|
||||
send.add_argument('--cc-cmd', dest='cc_cmd', type=str, action='store',
|
||||
default=None, help='Output cc list for patch file (used by git)')
|
||||
send.add_argument('--no-binary', action='store_true', dest='ignore_binary',
|
||||
default=False,
|
||||
help="Do not output contents of changes in binary files")
|
||||
send.add_argument('--no-check', action='store_false', dest='check_patch',
|
||||
default=True,
|
||||
help="Don't check for patch compliance")
|
||||
send.add_argument('--tree', dest='check_patch_use_tree', default=False,
|
||||
action='store_true',
|
||||
help=("Set `tree` to True. If `tree` is False then we'll "
|
||||
"pass '--no-tree' to checkpatch (default: tree=%(default)s)"))
|
||||
send.add_argument('--no-tree', dest='check_patch_use_tree',
|
||||
action='store_false', help="Set `tree` to False")
|
||||
send.add_argument('--no-tags', action='store_false', dest='process_tags',
|
||||
default=True, help="Don't process subject tags as aliases")
|
||||
send.add_argument('--no-signoff', action='store_false', dest='add_signoff',
|
||||
default=True, help="Don't add Signed-off-by to patches")
|
||||
send.add_argument('--smtp-server', type=str,
|
||||
help="Specify the SMTP server to 'git send-email'")
|
||||
send.add_argument('--keep-change-id', action='store_true',
|
||||
help='Preserve Change-Id tags in patches to send.')
|
||||
This is the main program. It collects arguments and runs either the tests or
|
||||
the control module.
|
||||
"""
|
||||
args = cmdline.parse_args()
|
||||
|
||||
send.add_argument('patchfiles', nargs='*')
|
||||
if not args.debug:
|
||||
sys.tracebacklimit = 0
|
||||
|
||||
# Only add the 'test' action if the test data files are available.
|
||||
if os.path.exists(func_test.TEST_DATA_DIR):
|
||||
test_parser = subparsers.add_parser('test', help='Run tests')
|
||||
test_parser.add_argument('testname', type=str, default=None, nargs='?',
|
||||
help="Specify the test to run")
|
||||
# Run our meagre tests
|
||||
if args.cmd == 'test':
|
||||
# pylint: disable=C0415
|
||||
from patman import func_test
|
||||
from patman import test_checkpatch
|
||||
|
||||
status = subparsers.add_parser('status',
|
||||
help='Check status of patches in patchwork')
|
||||
status.add_argument('-C', '--show-comments', action='store_true',
|
||||
help='Show comments from each patch')
|
||||
status.add_argument('-d', '--dest-branch', type=str,
|
||||
help='Name of branch to create with collected responses')
|
||||
status.add_argument('-f', '--force', action='store_true',
|
||||
help='Force overwriting an existing branch')
|
||||
result = test_util.run_test_suites(
|
||||
'patman', False, False, False, None, None, None,
|
||||
[test_checkpatch.TestPatch, func_test.TestFunctional,
|
||||
'gitutil', 'settings'])
|
||||
|
||||
# Parse options twice: first to get the project and second to handle
|
||||
# defaults properly (which depends on project)
|
||||
# Use parse_known_args() in case 'cmd' is omitted
|
||||
argv = sys.argv[1:]
|
||||
args, rest = parser.parse_known_args(argv)
|
||||
if hasattr(args, 'project'):
|
||||
settings.Setup(parser, args.project)
|
||||
args, rest = parser.parse_known_args(argv)
|
||||
sys.exit(0 if result.wasSuccessful() else 1)
|
||||
|
||||
# If we have a command, it is safe to parse all arguments
|
||||
if args.cmd:
|
||||
args = parser.parse_args(argv)
|
||||
else:
|
||||
# No command, so insert it after the known arguments and before the ones
|
||||
# that presumably relate to the 'send' subcommand
|
||||
nargs = len(rest)
|
||||
argv = argv[:-nargs] + ['send'] + rest
|
||||
args = parser.parse_args(argv)
|
||||
# Process commits, produce patches files, check them, email them
|
||||
elif args.cmd == 'send':
|
||||
# Called from git with a patch filename as argument
|
||||
# Printout a list of additional CC recipients for this patch
|
||||
if args.cc_cmd:
|
||||
re_line = re.compile(r'(\S*) (.*)')
|
||||
with open(args.cc_cmd, 'r', encoding='utf-8') as inf:
|
||||
for line in inf.readlines():
|
||||
match = re_line.match(line)
|
||||
if match and match.group(1) == args.patchfiles[0]:
|
||||
for cca in match.group(2).split('\0'):
|
||||
cca = cca.strip()
|
||||
if cca:
|
||||
print(cca)
|
||||
|
||||
if __name__ != "__main__":
|
||||
pass
|
||||
elif args.full_help:
|
||||
with resources.path('patman', 'README.rst') as readme:
|
||||
tools.print_full_help(str(readme))
|
||||
else:
|
||||
# If we are not processing tags, no need to warning about bad ones
|
||||
if not args.process_tags:
|
||||
args.ignore_bad_tags = True
|
||||
control.send(args)
|
||||
|
||||
if not args.debug:
|
||||
sys.tracebacklimit = 0
|
||||
# Check status of patches in patchwork
|
||||
elif args.cmd == 'status':
|
||||
ret_code = 0
|
||||
try:
|
||||
control.patchwork_status(args.branch, args.count, args.start, args.end,
|
||||
args.dest_branch, args.force,
|
||||
args.show_comments, args.patchwork_url)
|
||||
except Exception as exc:
|
||||
terminal.tprint(f'patman: {type(exc).__name__}: {exc}',
|
||||
colour=terminal.Color.RED)
|
||||
if args.debug:
|
||||
print()
|
||||
traceback.print_exc()
|
||||
ret_code = 1
|
||||
sys.exit(ret_code)
|
||||
|
||||
# Run our meagre tests
|
||||
if args.cmd == 'test':
|
||||
from patman import func_test
|
||||
from patman import test_checkpatch
|
||||
|
||||
result = test_util.run_test_suites(
|
||||
'patman', False, False, False, None, None, None,
|
||||
[test_checkpatch.TestPatch, func_test.TestFunctional,
|
||||
'gitutil', 'settings'])
|
||||
|
||||
sys.exit(0 if result.wasSuccessful() else 1)
|
||||
|
||||
# Process commits, produce patches files, check them, email them
|
||||
elif args.cmd == 'send':
|
||||
# Called from git with a patch filename as argument
|
||||
# Printout a list of additional CC recipients for this patch
|
||||
if args.cc_cmd:
|
||||
fd = open(args.cc_cmd, 'r')
|
||||
re_line = re.compile('(\S*) (.*)')
|
||||
for line in fd.readlines():
|
||||
match = re_line.match(line)
|
||||
if match and match.group(1) == args.patchfiles[0]:
|
||||
for cc in match.group(2).split('\0'):
|
||||
cc = cc.strip()
|
||||
if cc:
|
||||
print(cc)
|
||||
fd.close()
|
||||
|
||||
elif args.full_help:
|
||||
with importlib.resources.path('patman', 'README.rst') as readme:
|
||||
tools.print_full_help(str(readme))
|
||||
else:
|
||||
# If we are not processing tags, no need to warning about bad ones
|
||||
if not args.process_tags:
|
||||
args.ignore_bad_tags = True
|
||||
control.send(args)
|
||||
|
||||
# Check status of patches in patchwork
|
||||
elif args.cmd == 'status':
|
||||
ret_code = 0
|
||||
try:
|
||||
control.patchwork_status(args.branch, args.count, args.start, args.end,
|
||||
args.dest_branch, args.force,
|
||||
args.show_comments, args.patchwork_url)
|
||||
except Exception as e:
|
||||
terminal.tprint('patman: %s: %s' % (type(e).__name__, e),
|
||||
colour=terminal.Color.RED)
|
||||
if args.debug:
|
||||
print()
|
||||
traceback.print_exc()
|
||||
ret_code = 1
|
||||
sys.exit(ret_code)
|
||||
if __name__ == "__main__":
|
||||
sys.exit(run_patman())
|
||||
|
|
147
tools/patman/cmdline.py
Normal file
147
tools/patman/cmdline.py
Normal file
|
@ -0,0 +1,147 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Copyright 2023 Google LLC
|
||||
#
|
||||
|
||||
"""Handles parsing of buildman arguments
|
||||
|
||||
This creates the argument parser and uses it to parse the arguments passed in
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
from patman import gitutil
|
||||
from patman import project
|
||||
from patman import settings
|
||||
|
||||
PATMAN_DIR = pathlib.Path(__file__).parent
|
||||
HAS_TESTS = os.path.exists(PATMAN_DIR / "func_test.py")
|
||||
|
||||
def parse_args():
|
||||
"""Parse command line arguments from sys.argv[]
|
||||
|
||||
Returns:
|
||||
tuple containing:
|
||||
options: command line options
|
||||
args: command lin arguments
|
||||
"""
|
||||
epilog = '''Create patches from commits in a branch, check them and email
|
||||
them as specified by tags you place in the commits. Use -n to do a dry
|
||||
run first.'''
|
||||
|
||||
parser = argparse.ArgumentParser(epilog=epilog)
|
||||
parser.add_argument('-b', '--branch', type=str,
|
||||
help="Branch to process (by default, the current branch)")
|
||||
parser.add_argument('-c', '--count', dest='count', type=int,
|
||||
default=-1, help='Automatically create patches from top n commits')
|
||||
parser.add_argument('-e', '--end', type=int, default=0,
|
||||
help='Commits to skip at end of patch list')
|
||||
parser.add_argument('-D', '--debug', action='store_true',
|
||||
help='Enabling debugging (provides a full traceback on error)')
|
||||
parser.add_argument('-p', '--project', default=project.detect_project(),
|
||||
help="Project name; affects default option values and "
|
||||
"aliases [default: %(default)s]")
|
||||
parser.add_argument('-P', '--patchwork-url',
|
||||
default='https://patchwork.ozlabs.org',
|
||||
help='URL of patchwork server [default: %(default)s]')
|
||||
parser.add_argument('-s', '--start', dest='start', type=int,
|
||||
default=0, help='Commit to start creating patches from (0 = HEAD)')
|
||||
parser.add_argument(
|
||||
'-v', '--verbose', action='store_true', dest='verbose', default=False,
|
||||
help='Verbose output of errors and warnings')
|
||||
parser.add_argument(
|
||||
'-H', '--full-help', action='store_true', dest='full_help',
|
||||
default=False, help='Display the README file')
|
||||
|
||||
subparsers = parser.add_subparsers(dest='cmd')
|
||||
send = subparsers.add_parser(
|
||||
'send', help='Format, check and email patches (default command)')
|
||||
send.add_argument('-i', '--ignore-errors', action='store_true',
|
||||
dest='ignore_errors', default=False,
|
||||
help='Send patches email even if patch errors are found')
|
||||
send.add_argument('-l', '--limit-cc', dest='limit', type=int, default=None,
|
||||
help='Limit the cc list to LIMIT entries [default: %(default)s]')
|
||||
send.add_argument('-m', '--no-maintainers', action='store_false',
|
||||
dest='add_maintainers', default=True,
|
||||
help="Don't cc the file maintainers automatically")
|
||||
send.add_argument(
|
||||
'--get-maintainer-script', dest='get_maintainer_script', type=str,
|
||||
action='store',
|
||||
default=os.path.join(gitutil.get_top_level(), 'scripts',
|
||||
'get_maintainer.pl') + ' --norolestats',
|
||||
help='File name of the get_maintainer.pl (or compatible) script.')
|
||||
send.add_argument('-n', '--dry-run', action='store_true', dest='dry_run',
|
||||
default=False, help="Do a dry run (create but don't email patches)")
|
||||
send.add_argument('-r', '--in-reply-to', type=str, action='store',
|
||||
help="Message ID that this series is in reply to")
|
||||
send.add_argument('-t', '--ignore-bad-tags', action='store_true',
|
||||
default=False,
|
||||
help='Ignore bad tags / aliases (default=warn)')
|
||||
send.add_argument('-T', '--thread', action='store_true', dest='thread',
|
||||
default=False, help='Create patches as a single thread')
|
||||
send.add_argument('--cc-cmd', dest='cc_cmd', type=str, action='store',
|
||||
default=None, help='Output cc list for patch file (used by git)')
|
||||
send.add_argument('--no-binary', action='store_true', dest='ignore_binary',
|
||||
default=False,
|
||||
help="Do not output contents of changes in binary files")
|
||||
send.add_argument('--no-check', action='store_false', dest='check_patch',
|
||||
default=True,
|
||||
help="Don't check for patch compliance")
|
||||
send.add_argument(
|
||||
'--tree', dest='check_patch_use_tree', default=False,
|
||||
action='store_true',
|
||||
help=("Set `tree` to True. If `tree` is False then we'll pass "
|
||||
"'--no-tree' to checkpatch (default: tree=%(default)s)"))
|
||||
send.add_argument('--no-tree', dest='check_patch_use_tree',
|
||||
action='store_false', help="Set `tree` to False")
|
||||
send.add_argument(
|
||||
'--no-tags', action='store_false', dest='process_tags', default=True,
|
||||
help="Don't process subject tags as aliases")
|
||||
send.add_argument('--no-signoff', action='store_false', dest='add_signoff',
|
||||
default=True, help="Don't add Signed-off-by to patches")
|
||||
send.add_argument('--smtp-server', type=str,
|
||||
help="Specify the SMTP server to 'git send-email'")
|
||||
send.add_argument('--keep-change-id', action='store_true',
|
||||
help='Preserve Change-Id tags in patches to send.')
|
||||
|
||||
send.add_argument('patchfiles', nargs='*')
|
||||
|
||||
# Only add the 'test' action if the test data files are available.
|
||||
if HAS_TESTS:
|
||||
test_parser = subparsers.add_parser('test', help='Run tests')
|
||||
test_parser.add_argument('testname', type=str, default=None, nargs='?',
|
||||
help="Specify the test to run")
|
||||
|
||||
status = subparsers.add_parser('status',
|
||||
help='Check status of patches in patchwork')
|
||||
status.add_argument('-C', '--show-comments', action='store_true',
|
||||
help='Show comments from each patch')
|
||||
status.add_argument(
|
||||
'-d', '--dest-branch', type=str,
|
||||
help='Name of branch to create with collected responses')
|
||||
status.add_argument('-f', '--force', action='store_true',
|
||||
help='Force overwriting an existing branch')
|
||||
|
||||
# Parse options twice: first to get the project and second to handle
|
||||
# defaults properly (which depends on project)
|
||||
# Use parse_known_args() in case 'cmd' is omitted
|
||||
argv = sys.argv[1:]
|
||||
args, rest = parser.parse_known_args(argv)
|
||||
if hasattr(args, 'project'):
|
||||
settings.Setup(parser, args.project)
|
||||
args, rest = parser.parse_known_args(argv)
|
||||
|
||||
# If we have a command, it is safe to parse all arguments
|
||||
if args.cmd:
|
||||
args = parser.parse_args(argv)
|
||||
else:
|
||||
# No command, so insert it after the known arguments and before the ones
|
||||
# that presumably relate to the 'send' subcommand
|
||||
nargs = len(rest)
|
||||
argv = argv[:-nargs] + ['send'] + rest
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
return args
|
Loading…
Add table
Reference in a new issue