-
Oswald Buddenhagen authored
Change-Id: I670423c6001e2a504df8be80b42ee88566ad3baa Reviewed-by:
Oswald Buddenhagen <oswald.buddenhagen@digia.com>
e2f973a8
git-qt-cherry-pick 7.96 KiB
#! /usr/bin/perl
# Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
# Contact: http://www.qt-project.org/legal
#
# You may use this file under the terms of the 3-clause BSD license.
# See the file LICENSE from this package for details.
#
use warnings;
use strict;
my @repos = (
[ "projects.pro", "qt" ],
[ "qlalr.pro", "qt5/qlalr" ],
[ "qtactiveqt.pro", "qt5/qtactiveqt" ],
[ "qtbase.pro", "qt5/qtbase" ],
[ "qtdeclarative.pro", "qt5/qtdeclarative" ],
[ "qtdoc.pro", "qt5/qtdoc" ],
[ "qtphonon.pro", "qt5/qtphonon" ],
[ "qtquick1.pro", "qt5/qtquick1" ],
[ "qtscript.pro", "qt5/qtscript" ],
[ "qtsvg.pro", "qt5/qtsvg" ],
[ "qttools.pro", "qt5/qttools" ],
[ "qttranslations.pro", "qt5/qttranslations" ],
[ "qtxmlpatterns.pro", "qt5/qtxmlpatterns" ],
[ "qtcreator.pro", "qtcreator" ],
[ "git-hooks/sanitize-commit", "qt5/qtrepotools" ],
[ "shell/sanitize-commit", "devtools" ],
);
my @mappings = (
[ [ "qt", "qt5/qlalr" ], [
[ 'util/qlalr//[^/]+$', 'src//[^/]+$' ],
[ 'util/qlalr', '' ]
] ],
[ [ "qt", "qt5/qtactiveqt" ], [
[ 'tools/activeqt', 'tools' ],
[ 'doc/src/examples/activeqt', 'doc/src/examples' ],
[ 'doc/src/development//[^/]+$', 'doc/src//[^/]+$' ]
] ],
[ [ "qt", "qt5/qtbase" ], [
] ],
[ [ "qt", "qt5/qtdeclarative" ], [
[ 'tools/qml', 'tools/qmlviewer' ]
] ],
[ [ "qt", "qt5/qtdoc" ], [
[ 'tools/qdoc3/test', 'doc/config' ]
] ],
[ [ "qt", "qt5/qtphonon" ], [
] ],
[ [ "qt", "qt5/qtquick1" ], [
] ],
[ [ "qt", "qt5/qtscript" ], [
] ],
[ [ "qt", "qt5/qtsvg" ], [
] ],
[ [ "qt", "qt5/qttools" ], [
[ 'tools', 'src' ]
] ],
[ [ "qt", "qt5/qttranslations" ], [
] ],
[ [ "qt", "qt5/qtxmlpatterns" ], [
] ],
[ [ "devtools", "qt5/qtrepotools" ], [
[ 'shell/git-', 'bin/git-' ],
[ 'shell/git_post_commit_hook', 'git-hooks/git_post_commit_hook' ],
[ 'shell/sanitize-commit', 'git-hooks/sanitize-commit' ]
] ],
[ [ "qtcreator", "qt5/qttools" ], [
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
[ 'src/shared/proparser', 'src/linguist/shared' ],
], 1 ],
[ [ "qtcreator", "qt5/qtbase" ], [
[ 'src/shared/proparser', 'qmake/library' ],
], 1 ],
[ [ "qt5/qtbase", "qt5/qttools" ], [
[ 'qmake/library', 'src/linguist/shared' ],
], 1 ]
);
my ($cand, $inv);
sub map_name($)
{
my ($fn) = @_;
for my $ptha (@{$$cand[1]}) {
my ($pthi, $ptho) = ($$ptha[$inv], $$ptha[1 - $inv]);
$pthi .= "(.*)" if (!($pthi =~ s,//(.*),/($1),));
$ptho =~ s,//.*,/,;
last if ($fn =~ s/^$pthi/$ptho$1/);
}
return $fn;
}
sub get_arg()
{
if (@ARGV < 2) {
die $ARGV[0]." requires an argument.\n";
}
shift @ARGV;
return $ARGV[0];
}
sub get_repo_arg()
{
my $arg = $ARGV[0];
my $val = get_arg();
for my $rp (@repos) {
if ($$rp[1] eq $val) {
return $val;
}
if ($$rp[1] =~ /\/\Q$val\E$/) {
return $$rp[1];
}
}
die "Fatal: Unknown repository passed to $arg.\n";
}
my ($src_repo, $dst_repo, $other_path) = ("", "", "");
my @commits = ();
my $push = 0;
my $noop = 0;
while (@ARGV) {
my $arg = $ARGV[0];
if ($arg eq '-h' or $arg eq '-help' or $arg eq '--help') {
print <<EOF ;
Usage: $0 [options] [SHA1/-range]
Options:
-l, --pull <repo> Specify repo to pull from instead of guessing it.
-s, --push [<repo>] Push [to specified repo] instead of pulling.
-p, --path <path> Specify path of other repo instead of guessing it.
-n, --dry-run Dump patch to stdout instead of applying it.
-- Only SHA1s follow this option (use with -s without repo).
By default, the HEAD commit of the source repo is cherry-picked.
EOF
exit 0;
} elsif ($arg eq '-l' or $arg eq '--pull') {
$src_repo = get_repo_arg();
} elsif ($arg eq '-s' or $arg eq '--push') {
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
$dst_repo = get_repo_arg() if (@ARGV >= 2 && $ARGV[1] !~ /^-/);
$push = 1;
} elsif ($arg eq '-p' or $arg eq '--path') {
$other_path = get_arg();
} elsif ($arg eq '-n' or $arg eq '--dry-run') {
$noop = 1;
} elsif ($arg eq "--") {
shift @ARGV;
push @commits, @ARGV;
last;
} elsif ($arg =~ /^-/) {
die "Unrecognized option $arg.\n";
} else {
push @commits, $arg;
}
shift @ARGV;
}
die "-s and -l are mutually exclusive.\n" if ($src_repo ne "" and $dst_repo ne "");
push @commits, "HEAD" if (!@commits);
my $cdup = `git rev-parse --show-cdup` or exit 1;
chomp $cdup;
if (length($cdup)) {
chdir $cdup or die "Cannot enter $cdup: $!\n";
}
my $this_repo = "";
for my $rp (@repos) {
if (-f $$rp[0]) {
$this_repo = $$rp[1];
last;
}
}
die "Fatal: This Git repository is not known to this script.\n" if ($this_repo eq "");
if (!$push) {
$dst_repo = $this_repo;
} else {
$src_repo = $this_repo;
}
die "Fatal: source and target repository are the same.\n" if ($src_repo eq $dst_repo);
my @candidates = ();
my $mincand = 10;
for my $cand (@mappings) {
my $mcand = $$cand[2] // 0;
if ($mcand <= $mincand) {
for my $inv (0, 1) {
if (("" eq $src_repo or $$cand[0][$inv] eq $src_repo) and
("" eq $dst_repo or $$cand[0][1 - $inv] eq $dst_repo)) {
if ($mcand < $mincand) {
$mincand = $mcand;
@candidates = ();
}
push @candidates, [ $cand, $inv ];
last;
}
}
}
}
if (@candidates == 0) {
die "Fatal: found no mapping between source and target repository.\n";
} elsif (@candidates > 1) {
die "Fatal: found multiple mappings between source and target repository. Try -l/-p.\n";
}
($cand, $inv) = @{$candidates[0]};
print "Porting from ".$$cand[0][$inv]." to ".$$cand[0][1 - $inv]."\n";
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
if ($other_path eq "") {
my $this_path = $$cand[0][1 - ($push ^ $inv)];
my $cnt = 1;
while ($this_path =~ /\//g) { $cnt++ }
$other_path = "../"x$cnt . $$cand[0][$push ^ $inv];
}
print "Other path is ".$other_path."\n";
my $cd_other = "cd \"".$other_path."\" && ";
my ($src_cd, $dst_cd) = ("", "");
if (!$push) {
$src_cd = $cd_other;
} else {
$dst_cd = $cd_other;
}
my $short_src = $$cand[0][$inv];
$short_src =~ s,^.*/,,;
my $needid = -1;
for my $commit (@commits) {
my @revs;
if ($commit =~ /\.\./) {
@revs = `${src_cd}git rev-list --reverse $commit`;
} else {
@revs = ($commit);
}
for my $rev (@revs) {
my ($first, $empty, $sha1, $patch, $haveid) = (1, 0, "", "", 0);
open DIFF, $src_cd."git format-patch --stdout -1 --src-prefix=\@old\@/ --dst-prefix=\@new\@/ ".$rev." |" or die "cannot run git: $!";
while (<DIFF>) {
if ($first) {
$first = 0;
/^From (.{40}) / and $sha1 = $1;
} elsif ($_ eq "\n" || /^[-\w]+: /) {
$haveid = 1 if (/^Change-Id:/);
$empty = 1;
} else {
if (s/^(diff --git \@old\@\/)(.*)( \@new\@\/)(.*)\n/$1.map_name($2).$3.map_name($4)."\n"/e) {
} elsif (s/^(--- \@old\@|\+\+\+ \@new\@)\/([^\n]+)/$1."\/".map_name($2)/e) {
} elsif ($_ eq "---\n") {
$patch .= "\n" if (!$empty);
$patch .= "(cherry picked from ".$short_src."/".$sha1.")\n";
if (!$haveid) {
$needid = int(grep /codereview/, `${dst_cd}git remote -v`) if ($needid < 0);
$patch .= "Change-Id: I".$sha1."\n" if ($needid);
}
}
$empty = 0;
}
$patch .= $_;
}
close DIFF or die "Aborting at ".$rev."\n";
if ($noop) {
print $patch;
} else {
open PATCH, "| ".$dst_cd."git am -3" or die "cannot run git: $!";
print PATCH $patch;
close PATCH or die "Aborting at ".$rev."\n";
}
}
}
exit 0;