summaryrefslogtreecommitdiff
path: root/pwx
diff options
context:
space:
mode:
authorSven Eden <yamakuzure@gmx.net>2018-05-14 18:34:03 +0200
committerSven Eden <yamakuzure@gmx.net>2018-05-14 18:34:03 +0200
commitf3ad434bd80ddb838b1013a52c4ed962f09a4d48 (patch)
treea0ab1a0987f8f9692dddc0acadfa332f7537d37e /pwx
parentfe74b05c4ac2956cda37903fd77d4882fb2330f0 (diff)
migrate_tree.pl: Reworking of the formatted patches added.
Diffstat (limited to 'pwx')
-rwxr-xr-xpwx/migrate_tree.pl659
1 files changed, 458 insertions, 201 deletions
diff --git a/pwx/migrate_tree.pl b/pwx/migrate_tree.pl
index 86c905e36..4760a5178 100755
--- a/pwx/migrate_tree.pl
+++ b/pwx/migrate_tree.pl
@@ -5,8 +5,9 @@
# ================================================================
#
# Version Date Maintainer Changes, Additions, Fixes
-# 0.0.1 2017-05-02 sed, PrydeWorX First basic design
-# 0.0.2 2017-05-07 sed, PrydeWorX Work flow integrated up to creating the formatted patches
+# 0.0.1 2018-05-02 sed, PrydeWorX First basic design.
+# 0.0.2 2018-05-07 sed, PrydeWorX Work flow integrated up to creating the formatted patches.
+# 0.0.3 2018-05-13 sed, PrydeWorX Reworking of the formatted patches added.
#
# ========================
# === Little TODO list ===
@@ -24,13 +25,13 @@ use Try::Tiny;
# ================================================================
# === ==> ------ Help Text and Version ----- <== ===
# ================================================================
-Readonly my $VERSION => "0.0.2"; ## Please keep this current!
+Readonly my $VERSION => "0.0.3"; # Please keep this current!
Readonly my $VERSMIN => "-" x length($VERSION);
Readonly my $PROGDIR => dirname($0);
Readonly my $PROGNAME => basename($0);
Readonly my $WORKDIR => getcwd();
-Readonly my $CHECK_TREE => abs_path($PROGDIR . "/check_tree.pl");
-Readonly my $COMMIT_FILE => abs_path($PROGDIR . "/last_mutual_commits.csv");
+Readonly my $CHECK_TREE => abs_path( $PROGDIR . "/check_tree.pl" );
+Readonly my $COMMIT_FILE => abs_path( $PROGDIR . "/last_mutual_commits.csv" );
Readonly my $USAGE_SHORT => "$PROGNAME <--help|[OPTIONS] <upstream path> <refid>>";
Readonly my $USAGE_LONG => qq#
elogind git tree migration V$VERSION
@@ -73,76 +74,83 @@ Notes:
# === ==> -------- Global variables -------- <== ===
# ================================================================
-my $commit_count = 0; ## It is easiest to count the relevant commits globally.
-my $do_advance = 0; ## If set by --advance, use src-<hash> as last commit.
-my @lCommits = (); ## List of all relevant commits that have been found, in topological order.
-my @lPatches = (); ## List of the formatted patches build from @lCommits.
-my $main_result = 1; ## Used for parse_args() only, as simple $result is local everywhere.
-my $mutual_commit = ""; ## The last mutual commit to use. Will be read from csv if not set by args.
-my $output_path = abs_path("$PROGDIR/patches");
-my $previous_refid = ""; ## Store current upstream state, so we can revert afterwards.
-my $show_help = 0;
-my @source_files = (); ## Final file list to process, generated in in generate_file_list().
-my $upstream_path = "";
-my $wanted_refid = ""; ## The refid to reset the upstream tree to.
-
+my $commit_count = 0; # It is easiest to count the relevant commits globally.
+my $do_advance = 0; # If set by --advance, use src-<hash> as last commit.
+my %hDirectories = (); # Filled when searching relevant files, used to validate new files.
+my @lCommits = (); # List of all relevant commits that have been found, in topological order.
+my @lCreated = (); # List of all files that were created using the migrated commits.
+my @lPatches = (); # List of the formatted patches build from @lCommits.
+my $main_result = 1; # Used for parse_args() only, as simple $result is local everywhere.
+my $mutual_commit = ""; # The last mutual commit to use. Will be read from csv if not set by args.
+my $output_path = "";
+my $previous_refid = ""; # Store current upstream state, so we can revert afterwards.
+my $prg_line = ""; # Current line when showing progress
+my $show_help = 0;
+my @source_files = (); # Final file list to process, generated in in generate_file_list().
+my $upstream_path = "";
+my $wanted_refid = ""; # The refid to reset the upstream tree to.
# ================================================================
# === ==> ------- MAIN DATA STRUCTURES ------ <== ===
# ================================================================
-my %hCommits = (); ## Hash of all upstream commits that touch at least one file:
- ## ( refid : count of files touched )
-my %hFiles = (); ## List of all source files as %hFile structures with a simple
- ## ( tgt : $hFile ) mapping.
-my $hFile = {}; ## Simple description of one file consisting of:
- ## Note: The store is %hFiles, this is used as a global pointer.
- ## Further although the target is the key in %hFiles, we
- ## store it here, too, so we always no the $hFile's key.
- ## ( patch: Full path to the patch that check_tree.pl would generate
- ## src : The potential relative upstream path with 'elogind' substituted by 'systemd'
- ## tgt : The found relative path in the local tree
- ## )
-my %hMutuals = (); ## Mapping of the $COMMIT_FILE, that works as follows:
- ## CSV lines are structured as:
- ## <refid> <hash> src-<hash> tgt-<hash>
- ## They map as follows:
- ## ( <refid> : {
- ## mutual : <hash> | This is the last mutual commit
- ## src : <hash> | This is the last individual commit in the upstream tree (*)
- ## tgt : <hash> | This is the last individual commit in the local tree (*)
- ## } )
- ## (*) When this entry was written. This means that src-<hash> can be used as
- ## the next last mutual commit, when this migration run is finished. To make
- ## this automatic, the --advance option triggers exactly that.
+my %hCommits = (); # Hash of all upstream commits that touch at least one file:
+ # ( refid : count of files touched )
+my %hFiles = (); # List of all source files as %hFile structures with a simple
+ # ( tgt : $hFile ) mapping.
+my $hFile = {}; # Simple description of one file consisting of:
+ # Note: The store is %hFiles, this is used as a global pointer.
+ # Further although the target is the key in %hFiles, we
+ # store it here, too, so we always no the $hFile's key.
+ # ( patch: Full path to the patch that check_tree.pl would generate
+ # src : The potential relative upstream path with 'elogind' substituted by 'systemd'
+ # tgt : The found relative path in the local tree
+ # )
+my %hMutuals = (); # Mapping of the $COMMIT_FILE, that works as follows:
+ # CSV lines are structured as:
+ # <refid> <hash> src-<hash> tgt-<hash>
+ # They map as follows:
+ # ( <refid> : {
+ # mutual : <hash> | This is the last mutual commit
+ # src : <hash> | This is the last individual commit in the upstream tree (*)
+ # tgt : <hash> | This is the last individual commit in the local tree (*)
+ # } )
+ # (*) When this entry was written. This means that src-<hash> can be used as
+ # the next last mutual commit, when this migration run is finished. To make
+ # this automatic, the --advance option triggers exactly that.
+
# ================================================================
# === ==> -------- Function list -------- <== ===
# ================================================================
-sub build_hCommits; ## Build a hash of commits for the current hFile.
-sub build_hFile; ## Add an entry to hFiles for a specific target file.
-sub build_lCommits; ## Build the topological list of all relevant commits.
-sub build_lPatches; ## Fill $output_path with formatted patches from @lCommits.
-sub checkout_upstream; ## Checkout the given refid on $upstream_path.
-sub generate_file_list; ## Find all relevant files and store them in @wanted_files
-sub get_last_mutual; ## Find or read the last mutual refid between this and the upstream tree.
-sub parse_args; ## Parse ARGV for the options we support
-sub wanted; ## Callback function for File::Find
+sub apply_patches; # Apply a reworked patch.
+sub build_hCommits; # Build a hash of commits for the current hFile.
+sub build_hFile; # Add an entry to hFiles for a specific target file.
+sub build_lCommits; # Build the topological list of all relevant commits.
+sub build_lPatches; # Fill $output_path with formatted patches from @lCommits.
+sub check_tree; # Use check_tree.pl on the given commit and file.
+sub checkout_upstream; # Checkout the given refid on $upstream_path.
+sub generate_file_list; # Find all relevant files and store them in @wanted_files
+sub get_last_mutual; # Find or read the last mutual refid between this and the upstream tree.
+sub parse_args; # Parse ARGV for the options we support
+sub rework_patch; # Use check_tree.pl to generate valid diffs on all valid files within the patch.
+sub show_prg; # Helper to show a progress line that is not permanent.
+sub wanted; # Callback function for File::Find
# ================================================================
# === ==> -------- Prechecks -------- <== ==
# ================================================================
--x $CHECK_TREE or die ("$CHECK_TREE not found!");
+-x $CHECK_TREE or die("$CHECK_TREE not found!");
+$output_path = abs_path("$PROGDIR/patches");
$main_result = parse_args(@ARGV);
-( (!$main_result) ## Note: Error or --help given, then exit.
- or ( $show_help and print "$USAGE_LONG" ) )
- and exit(!$main_result);
+(
+ ( !$main_result ) ## Note: Error or --help given, then exit.
+ or ( $show_help and print "$USAGE_LONG" ) ) and exit( !$main_result );
get_last_mutual and generate_file_list
- or exit 1;
-checkout_upstream($wanted_refid) ## Note: Does nothing if $wanted_refid is already checked out.
- or exit 1;
-
+ or exit 1;
+checkout_upstream($wanted_refid) ## Note: Does nothing if $wanted_refid is already checked out.
+ or exit 1;
# ================================================================
# === ==> -------- = MAIN PROGRAM = -------- <== ===
@@ -157,7 +165,7 @@ for my $file_part (@source_files) {
build_hFile($file_part) or next;
build_hCommits or next;
}
-printf(" %d commits found\n", $commit_count);
+printf( " %d commits found\n", $commit_count );
# -----------------------------------------------------------------
# --- 2) Get a list of all commits and build @lCommits, checking --
@@ -169,10 +177,42 @@ build_lCommits or exit 1;
# -----------------------------------------------------------------
# --- 3) Go through the relevant commits and create formatted ---
-# --- patches for them using. ---
+# --- patches for them. ---
# -----------------------------------------------------------------
build_lPatches or exit 1;
+# -----------------------------------------------------------------
+# --- 4) Go through the patches and rewrite them. We only want ---
+# --- them to touch files of relevance, and need them to ---
+# --- contain only diffs that are valid for us. We'll use ---
+# --- check_tree.pl to achieve the latter. ---
+# -----------------------------------------------------------------
+for ( my $i = 0 ; $i < $commit_count ; ++$i ) {
+ my $fmt = sprintf( "%04d-*.patch", $i + 1 );
+ my @lFiles = glob qq("${output_path}/${fmt}");
+
+ # Be sure this is solid!
+ # ----------------------------------------------------------
+ if ( scalar @lFiles > 1 ) {
+ print "\nERROR: $fmt results in more than one patch!\n";
+ return 0;
+ } elsif ( 1 > scalar @lFiles ) {
+ print "\nERROR: No patches found for $fmt!";
+ return 0;
+ }
+
+ show_prg( sprintf("Reworking %s"), basename( $lFiles[0] ) );
+ rework_patch( $lFiles[0] ) or exit 1;
+
+ # -------------------------------------------------------------
+ # --- 5) Reworked patches must be applied directly. ---
+ # --- Otherwise we'll screw up if a newly created file ---
+ # --- gets patched later. ---
+ # -------------------------------------------------------------
+ show_prg( sprintf("Applying %s"), basename( $lFiles[0] ) );
+ apply_patch( $lFiles[0] ) or exit 1;
+} ## end for ( my $i = 0 ; $i < ...)
+show_prg("");
# ===========================
# === END OF MAIN PROGRAM ===
@@ -188,33 +228,32 @@ length($previous_refid) and checkout_upstream($previous_refid);
# === ==> ---- Function Implementations ---- <== ===
# ================================================================
+# --------------------------------------------------------------
+# --- Apply a reworked patch ---
+# --------------------------------------------------------------
+sub apply_patch {
+ my ($pFile) = @_;
+
+ return 1;
+}
# ------------------------------------------------------
# --- Build a hash of commits for the current hFile. ---
# ------------------------------------------------------
sub build_hCommits {
my $git = Git::Wrapper->new($upstream_path);
-
- my @lRev = $git->rev_list( {
- topo_order => 1,
- "reverse" => 1,
- oneline => 1
- },
- "${mutual_commit}..${wanted_refid}",
- $hFile->{src} );
+ my @lRev = $git->rev_list( { topo_order => 1, "reverse" => 1, oneline => 1 }, "${mutual_commit}..${wanted_refid}", $hFile->{src} );
for my $line (@lRev) {
if ( $line =~ m/^(\S+)\s+/ ) {
- defined($hCommits{$1})
- or ++$commit_count
- and $hCommits{$1} = 0;
+ defined( $hCommits{$1} )
+ or ++$commit_count and $hCommits{$1} = 0;
++$hCommits{$1};
}
- }
+ } ## end for my $line (@lRev)
return 1;
-}
-
+} ## end sub build_hCommits
# ------------------------------------------------------------------
# --- Build a list of the relevant commits in topological order. ---
@@ -222,23 +261,19 @@ sub build_hCommits {
sub build_lCommits {
my $git = Git::Wrapper->new($upstream_path);
- my @lRev = $git->rev_list( {
- topo_order => 1,
- "reverse" => 1,
- oneline => 1
- },
- "${mutual_commit}..${wanted_refid}" );
+ my @lRev = $git->rev_list( { topo_order => 1, "reverse" => 1, oneline => 1 }, "${mutual_commit}..${wanted_refid}" );
for my $line (@lRev) {
if ( $line =~ m/^(\S+)\s+/ ) {
- defined($hCommits{$1})
- and push @lCommits, "$1";
+ defined( $hCommits{$1} )
+ and show_prg("Noting down $1")
+ and push @lCommits, "$1";
}
- }
-
- return 1;
-}
+ } ## end for my $line (@lRev)
+ show_prg("");
+ return 1;
+} ## end sub build_lCommits
# ----------------------------------------------------------
# --- Add an entry to hFiles for a specific target file. ---
@@ -262,71 +297,129 @@ sub build_hFile {
$patch =~ s/\//_/g;
# Build the central data structure.
- %hFiles = (
- $tgt => {
- patch => $output_path . "/" . $patch . ".patch",
- src => $src,
- tgt => $tgt
- } );
-
+ $hFiles{$tgt} = {
+ patch => $output_path . "/" . $patch . ".patch",
+ src => $src,
+ tgt => $tgt
+ };
+
# This is now our current hFile
$hFile = $hFiles{$tgt};
return 1;
-}
-
+} ## end sub build_hFile
# ----------------------------------------------------------------
# --- Fill $output_path with formatted patches from @lCommits. ---
# ----------------------------------------------------------------
sub build_lPatches {
- my $git = Git::Wrapper->new($upstream_path);
- my $cnt = 0;
- my $curLen = 0;
- my $maxLen = 0;
- my @lRev = ();
- my @lPath = ();
+ my $git = Git::Wrapper->new($upstream_path);
+ my $cnt = 0;
+ my @lRev = ();
+ my @lPath = ();
for my $refid (@lCommits) {
- @lRev = $git->rev_list( {
- "1" => 1,
- oneline => 1
- }, $refid );
+ @lRev = $git->rev_list( { "1" => 1, oneline => 1 }, $refid );
- $curLen = length($lRev[0]);
- $curLen > $maxLen and $maxLen = $curLen;
- printf("\r%03d: %s", ++$cnt, $lRev[0]
- . ($maxLen > $curLen ? ' ' x ($maxLen - $curLen) : ""));
+ show_prg( sprintf( "Building %03d: %s", ++$cnt, $lRev[0] ) );
try {
- @lPath = $git->format_patch({
- "1" => 1,
- "find-copies" => 1,
- "find-copies-harder" => 1,
- "numbered" => 1,
- "output-directory" => $output_path
- },
- "--start-number=$cnt",
- $refid);
- } catch {
+ @lPath = $git->format_patch(
+ {
+ "1" => 1,
+ "find-copies" => 1,
+ "find-copies-harder" => 1,
+ "numbered" => 1,
+ "output-directory" => $output_path
+ },
+ "--start-number=$cnt",
+ $refid
+ );
+ } ## end try
+ catch {
print "\nERROR: Couldn't format-patch $refid\n";
print "Exit Code : " . $_->status . "\n";
- print "Message : " . $_->error . "\n";
+ print "Message : " . $_->error . "\n";
return 0;
};
+ } ## end for my $refid (@lCommits)
+ $cnt and show_prg("") and print("$cnt patches built\n");
+
+ # Just a safe guard, that is almost guaranteed to never catch.
+ if ( $cnt != $commit_count ) {
+ print "ERROR: $commit_count patches expected, but only $cnt patches generated!\n";
+ return 0;
}
- $maxLen and print "\r" . (' ' x $maxLen) . "\r$cnt patches built\n";
-
+
return 1;
-}
+} ## end sub build_lPatches
+
+# -------------------------------------------------------
+# --- Use check_tree.pl on the given commit and file. ---
+# -------------------------------------------------------
+sub check_tree {
+ my ( $commit, $file, $isNew ) = @_;
+ my $stNew = "";
+
+ # If this is the creation of a new file, the hFile must be built.
+ if ($isNew) {
+ my $tgt_file = basename($file);
+ my $tgt_dir = dirname($file);
+ $tgt_file =~ s/systemd/elogind/g;
+
+ defined( $hDirectories{$tgt_dir} )
+ or $tgt_dir =~ s/systemd/elogind/g;
+
+ my $tgt = "$tgt_dir/$tgt_file";
+
+ # Build the patch name
+ my $patch = $tgt;
+ $patch =~ s/\//_/g;
+ $hFiles{$file} = {
+ patch => $output_path . "/" . $patch . ".patch",
+ src => $file,
+ tgt => $tgt
+ };
+ $stNew = "--create ";
+ } ## end if ($isNew)
+ my $path = $hFiles{$file}{patch};
+
+ # Now get the patch built
+ my @lResult = `$CHECK_TREE --stay -c $commit ${stNew}-f $file $upstream_path 2>&1`;
+ my $res = $?;
+ my $err = $!;
+
+ if ($res) {
+ print "\n$CHECK_TREE died!\n";
+
+ if ( $res == -1 ) {
+ print "failed to execute: $err\n";
+ } elsif ( $? & 127 ) {
+ printf "Signal %d, %s coredump\n", ( $? & 127 ), ( $? & 128 ) ? 'with' : 'without';
+ } else {
+ printf "child exited with value %d\n", $? >> 8;
+ }
+ print "-----\n" . join( "", @lResult ) . "-----\n";
+ return "";
+ } ## end if ($res)
+
+ # If check_tree found no diff or cleaned up all hunks, no patch is created.
+ for my $line (@lResult) {
+ chomp $line;
+ if ( $line =~ m/${file}:\s+(clean|same)/ ) {
+ return "none";
+ }
+ } ## end for my $line (@lResult)
+ return $path;
+} ## end sub check_tree
# -----------------------------------------------------------------------
# --- Checkout the given refid on $upstream_path ---
# --- Returns 1 on success, 0 otherwise. ---
# -----------------------------------------------------------------------
sub checkout_upstream {
- my ($commit) = @_;
+ my ($commit) = @_;
# It is completely in order to not wanting to checkout a specific commit.
defined($commit) and length($commit) or return 1;
@@ -337,43 +430,45 @@ sub checkout_upstream {
# Save the previous commit
try {
- @lOut = $git->rev_parse({short => 1}, "HEAD");
- } catch {
+ @lOut = $git->rev_parse( { short => 1 }, "HEAD" );
+ }
+ catch {
print "ERROR: Couldn't rev-parse $upstream_path HEAD\n";
print "Exit Code : " . $_->status . "\n";
- print "Message : " . $_->error . "\n";
+ print "Message : " . $_->error . "\n";
return 0;
};
$previous_refid = $lOut[0];
# Get the shortened commit hash of $commit
try {
- @lOut = $git->rev_parse({short => 1}, $commit);
- } catch {
+ @lOut = $git->rev_parse( { short => 1 }, $commit );
+ }
+ catch {
print "ERROR: Couldn't rev-parse $upstream_path \"$commit\"\n";
print "Exit Code : " . $_->status . "\n";
- print "Message : " . $_->error . "\n";
+ print "Message : " . $_->error . "\n";
return 0;
};
$new_commit = $lOut[0];
# Now check it out, unless we are already there:
- if ($previous_refid ne $new_commit) {
+ if ( $previous_refid ne $new_commit ) {
print "Checking out $new_commit in upstream tree...";
try {
$git->checkout($new_commit);
- } catch {
+ }
+ catch {
print "\nERROR: Couldn't checkout \"new_commit\" in $upstream_path\n";
print "Exit Code : " . $_->status . "\n";
- print "Message : " . $_->error . "\n";
+ print "Message : " . $_->error . "\n";
return 0;
};
print " done\n";
- }
+ } ## end if ( $previous_refid ne...)
return 1;
-}
-
+} ## end sub checkout_upstream
# -----------------------------------------------------------------------
# --- Finds all relevant files and store them in @wanted_files ---
@@ -390,30 +485,36 @@ sub generate_file_list {
# The idea now is, that we use File::Find to search for files
# in all legal directories this program allows.
print "Find relevant files...";
- for my $xDir ("docs", "factory", "m4", "man", "shell-completion", "src", "tools") {
+ for my $xDir ( "docs", "factory", "m4", "man", "shell-completion", "src", "tools" ) {
if ( -d "$xDir" ) {
- find(\&wanted, "$xDir");
+ find( \&wanted, "$xDir" );
}
}
# There are also root files we need to check. Thanks to the usage of
# check_tree.pl to generate the later commit diffs, these can be safely
# added to our file list as well.
- for my $xFile ("Makefile", "Makefile.am", "TODO", "CODING_STYLE", "configure",
- ".mailmap", "LICENSE.GPL2", "meson_options.txt", "NEWS",
- "meson.build", "configure.ac", ".gitignore") {
+ for my $xFile ( "Makefile", "Makefile.am", "TODO", "CODING_STYLE", "configure", ".mailmap", "LICENSE.GPL2", "meson_options.txt", "NEWS", "meson.build", "configure.ac", ".gitignore" ) {
-f "$xFile" and push @source_files, "./$xFile";
}
- print " done\n";
+ print " done - " . ( scalar @source_files ) . " files found\n";
# Just to be sure...
scalar @source_files
- or print("ERROR: No source files found? Where the hell are we?\n")
- and return 0;
+ or print("ERROR: No source files found? Where the hell are we?\n")
+ and return 0;
+
+ # Eventually we can add each directory to %hDirectories
+ for my $xFile (@source_files) {
+ my $xDir = dirname($xFile);
+ $xDir =~ s,^\./,,;
+ if ( length($xDir) > 1 ) {
+ defined( $hDirectories{$xDir} ) or $hDirectories{$xDir} = 1;
+ }
+ } ## end for my $xFile (@source_files)
return 1;
-}
-
+} ## end sub generate_file_list
# ------------------------------------------------------------------------------
# --- Find or read the last mutual refid between this and the upstream tree. ---
@@ -423,54 +524,47 @@ sub get_last_mutual {
# No matter whether the commit is set or not, we need to read the
# commit file now, and write it back later if we have changes.
if ( -f $COMMIT_FILE ) {
- if (open my $fIn, "<", $COMMIT_FILE) {
+ if ( open my $fIn, "<", $COMMIT_FILE ) {
my @lLines = <$fIn>;
close $fIn;
-
+
for my $line (@lLines) {
chomp $line;
if ( $line =~ m/^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*$/ ) {
my $ref = $1;
my $src = $3;
my $tgt = $4;
- $hMutuals{$ref} = {
- mutual => $2,
- src => undef,
- tgt => undef
- };
+ $hMutuals{$ref} = { mutual => $2, src => undef, tgt => undef };
$src =~ m/^src-(\S+)$/ and $hMutuals{$ref}{src} = $1;
$tgt =~ m/^tgt-(\S+)$/ and $hMutuals{$ref}{tgt} = $1;
- }
- }
+ } ## end if ( $line =~ m/^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s*$/)
+ } ## end for my $line (@lLines)
} else {
print("ERROR: $COMMIT_FILE can not be read!\n$!\n");
return 0;
}
- }
+ } ## end if ( -f $COMMIT_FILE )
# If this is already set, we are fine.
if ( length($mutual_commit) ) {
$hMutuals{$wanted_refid}{mutual} = $mutual_commit;
return 1;
}
-
+
# Now check against --advance and then set $mutual_commit accordingly.
- if (defined($hMutuals{$wanted_refid})) {
+ if ( defined( $hMutuals{$wanted_refid} ) ) {
if ($do_advance) {
- defined($hMutuals{$wanted_refid}{src})
- and $hMutuals{$wanted_refid}{mutual} = $hMutuals{$wanted_refid}{src}
- or print "ERROR: --advance set, but no source hash found!\n"
- and return 0;
+ defined( $hMutuals{$wanted_refid}{src} ) and $hMutuals{$wanted_refid}{mutual} = $hMutuals{$wanted_refid}{src}
+ or print "ERROR: --advance set, but no source hash found!\n" and return 0;
}
$mutual_commit = $hMutuals{$wanted_refid}{mutual};
return 1;
- }
-
+ } ## end if ( defined( $hMutuals...))
+
print "ERROR: There is no last mutual commit known for refid \"$wanted_refid\"!\n";
-
- return 0;
-}
+ return 0;
+} ## end sub get_last_mutual
# -----------------------------------------------------------------------
# --- parse the given list for arguments. ---
@@ -478,49 +572,51 @@ sub get_last_mutual {
# --- sets global $show_help to 1 if the long help should be printed. ---
# -----------------------------------------------------------------------
sub parse_args {
- my @args = @_;
- my $result = 1;
+ my @args = @_;
+ my $result = 1;
- for (my $i = 0; $i < @args; ++$i) {
+ for ( my $i = 0 ; $i < @args ; ++$i ) {
# Check --advance option
- if ($args[$i] =~ m/^--advance$/) {
+ if ( $args[$i] =~ m/^--advance$/ ) {
$do_advance = 1;
}
# Check for -c|--commit option
# -------------------------------------------------------------------------------
- elsif ($args[$i] =~ m/^-(?:c|-commit)$/) {
- if ( ( ($i + 1) >= @args )
- || ( $args[$i+1] =~ m,^[-/.], ) ) {
+ elsif ( $args[$i] =~ m/^-(?:c|-commit)$/ ) {
+ if ( ( ( $i + 1 ) >= @args )
+ || ( $args[ $i + 1 ] =~ m,^[-/.], ) )
+ {
print "ERROR: Option $args[$i] needs a refid as argument!\n\nUsage: $USAGE_SHORT\n";
$result = 0;
next;
- }
- $mutual_commit = $args[++$i];
- }
+ } ## end if ( ( ( $i + 1 ) >= @args...))
+ $mutual_commit = $args[ ++$i ];
+ } ## end elsif ( $args[$i] =~ m/^-(?:c|-commit)$/)
# Check for -h|--help option
# -------------------------------------------------------------------------------
- elsif ($args[$i] =~ m/^-(?:h|-help)$/) {
+ elsif ( $args[$i] =~ m/^-(?:h|-help)$/ ) {
$show_help = 1;
}
# Check for -o|--output option
# -------------------------------------------------------------------------------
- elsif ($args[$i] =~ m/^-(?:o|-output)$/) {
- if ( ( ($i + 1) >= @args )
- || ( $args[$i+1] =~ m,^[-/.], ) ) {
+ elsif ( $args[$i] =~ m/^-(?:o|-output)$/ ) {
+ if ( ( ( $i + 1 ) >= @args )
+ || ( $args[ $i + 1 ] =~ m,^[-/.], ) )
+ {
print "ERROR: Option $args[$i] needs a path as argument!\n\nUsage: $USAGE_SHORT\n";
$result = 0;
next;
- }
- $output_path = abs_path($args[++$i]);
- }
+ } ## end if ( ( ( $i + 1 ) >= @args...))
+ $output_path = abs_path( $args[ ++$i ] );
+ } ## end elsif ( $args[$i] =~ m/^-(?:o|-output)$/)
# Check for unknown options:
# -------------------------------------------------------------------------------
- elsif ($args[$i] =~ m/^-/) {
+ elsif ( $args[$i] =~ m/^-/ ) {
print "ERROR: Unknown option \"$args[$i]\" encountered!\n\nUsage: $USAGE_SHORT\n";
$result = 0;
}
@@ -529,51 +625,212 @@ sub parse_args {
# -------------------------------------------------------------------------------
else {
# But only if they are not set, yet:
- if (length($upstream_path) && length($wanted_refid)) {
+ if ( length($upstream_path) && length($wanted_refid) ) {
print "ERROR: Superfluous argument \"$args[$i]\" found!\n\nUsage: $USAGE_SHORT\n";
$result = 0;
next;
}
- if (length($upstream_path) ) {
+ if ( length($upstream_path) ) {
$wanted_refid = "$args[$i]";
} else {
- if ( ! -d "$args[$i]") {
+ if ( !-d "$args[$i]" ) {
print "ERROR: Upstream path \"$args[$i]\" does not exist!\n\nUsage: $USAGE_SHORT\n";
$result = 0;
next;
}
- $upstream_path = abs_path($args[$i]);
- }
- }
- } ## End looping arguments
+ $upstream_path = abs_path( $args[$i] );
+ } ## end else [ if ( length($upstream_path...))]
+ } ## end else [ if ( $args[$i] =~ m/^--advance$/)]
+ } ## End looping arguments
# If we have no refid now, show short help.
- if ($result && !$show_help && !length($wanted_refid) ) {
+ if ( $result && !$show_help && !length($wanted_refid) ) {
print "ERROR: Please provide a path to upstream and a refid!\n\nUsage: $USAGE_SHORT\n";
$result = 0;
}
# If both --advance and --commit were used, we can not tell what the
# user really wants. So better be safe here, or we might screw the tree!
- if ($do_advance && length($mutual_commit)) {
+ if ( $do_advance && length($mutual_commit) ) {
print "ERROR: You have used both --advance and --commit.\n";
print " Which one is the one you really want?\n\n";
print "Usage: $USAGE_SHORT\n";
$result = 0;
- }
+ } ## end if ( $do_advance && length...)
return $result;
-} ## parse_srgs() end
+} ## parse_srgs() end
+
+# --------------------------------------------------------------
+# --- Use check_tree.pl to generate valid diffs on all valid ---
+# --- files within the patch with the given number. ---
+# --------------------------------------------------------------
+sub rework_patch {
+ my ($pFile) = @_;
+ my @lLines = ();
+
+ if ( open( my $fIn, "<", $pFile ) ) {
+ @lLines = <$fIn>;
+ close($fIn);
+ chomp(@lLines);
+ } else {
+ print "\nERROR: $pFile could not be opened for reading!\n$!\n";
+ return 0;
+ }
+
+ # Copy the header, ended by either '---' or 'diff '
+ # ----------------------------------------------------------
+ my @lOut = ();
+ my $lCnt = scalar @lLines;
+ my $commit = "";
+
+ while ( $lCnt-- > 0 ) {
+
+ # Can not be done in while(), or empty lines would break the loop.
+ my $line = shift @lLines;
+
+ # We break this once we have found a file summary line
+ if ( $line =~ m/^\s+(\S+)\s+\|\s+\d+/ ) {
+ unshift @lLines, $line; ## Still needed
+ ++$lCnt; ## Yeah, put it up again!
+ last;
+ }
+
+ # Before transfering the line, see if this is the commit info
+ $line =~ m/^From (\S+)\s\w{3}\s\w{3}\s\d{2}/ and $commit = $1;
+
+ push @lOut, $line;
+ } ## end while ( $lCnt-- > 0 )
+ # There is something wrong if we have no commit hash now
+ if ( 0 == length($commit) ) {
+ print "\nERROR: No 'From <hash>' line found!\n";
+ return 0;
+ }
+
+ # There is something wrong if the next part is not a file summary line.
+ # ----------------------------------------------------------------------
+ if ( !defined( $lLines[0] ) || !( $lLines[0] =~ m/^\s+(\S+)\s+\|\s+\d+/ ) ) {
+ print "\nERROR: No file summary block found!\n";
+ print "The line currently looked at is:\n";
+ print "|" . ( defined( $lLines[0] ) ? $lLines[0] : "UNDEF" ) . "|\n";
+ print "We still have $lCnt lines to go.\n";
+ print "\nlOut so far:\n" . join( "\n", @lOut ) . "\n---------- END\n";
+ return 0;
+ } ## end if ( !defined( $lLines...))
+
+ my @lFixedPatches = ();
+ while ( $lCnt-- > 0 ) {
+ my $isNew = 0; ## 1 if we hit a creation summary line
+ my $line = shift @lLines;
+ my $real = ""; ## The real file to work with
+ my $src = ""; ## Source in upstream
+ my $tgt = ""; ## Target in downstream
+
+ # This ends on the first empty line.
+ $line =~ m/^\s*$/ and push( @lOut, "" ) and last;
+
+ # This is either a line modification information, or a
+ # creation line of a new file. These look like this...
+ # src/shared/meson.build | 1 +
+ $line =~ m/^\s+(\S+)\s+\|.*/ and $src = $1;
+
+ # ...or that:
+ # create mode 100644 src/network/netdev/wireguard.c
+ $line =~ m/^\s+create\s+mode\s+\d+\s+(\S+)\s*$/
+ and $src = $1
+ and $isNew = 1;
+
+ # Otherwise it is the modification summary line
+ length($src) or push( @lOut, $line ) and next;
+
+ $tgt = $src;
+ $tgt =~ s/systemd/elogind/g;
+
+ # The determination what is valid is different for whether this is
+ # the modification of an existing or the creation of a new file
+ if ($isNew) {
+ defined( $hDirectories{ dirname($src) } ) and $real = $src;
+ defined( $hDirectories{ dirname($tgt) } ) and $real = $tgt;
+ } else {
+
+ # Try the renamed first, then the non-renamed
+ defined( $hFiles{$tgt} ) and $real = $tgt
+ or defined( $hFiles{$src} )
+ and $real = $src;
+ } ## end else [ if ($isNew) ]
+
+ # We neither need diffs on invalid files, nor new files in invalid directories.
+ length($real) or next;
+
+ # Now use $real to get the patch needed, if it is set.
+ my $pNew = check_tree( $commit, $real, $isNew );
+
+ # If no patch was generated, the file is either "same" or "clean".
+ $pNew eq "none" and next;
+
+ # However, an empty $pNew indicates an error. (check_tree() has it reported already.)
+ length($pNew) and push @lFixedPatches, $pNew or return 0;
+
+ # If we are here, transfer the file line. It is useful.
+ push @lOut, $line;
+ } ## End of scanning lines
+
+ scalar @lFixedPatches or next;
+
+ # Load all generated patches and add them to lOut
+ # ----------------------------------------------------------
+ for my $pNew (@lFixedPatches) {
+ if ( open my $fIn, "<", $pNew ) {
+ my @lNew = <$fIn>;
+ close($fIn);
+ chomp(@lNew);
+ push @lOut, @lNew;
+ unlink $pNew;
+ } else {
+ print "\nERROR: Can't open $pNew for reading!\n$!\n";
+ return 0;
+ }
+ } ## end for my $pNew (@lFixedPatches)
+
+ # Eventually overwrite $pFile with @lOut
+ # ----------------------------------------------------------
+ if ( open( my $fOut, ">", $pFile ) ) {
+ print $fOut join( "\n", @lOut ) . "\n";
+ close($fOut);
+ } else {
+ print "\nERROR: Can not opne $pFile for writing!\n$!\n";
+ }
+
+ return 1;
+} ## end sub rework_patch
+
+# Helper to show the argument as a non permanent progress line.
+sub show_prg {
+ my ($msg) = @_;
+ my $len = length($prg_line);
+
+ $len and print "\r" . ( ' ' x $len ) . "\r";
+
+ $prg_line = $msg;
+
+ if ( length($prg_line) ) {
+ local $| = 1;
+ print $msg;
+ }
+
+ return 1;
+} ## end sub show_prg
# Callback function for File::Find
sub wanted {
my $f = $File::Find::name;
- $f =~ m,^\./, or $f = "./$f";
+ $f =~ m,^\./, or $f = "./$f";
- -f $_ and (! ($_ =~ m/\.pwx$/ ) )
- and push @source_files, $File::Find::name;
+ -f $_
+ and ( !( $_ =~ m/\.pwx$/ ) )
+ and push @source_files, $File::Find::name;
return 1;
-}
+} ## end sub wanted