[netfilter-cvslog] r4020 - in trunk/patch-o-matic-ng: . patch2pom

laforge at netfilter.org laforge at netfilter.org
Mon Jun 27 11:10:24 CEST 2005


Author: laforge at netfilter.org
Date: 2005-06-27 11:10:23 +0200 (Mon, 27 Jun 2005)
New Revision: 4020

Added:
   trunk/patch-o-matic-ng/patch2pom/
   trunk/patch-o-matic-ng/patch2pom/PatchChunk.pm
   trunk/patch-o-matic-ng/patch2pom/PatchFile.pm
   trunk/patch-o-matic-ng/patch2pom/README
   trunk/patch-o-matic-ng/patch2pom/patch2pom
Log:
add the new patch2pom tool by Jonas Berlin


Added: trunk/patch-o-matic-ng/patch2pom/PatchChunk.pm
===================================================================
--- trunk/patch-o-matic-ng/patch2pom/PatchChunk.pm	2005-06-27 09:10:08 UTC (rev 4019)
+++ trunk/patch-o-matic-ng/patch2pom/PatchChunk.pm	2005-06-27 09:10:23 UTC (rev 4020)
@@ -0,0 +1,192 @@
+#!/usr/bin/perl -w
+#
+# PatchChunk.pm helper package for the patch2pom script
+# (C) 2005      by Jonas Berlin <xkr47 at outerspace.dyndns.org>
+#
+# This code is subject to the GNU GPLv2
+#
+# This package represents a chunk of a diff -Nru style file, where a
+# chunk means a block starting with "@@ -1,2 +3,4 @@" and the
+# lines following that belong to that block.
+
+package PatchChunk;
+
+use strict;
+
+our $TYPE_NONE = 0;
+our $TYPE_BOTH = 1;
+our $TYPE_NEW = 2;
+our $TYPE_OLD = 3;
+
+my $NONEWLINE_STR = "\\ No newline at end of file\n";
+
+sub typename {
+    my $this = shift;
+    my $type = shift;
+    if($type == $TYPE_NONE) {
+	return "NONE";
+    } elsif($type == $TYPE_BOTH) {
+	return "BOTH";
+    } elsif($type == $TYPE_NEW) {
+	return "NEW";
+    } elsif($type == $TYPE_OLD) {
+	return "OLD";
+    } else {
+	return "<INVALID $type>";
+    }
+}
+
+
+sub _typechar {
+    my $type = shift;
+    if($type == $TYPE_NONE) {
+	return "";
+    } elsif($type == $TYPE_BOTH) {
+	return " ";
+    } elsif($type == $TYPE_NEW) {
+	return "+";
+    } elsif($type == $TYPE_OLD) {
+	return "-";
+    } else {
+	return "INVALIDTYPE $type ";
+    }
+}
+
+sub _warnonce {
+    my $this = shift;
+    my $warning = shift;
+
+    unless($this->{_warned}->{$warning}) {
+	$this->{_warned}->{$warning} = 1;
+	print STDERR "\033[36;1;40mWarning: $warning\033[m\n";
+    }
+}
+
+sub new {
+    my $class = shift;
+    $class = ref($class) || $class;
+    my $this = {}; # $class->SUPER::new();
+    bless $this, $class;
+
+    my $line = shift;
+    return undef unless($line =~ /^\@\@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? \@\@.*$/);
+
+    $this->{oldstart}  = $1;
+    $this->{oldlen}    = defined($2) ? $2 : 1;
+    $this->{newstart}  = $3;
+    $this->{newlen}    = defined($4) ? $4 : 1;
+
+    $this->{_oldleft}  = $this->{oldlen};
+    $this->{_newleft}  = $this->{newlen};
+
+    $this->{_state}     = $TYPE_NONE;
+    $this->{nonewline} = 0;
+    $this->{finished}  = 0;
+
+    $this->{_warned}    = {};
+
+    return $this;
+}
+
+sub _finish_minichunk {
+    my $this = shift;
+
+    if($this->{_state} != $TYPE_NONE) {
+	push @{$this->{minichunks}}, $this->{lines};
+	push @{$this->{minichunktypes}}, $this->{_state};
+    }
+}
+
+# to be used at EOF or unidentified data
+sub finish {
+    my $this = shift;
+    return if($this->{finished});
+    $this->{finished} = 1;
+    $this->_finish_minichunk();
+    $this->_warnonce("diff counters broken\n") if($this->{_oldleft} != 0 || $this->{_newleft} != 0);
+}
+
+sub add_line {
+    my $this = shift;
+    my $line = shift;
+
+    if($this->{finished}) {
+	return 0;
+    }
+
+    my $newstate;
+    if($line =~ /^ /) {
+	$newstate = $TYPE_BOTH;
+    } elsif($line =~ /^\+/) {
+	$newstate = $TYPE_NEW;
+    } elsif($line =~ /^-/) {
+	$newstate = $TYPE_OLD;
+    } elsif($line eq $NONEWLINE_STR) {
+	$this->{nonewline} = 1;
+	$this->finish();
+	return 1;
+    } else {
+	$this->finish();
+	return 0;
+    }
+
+    if($newstate != $TYPE_NEW) {
+	if($this->{_oldleft} <= 0) {
+	    $this->{oldlen}++;
+	    $this->_warnonce("diff counters broken\n");
+	} else {
+	    $this->{_oldleft}--;
+	}
+    }
+
+    if($newstate != $TYPE_OLD) {
+	if($this->{_newleft} <= 0) {
+	    $this->{newlen}++;
+	    $this->_warnonce("diff counters broken\n");
+	} else {
+	    $this->{_newleft}--;
+	}
+    }
+
+    if($newstate != $this->{_state}) {
+	$this->_finish_minichunk();
+	$this->{lines} = [];
+	$this->{_state} = $newstate;
+    }
+
+    push @{$this->{lines}}, substr($line, 1);
+
+    return 1;
+}
+
+sub adjust_position {
+    my $this = shift;
+    my ($oldoff, $newoff) = @_;
+
+    $this->{oldstart} += $oldoff;
+    $this->{newstart} += $newoff;
+}
+
+sub format_minichunk {
+    my $this = shift;
+    my $idx = shift;
+
+    return "<INVALID IDX $idx>" if($idx < 0 || $idx >= scalar(@{$this->{minichunks}}));
+    my $char = _typechar($this->{minichunktypes}->[$idx]);
+    return $char.join($char,@{$this->{minichunks}->[$idx]});
+}
+
+sub format {
+    my $this = shift;
+    my $str;
+    $str = "@@ -".$this->{oldstart}.($this->{oldlen} != 1 ? ",".$this->{oldlen} : "");
+    $str .=  " +".$this->{newstart}.($this->{newlen} != 1 ? ",".$this->{newlen} : "");
+    $str .= " @@\n";
+    for(my $i=0; $i<scalar(@{$this->{minichunks}}); ++$i) {
+	$str .= $this->format_minichunk($i);
+    }
+    $str .= $NONEWLINE_STR if($this->{nonewline});
+    return $str;
+}
+
+1

