The easiest way to patch files is to use the UNIX "patch" utility (big surprise!) written by none other than LarryWall? himself. (LarryWall? is the same guy who wrote Perl.)
Another useful thing is to use Perl's support for "HERE document" quoting. This is a method of quoting which allows one to include arbitrary text verbatim into a string in Perl. This makes it easy to quote Perl code (otherwise you'd have to worry about accidently interpolating variables, etc.) which is useful because the files you'll be patching are probably Perl programs.
An example of "HERE document" quoting:
my $long_string = <<'END_OF_STRING'; This is the first line of the string. This is the second line of the string. I can include funny characters $@'"`[->blah and Perl won't care. END_OF_STRING
Now the scalar $long_string contains four lines of text. Notice that the terminating string must occur on a line by itself. See the CamelBook? or the perlop man page for more information.
Using the patch utility
Patch works by taking the output of the diff utility and applying it to your files. There are all sorts of options and output formats for diff but we'll keep things simple here and only use one set of options. Patch supports several different file formats, but with varying levels of support. I suggest using the "unified context diff" format. It's only supported by the GNU versions of diff and patch, but PerlNomic runs on Odin which is a Linux box. If you are developing your patches on a system with a non-GNU diff, then you may need to use a different format. See the diff and patch man pages and/or info pages for more information.
Generating your patch file
Make a directory called "old" and put all of your files in it. Now make a directory called "new" and put copies of all your files in it. Modify the files in "new" so they have all the changes you want. Now run the following command from the parent directory:
diff -Naur old new >> my.patch
This will make diff look at the directories old and new and record any differences in the files contained in the directories. It will write all of these differences to standard out, which you have redirected into the file my.patch. (obviously, you can change the name if you want.)
Take a look at the file my.patch to make sure it's doing what you want. The unified context diff format is pretty easy to figure out. Lines starting with "-" are being removed, and lines which start with "+" are being added.
I strongly recommend that you always use this old/new directory approach when making diffs. It's easier to keep things straight, plus it means that you'll always use the same "-p" option to patch (see below).
Creating your Perl script
Create a new file in your favorite text editor. Put the following into it:
#!/usr/bin/perl # # Description of what my patch does # # Author: my name # Date: today's date #
open (PATCH, "|patch -p1"); print PATCH <<'__END__OF__PATCH__'; __END__OF__PATCH__ close PATCH;
Now paste the contents of my.patch (or whatever you called it) between the "print" line and the "__END__OF__PATCH__" line. Make sure you don't add or delete any lines by accident! (if your patch file has some blank lines at the end, make sure to leave them there when you paste. You want the EXACT contents of the patch file to be contained there!
This is your PerlNomic proposal. Upload it to PerlNomic. Be very careful when pasting it into the form. (Perhaps the form should be modified to allow file uploads.. recent versions of HTML support this)
How it works
The "open" line forks off a patch process and sets up a pipe into it. The "-p1" option causes patch to ignore the first directory name in pathnames. (So it won't start looking for directories called "old" or "new".. instead it will strip off the directory name and look for the files in the current directory.)
The "print" statement writes the patch to the pipe. The patch process reads in the patch and patches the files.
You can put additional Perl code before the "open" line or after the "close" line if you need to do other stuff in addition to patching files.
Future additions for this guide: