This is a lesson on how to write a PerlNomic proposal which patches other files. This is important because (so far) much of the game consists of patching existing files, including both CGI scripts and proposals. (And sometimes other files, such as when RobAdams attemped to patch players.txt to remove himself from the game.)

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.

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:

 # Description of what my patch does
 # Author: my name
 # Date: today's date

 open (PATCH, "|patch -p1");
 print 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:

FunWiki | RecentChanges | Preferences
Edit text of this page | View other revisions
Last edited October 22, 2002 10:57 (diff)