Added: trunk/patch-o-matic-ng/patch2pom/PatchFile.pm
===================================================================
--- trunk/patch-o-matic-ng/patch2pom/PatchFile.pm	2005-06-27 09:10:08 UTC (rev 4019)
+++ trunk/patch-o-matic-ng/patch2pom/PatchFile.pm	2005-06-27 09:10:23 UTC (rev 4020)
@@ -0,0 +1,133 @@
+#!/usr/bin/perl -w
+#
+# PatchFile.pm helper package for the patch2pom script
+# (C) 2005      by Jonas Berlin <xkr47 at outerspace.dyndns.org>
+#
+# This code is subject to the GNU GPLv2
+#
+# This package represents a single file from a diff -Nru style patch.
+
+package PatchFile;
+
+use strict;
+
+my $STATE_DIFF_OR_MINUS = 0;
+my $STATE_MINUS = 1;
+my $STATE_PLUS = 2;
+my $STATE_CHUNKS = 10;
+
+sub new {
+    my $class = shift;
+    $class = ref($class) || $class;
+    my $this = {}; # $class->SUPER::new();
+    bless $this, $class;
+
+    $this->{_state}   = $STATE_DIFF_OR_MINUS;
+    $this->{finished} = 0;
+    $this->{success}  = 0;
+    $this->{started}  = 0;
+    $this->{chunks}   = [];
+
+    return $this;
+}
+
+sub _parse_fileline {
+    my $line = $_[0];
+
+    unless($line =~ /^...\s([^\t]+)\t(.*)/) {
+	print STDERR "\033[36;1;40mInvalid file line:\n$line\033[m\n";
+	exit(10);
+    }
+
+    return { file => $1, date => $2 };
+}
+
+sub _finish_chunk {
+    my $this = shift;
+
+    return unless(defined($this->{_chunk}));
+
+    $this->{_chunk}->finish();
+    push @{$this->{chunks}}, $this->{_chunk};
+    if($this->{_chunk}->{nonewline}) {
+	$this->{finished} = 1;
+	$this->{success} = 1;
+    }
+    $this->{_chunk} = undef;
+}
+
+# call at eof or next /^diff /
+sub finish {
+    my $this = shift;
+
+    $this->_finish_chunk();
+    $this->{finished} = 1;
+    $this->{success} = scalar(@{$this->{chunks}}) > 0;
+}
+
+sub format {
+    my $this = shift;
+    my $str = $this->{diffline};
+    $str .= "--- ".$this->{old}->{file}."\t".$this->{old}->{date}."\n";
+    $str .= "+++ ".$this->{new}->{file}."\t".$this->{new}->{date}."\n";
+    foreach my $chunk (@{$this->{chunks}}) {
+	$str .= $chunk->format();
+    }
+    return $str;
+}
+
+sub add_line {
+    my $this = shift;
+    my $line = shift;
+
+    return 0 if($this->{finished});
+
+    if(/^diff /) {
+	unless($this->{_state} == $STATE_DIFF_OR_MINUS) {
+	    $this->finish();
+	    return 0;
+	}
+	$this->{diffline} = $line;
+	$this->{_state} = $STATE_MINUS;
+	$this->{started} = 1;
+
+    } elsif(($this->{_state} == $STATE_DIFF_OR_MINUS || $this->{_state} == $STATE_MINUS) && /^--- /) {
+	$this->{old} = _parse_fileline($line);
+	$this->{_state} = $STATE_PLUS;
+	$this->{started} = 1;
+
+    } elsif($this->{_state} == $STATE_PLUS && /^\+\+\+ /) {
+	$this->{new} = _parse_fileline($line);
+	$this->{_state} = $STATE_CHUNKS;
+
+    } elsif($this->{_state} == $STATE_CHUNKS) {
+	my $isnewchunk = $line =~ /^@@/;
+
+	my $ret = 1;
+
+	if(defined($this->{_chunk})) {
+	    if($isnewchunk) {
+		$this->{_chunk}->finish();
+	    } else {
+		$ret = $this->{_chunk}->add_line($line);
+	    }
+
+	    if($this->{_chunk}->{finished}) {
+		$this->_finish_chunk();
+	    }
+	}
+
+	if($isnewchunk && !$this->{finished}) {
+	    $this->{_chunk} = new PatchChunk($_);
+	    $ret = 0 unless(defined($this->{_chunk}));
+	}
+
+	if(!$ret) {
+	    $this->finish();
+	    return 0;
+	}
+    } else {
+	return 0;
+    }
+    return 1;
+}

