summaryrefslogtreecommitdiffstats
path: root/bin
diff options
context:
space:
mode:
authorOswald Buddenhagen <oswald.buddenhagen@gmx.de>2023-03-12 13:39:11 +0100
committerOswald Buddenhagen <oswald.buddenhagen@gmx.de>2024-01-09 16:36:47 +0000
commitbc2eaa3ec88eef320345aed8dc8d9be4b6c2b119 (patch)
treed06ac5f73cce400e2b171d668efcdc959ea1dd8c /bin
parent31cef4c662ac13c683a7f94ef854b01fa6b53cab (diff)
gpush: make it possible to set format-patch options in mail mode
this is required for setting mail receivers and actual patch formatting options. the relevant options are identical for send-email and format-patch, so we don't differentiate these. Change-Id: Ie7f35b3402531ecec7762e07b32526c909589809 Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Diffstat (limited to 'bin')
-rwxr-xr-xbin/git-gpush61
-rw-r--r--bin/git_gpush.pm54
2 files changed, 105 insertions, 10 deletions
diff --git a/bin/git-gpush b/bin/git-gpush
index 6621c12..288f763 100755
--- a/bin/git-gpush
+++ b/bin/git-gpush
@@ -167,6 +167,11 @@ Options:
This setting persists for the series, even when it grows.
Use an empty topic to delete a previously set one.
+ -- <git option>...
+ In mail mode, set additional options for git format-patch and
+ git send-email for the specified series. All subsequent arguments
+ are consumed by this, so this must be the last option.
+
-o, --onto, --base <base>
Specify the commit to rebase the pushed series onto. It is possible
to specify upstream commits, commits pushed for review, or 'ROOT' to
@@ -390,6 +395,7 @@ my $list_online = 0;
my $send_email = 0;
my $keep_version = 0;
my $reset_version = 0;
+my $format_opts;
my $outdir;
my @reviewers;
@@ -467,6 +473,9 @@ sub parse_arguments(@)
$list_online = 1;
} elsif ($arg eq "--send") {
$send_email = 1;
+ } elsif ($arg eq "--") {
+ $format_opts = \@_;
+ last;
} elsif ($arg eq "--aliases") {
foreach my $key (sort(keys %aliases)) {
print "$key = $aliases{$key}\n";
@@ -532,7 +541,8 @@ sub parse_arguments(@)
$commit_count || $from_base || $extend || $capture;
my $series_modifying =
$series_specifying || defined($ref_to) || defined($topic)
- || $keep_version || $reset_version;
+ || $keep_version || $reset_version
+ || $format_opts;
my $gerrit_specific =
@reviewers || @CCs || defined($remote) || $force_branch;
my $push_specific =
@@ -552,6 +562,8 @@ sub parse_arguments(@)
if ($send_email);
fail("--keep-version/--reset-version is exclusive to mail mode.\n")
if ($keep_version || $reset_version);
+ fail("-- ... is exclusive to mail mode.\n")
+ if ($format_opts);
}
if ($group_only) {
@@ -923,6 +935,36 @@ sub determine_version($)
$$group{version} = $ver;
}
+sub new_fmt_opt()
+{
+ return new_prop(quote_list_prop(@$format_opts));
+}
+
+sub determine_format_options($)
+{
+ my ($group) = @_;
+
+ my ($fmt_opt, $fmt_opt_text);
+ if ($format_opts) {
+ $fmt_opt = new_fmt_opt();
+ $fmt_opt_text = $fmt_opt && $format_opts;
+ } else {
+ $fmt_opt = aggregate_indirect_property(
+ $group,
+ # Loose Changes should inherit the series' options,
+ # while for grouped ones undef means empty.
+ sub { defined($$_{grp}) ? ($$_{fmt} // -1) : undef },
+ sub { ("has inconsistent patch preparation options:\n",
+ map { " ".(length($_) ? format_cmd(unquote_list_prop($_))
+ : "<none>")."\n" } @_) });
+ $fmt_opt = undef if (($fmt_opt // 0) == -1);
+ $fmt_opt_text = [ unquote_list_prop($prop_by_key{$fmt_opt}) ]
+ if (defined($fmt_opt));
+ }
+ $$group{fmt_opt} = $fmt_opt;
+ $$group{fmt_opt_text} = $fmt_opt_text;
+}
+
sub scan_pushed_group($$)
{
my ($group, $commits) = @_;
@@ -1996,7 +2038,9 @@ sub annotate_group($$)
my @annot;
if ($extra) {
- # TODO
+ my $fmt_opt = $$group{fmt_opt_text};
+ push @annot, "> Format options: ".format_cmd(@$fmt_opt)."\n"
+ if ($fmt_opt);
}
$$group{annotation} = \@annot if (@annot);
}
@@ -2221,9 +2265,11 @@ sub format_patches($)
my $base = $$group{base};
my $tpc = $$group{topic};
my $ver = $$group{version};
+ my $fmt_opt = $$group{fmt_opt_text};
my @gitopt = ('--binary');
push @gitopt, '--reroll-count', $ver if ($ver > 1);
+ push @gitopt, @$fmt_opt if ($fmt_opt);
# Can't use the -<n> <tip> notation, as -8 is misunderstood
# by git send-email.
push @gitopt, (($base eq 'ROOT') ? '--root' : '^'.$base), $tip;
@@ -2253,6 +2299,7 @@ sub update_state_grouping($)
my ($group) = @_;
my $gid = $$group{gid};
+ my $fmt = $format_opts && new_fmt_opt();
foreach my $change (@{$$group{changes}}) {
$$change{grp} = $gid;
# We persist only explicitly specified values. Fallbacks
@@ -2265,6 +2312,8 @@ sub update_state_grouping($)
if (defined($ref_base) || $reset_props);
$$change{ver} = 0
if ($reset_version);
+ $$change{fmt} = $fmt
+ if ($format_opts);
$$change{exclude} = $exclude ? 1 : undef
if ($include || $exclude);
}
@@ -2274,10 +2323,10 @@ sub update_state($)
{
my ($group) = @_;
- my ($gid, $branch, $tpc, $ver, $base) =
+ my ($gid, $branch, $tpc, $ver, $fmt, $base) =
($$group{gid}, $$group{branch}, $$group{topic},
$$group{version},
- $$group{base});
+ $$group{fmt_opt}, $$group{base});
# Setting an empty topic clears the previous topic from the server.
$tpc = undef if (defined($tpc) && !length($tpc));
foreach my $change (@{$$group{changes}}) {
@@ -2287,6 +2336,7 @@ sub update_state($)
$$change{topic} = $tpc;
$$change{ntopic} = undef;
$$change{ver} = $ver;
+ $$change{fmt} = $fmt;
$$change{tgt} = $branch;
$$change{ntgt} = undef;
my $commit = $$change{local};
@@ -2388,6 +2438,9 @@ sub execute_pushing()
resolve_ref_base();
foreach my $group (@$annot_groups) {
determine_topic($group);
+ if ($mail_mode) {
+ determine_format_options($group);
+ }
}
if ($rebase) {
# Rebasing may take a while, so make sure all base determination
diff --git a/bin/git_gpush.pm b/bin/git_gpush.pm
index dce7400..06cf21a 100644
--- a/bin/git_gpush.pm
+++ b/bin/git_gpush.pm
@@ -17,7 +17,7 @@ use Carp;
$SIG{__WARN__} = \&Carp::cluck;
$SIG{__DIE__} = \&Carp::confess;
-use List::Util qw(min max);
+use List::Util qw(min max pairmap);
use File::Spec;
use File::Temp qw(mktemp);
use IPC::Open3 qw(open3);
@@ -125,7 +125,7 @@ use constant {
DRY_RUN => 512 # Don't actually run the command if $dry_run is true
};
-sub _format_cmd(@)
+sub format_cmd(@)
{
return join(' ', map { /\s/ ? '"' . $_ . '"' : $_ } @_);
}
@@ -138,10 +138,10 @@ sub open_process($@)
$flags &= ~DRY_RUN if (!$dry_run);
$process{flags} = $flags;
if ($flags & DRY_RUN) {
- print "+ "._format_cmd(@cmd)." [DRY]\n" if ($debug);
+ print "+ ".format_cmd(@cmd)." [DRY]\n" if ($debug);
return \%process;
}
- my $cmd = _format_cmd(@cmd);
+ my $cmd = format_cmd(@cmd);
$process{cmd} = $cmd;
my ($in, $out, $err);
if ($flags & USE_STDIN) {
@@ -708,6 +708,47 @@ our %gerrit_info_by_key;
our %gerrit_info_by_sha1;
our %gerrit_infos_by_id;
+#############################
+# state variable processing #
+#############################
+
+{ # start text escape functions
+
+my @escapes = split //, "\\\\\"\"\aa\bb\tt\nn\rr\013v\ff\ee s";
+my %esc_to_char = pairmap { $b => $a } @escapes;
+my %char_to_esc = pairmap { $a => $b } @escapes;
+
+sub quote_text_prop($;$)
+{
+ my ($in, $sp) = @_;
+
+ my $re = $sp ? qr/(\p{Cc}|\\|\"| )/ : qr/(\p{Cc}|\\|\")/;
+ $in =~ s{$re}{"\\".($char_to_esc{$1} // sprintf("%03o", ord($1)))}ge;
+ return $in;
+}
+
+sub unquote_text_prop($)
+{
+ my ($in) = @_;
+
+ $in =~ s{(?>\\([\\\"a-z]|[0-3][0-7][0-7]))}{$esc_to_char{$1} // chr(oct($1))}ge;
+ return $in;
+}
+
+} # end text escape functions
+
+sub quote_list_prop(@)
+{
+ return join(" ", map { quote_text_prop($_, 1) } @_);
+}
+
+sub unquote_list_prop($)
+{
+ my ($in) = @_;
+
+ return map { unquote_text_prop($_) } split(/ /, $in);
+}
+
##################
# state handling #
##################
@@ -721,6 +762,7 @@ our %gerrit_infos_by_id;
# - src: Local branch name, or "-" if Change is on a detached HEAD.
# - tgt: Target branch name.
# - topic: Gerrit topic. Persisted only as a cache.
+# - fmt: format-patch/send-email options (indirect).
# - pushed: SHA1 of the commit this Change was pushed as last time
# from this repository.
# - rebased: prospective value for 'pushed'.
@@ -807,9 +849,9 @@ sub save_state(;$$)
print "Saving ".($new ? "new " : "")."state".($dry ? " [DRY]" : "")." ...\n" if ($debug);
my %prop_hash;
my (@lines, @updates);
- my %ikeys = map { $_ => 1 } ();
+ my %ikeys = map { $_ => 1 } ('fmt');
my @fkeys = ('key', 'grp', 'id', 'base', 'src', 'tgt',
- 'topic', 'ver',
+ 'topic', 'ver', 'fmt',
'nbase', 'ntgt', 'ntopic', 'exclude', 'hide');
my @rkeys = ('pushed', 'rebased', 'orig', 'rorig');
if ($new) {