Added: trunk/patch-o-matic-ng/patch2pom/README
===================================================================
--- trunk/patch-o-matic-ng/patch2pom/README	2005-06-27 09:10:08 UTC (rev 4019)
+++ trunk/patch-o-matic-ng/patch2pom/README	2005-06-27 09:10:23 UTC (rev 4020)
@@ -0,0 +1,3 @@
+
+Please see top of patch2pom script for instructions.
+

Added: trunk/patch-o-matic-ng/patch2pom/patch2pom
===================================================================
--- trunk/patch-o-matic-ng/patch2pom/patch2pom	2005-06-27 09:10:08 UTC (rev 4019)
+++ trunk/patch-o-matic-ng/patch2pom/patch2pom	2005-06-27 09:10:23 UTC (rev 4020)
@@ -0,0 +1,350 @@
+#!/usr/bin/perl -w
+#
+# patch2pom, helper script for the patch-o-matic 'next generation' package
+# (C) 2005      by Jonas Berlin <xkr47 at outerspace.dyndns.org>
+#
+# This code is subject to the GNU GPLv2
+#
+# The separate PatchChunk.pm and PatchFile.pm files are required for
+# proper operation.
+#
+# This script takes a diff -Nru on input and converts it to
+# patch-o-matic-ng format by extracting new files from the diff as
+# separate files and making trivial updates to known file types using
+# "ladd" files. Any changes not matching the above criteria are passed
+# forward as a normal diff.
+#
+# If run as
+#
+#   ./patch2pom patch-o-matic/foobar/linux-2.6 < mypatch.patch
+#
+# .. then the command will create a directory structure below
+# patch-o-matic/foobar/linux-2.6/ with new files and/or .ladd files
+# when possible. Any parts of the diff that cannot be applied as new
+# files or .ladd files are passed forward to a patch file called
+# patch-o-matic/foobar/linux-2.6.patch. Example output directory
+# structure:
+#
+# pom-ng/foobar/linux-2.6/net/ipv4/netfilter/ipt_foobar.c
+# pom-ng/foobar/linux-2.6/net/ipv4/netfilter/Kconfig.ladd
+# pom-ng/foobar/linux-2.6/net/ipv4/netfilter/Makefile.ladd
+# pom-ng/foobar/linux-2.6/include/linux/netfilter_ipv4/ip_foo.h.ladd
+# pom-ng/foobar/linux-2.6/include/linux/netfilter_ipv4/ip_foo.h.ladd_2
+# ...
+# pom-ng/foobar/linux-2.6.patch
+#
+# Tip: when creating new versions of already existing modules in
+#      pom-ng, it might be convenient to give a different destination
+#      and then compare the results.
+#
+# Note: If files already exist in the given destination directory,
+#       they will not be removed, so before re-running the same
+#       command, you probably want to erase the old one first. The
+#       same goes for the patch optionally created by this script.
+
+BEGIN {
+    my $scripthome = $0;
+    $scripthome =~ s![^/]+$!!;
+    push @INC, $scripthome;
+}
+
+use strict;
+use File::Path;
+use Date::Parse;
+
+use PatchChunk;
+use PatchFile;
+
+my $pombase = shift @ARGV;
+
+unless(defined($pombase)) {
+
+    print STDERR 'usage: '.$0.' pomdir-base
+The command expects a diff -Nru style diff on standard input.
+
+Examples:
+
+diff -Nru orig-linux linux | '.$0.' patch-o-matic-ng/foobar/linux-2.6
+
+  This will create files in patch-o-matic-ng/foobar/linux-2.6/ and/or
+  a patch file patch-o-matic-ng/foobar/linux-2.6.patch
+
+diff -Nru orig-iptables iptables | '.$0.' patch-o-matic-ng/foobar/iptables
+
+  Creates files in .../iptables and/or patch file .../iptables.patch
+';
+    exit(1);
+}
+
+$pombase =~ s!/+$!!;
+
+sub create_file {
+    my ($file, $date, @content) = @_;
+
+    $file = $pombase.'/'.$file;
+
+    my $dir = $file;
+    $dir =~ s![^/]+$!!;
+
+    mkpath($dir);
+
+    open NEWFILE, '>', $file;
+    print NEWFILE @content;
+    close NEWFILE;
+
+    my $time = str2time($date);
+
+    utime($time, $time, $file);
+}
+
+my $patch_file_opened = 0;
+
+sub pprint {
+    unless($patch_file_opened) {
+	my $pomparent = $pombase;
+	$pomparent =~ s![^/]+$!!;
+	mkpath($pomparent) if(length($pomparent));
+
+	$patch_file_opened = 1 if(open PATCHFILE, '>', $pombase.'.patch');
+    }
+    print PATCHFILE @_;
+}
+
+# ensure that a FilePatch object only contains alternating "common" and "new" lines
+sub check_adds_only {
+    my $file = shift;
+
+    foreach my $chunk (@{$file->{chunks}}) {
+	my $state = 0;
+	foreach my $chunktype (@{$chunk->{minichunktypes}}) {
+	    if($chunktype != ($state ? $PatchChunk::TYPE_NEW : $PatchChunk::TYPE_BOTH)) {
+		return 0;
+	    }
+	    $state = !$state;
+	}
+    }
+
+    return 1;
+}
+
+my %ladd_idx;
+
+
+sub ladd_filename {
+    my $filename = shift;
+
+    $ladd_idx{$filename} = 1 unless(defined($ladd_idx{$filename}));
+    my $ladd_filename = $filename.".ladd";
+    $ladd_filename .= "_".$ladd_idx{$filename} if($ladd_idx{$filename} > 1);
+    $ladd_idx{$filename}++;
+
+    return $ladd_filename;
+}
+
+###### the core logic for creating new and .ladd files and .patch file
+sub handle_file {
+    my $file = shift;
+
+    my $filename = $file->{new}->{file};
+    $filename =~ s!^[^/]+/!!;
+
+    if(scalar(@{$file->{chunks}}) == 1 &&
+       $file->{chunks}->[0]->{oldstart} == 0 &&
+       $file->{chunks}->[0]->{oldlen} == 0 &&
+       scalar(@{$file->{chunks}->[0]->{minichunks}}) == 1 &&
+       $file->{chunks}->[0]->{minichunktypes}->[0] == $PatchChunk::TYPE_NEW) {
+
+	### It's a totally new file
+
+	my @content = @{$file->{chunks}->[0]->{minichunks}->[0]};
+	chomp $content[$#content] if($file->{chunks}->[0]->{nonewline});
+
+	create_file($filename, $file->{new}->{date}, @content);
+
+    } elsif($filename =~ m!/Kconfig$!) {
+
+	### 2.6 Kconfig
+
+	my $success = 0;
+
+	if(check_adds_only($file)) {
+
+	    $success = 1;
+	  kconfig_bail:
+	    foreach my $chunk (@{$file->{chunks}}) {
+		for(my $i=0; $i<scalar(@{$chunk->{minichunks}})-1; $i+=2) {
+
+		    my @lines = @{$chunk->{minichunks}->[$i+1]};
+		    my $state = 0;
+		    for($i=0; $i<=$#lines; ++$i) {
+			if($state == 0 && $lines[$i] =~ /^$/) {
+			    # do nothing
+			} elsif(($state == 0 || $state == 3) && $lines[$i] =~ /^config \S+$/) {
+			    $state = 1;
+			} elsif($state == 0) {
+			    $success = 0; last kconfig_bail;
+
+			} elsif($state >= 1 && $state <= 2) {
+			    if($lines[$i] =~ /^\t\S/) {
+				$state++;
+			    } else {
+				$success = 0; last kconfig_bail;
+			    }
+			} elsif($state == 3) {
+			    unless($lines[$i] =~ /^\t|^$/) {
+				$success = 0; last kconfig_bail;
+			    }
+			} else {
+			    die "Internal bug, please report\n";
+			}
+		    }
+
+		    ##TODO## maybe check that post-context matches /^\S/
+
+		    unless($state == 3) {
+			$success = 0; last kconfig_bail;
+		    }
+		}
+	    }
+
+	    if($success) {
+		foreach my $chunk (@{$file->{chunks}}) {
+		    for(my $i=0; $i<scalar(@{$chunk->{minichunks}})-1; $i+=2) {
+
+			my $ladd_filename = ladd_filename($filename);
+
+			my @lines = @{$chunk->{minichunks}->[$i+1]};
+
+			while($lines[$#lines] =~ /^$/) {
+			    delete $lines[$#lines];
+			}
+
+			create_file($ladd_filename, $file->{new}->{date}, @lines);
+		    }
+		}
+	    }
+	}
+
+	pprint $file->format() unless($success);
+
+    } elsif($filename =~ m!/Documentation/Configure\.help$!) {
+
+	### 2.4 Configure.help
+
+	##TODO## implement algorithm if somebody still wants this
+
+	pprint $file->format();
+
+    } elsif($filename =~ m!/(?:Makefile|Config\.in)$!) {
+
+	### Makefile
+	### 2.4 Config.in
+
+	if(check_adds_only($file)) {
+	    foreach my $chunk (@{$file->{chunks}}) {
+		for(my $i=0; $i<scalar(@{$chunk->{minichunks}})-1; $i+=2) {
+
+		    # pick last line of preceding context lines
+		    my $context_minichunk = $chunk->{minichunks}->[$i];
+		    my $context = @$context_minichunk[scalar(@{$context_minichunk})-1];
+
+		    my $ladd_filename = ladd_filename($filename);
+
+		    create_file($ladd_filename, $file->{new}->{date}, $context, @{$chunk->{minichunks}->[$i+1]});
+		}
+	    }
+
+	} else {
+	    pprint $file->format();
+	}
+
+    } elsif($filename =~ m![^/]\.[ch]$!) {
+
+	### *.c
+	### *.h
+
+	my $success = 0;
+
+	if(check_adds_only($file)) {
+	    $success = 1;
+
+	  source_bail:
+	    foreach my $chunk (@{$file->{chunks}}) {
+		for(my $i=0; $i<scalar(@{$chunk->{minichunks}})-1; $i+=2) {
+
+		    # pick last line of preceding context lines
+		    my $context_minichunk = $chunk->{minichunks}->[$i];
+		    my $context = @$context_minichunk[scalar(@{$context_minichunk})-1];
+
+		    # if "here" mentioned in comment, we accept
+		    unless($context =~ m!/\*(?:\*[^/]|[^*])+\shere(?:\*[^/]|[^*])*\*/!) {
+			$success = 0; last source_bail;
+		    }
+		}
+	    }
+
+	    ##TODO## we could accept partial .ladd conversion and modify the patch
+
+	    if($success) {
+		foreach my $chunk (@{$file->{chunks}}) {
+		    for(my $i=0; $i<scalar(@{$chunk->{minichunks}})-1; $i+=2) {
+
+			# pick last line of preceding context lines
+			my $context_minichunk = $chunk->{minichunks}->[$i];
+			my $context = @$context_minichunk[scalar(@{$context_minichunk})-1];
+
+			my $ladd_filename = ladd_filename($filename);
+
+			create_file($ladd_filename, $file->{new}->{date}, $context, @{$chunk->{minichunks}->[$i+1]});
+		    }
+		}
+	    }
+	}
+
+	pprint $file->format() unless($success);
+
+    } else {
+
+	### default
+
+	pprint $file->format();
+    }
+}
+
+############# main parse loop
+
+my $file = new PatchFile();
+
+while(<>) {
+    while(!$file->add_line($_)) {
+	unless($file->{started}) {
+	    if(/^Files .* differ$/) {
+		print STDERR "Ignoring: $_";
+	    } elsif(/^Only in/) {
+		print STDERR "ABORTING: It seems you forgot the -N flag from your diff command.. I got: $_";
+		exit(1);
+	    } elsif(/^Common /) {
+		print STDERR "ABORTING: It seems you forgot the -r flag from your diff command.. I got: $_";
+		exit(1);
+	    } elsif(/^[\d><]/) {
+		print STDERR "ABORTING: It seems you forgot the -u flag from your diff command.. I got: $_";
+		exit(1);
+	    } else {
+		print;
+	    }
+	    last;
+	}
+
+	if($file->{success}) {
+	    handle_file($file);
+	}
+
+	$file = new PatchFile();
+    }
+}
+
+$file->finish();
+
+handle_file($file) if($file->{success});
+
+close PATCHFILE if($patch_file_opened);


Property changes on: trunk/patch-o-matic-ng/patch2pom/patch2pom
___________________________________________________________________
Name: svn:executable
   + *




More information about the netfilter-cvslog mailing list