Config::Patch - Patch configuration files and unpatch them later
use Config::Patch;
my $patcher = Config::Patch->new(
file => "/etc/syslog.conf",
key => "mypatch",
);
# Append a patch:
$patcher->append(q{
# Log my stuff
my.* /var/log/my
});
# Appends the following to /etc/syslog.conf:
*-------------------------------------------
| ...
| #(Config::Patch-mypatch-append)
| # Log my stuff
| my.* /var/log/my
| #(Config::Patch-mypatch-append)
*-------------------------------------------
# Prepend a patch:
$patcher->prepend(q{
# Log my stuff
my.* /var/log/my
});
# Prepends the following to /etc/syslog.conf:
*-------------------------------------------
| #(Config::Patch-mypatch-append)
| # Log my stuff
| my.* /var/log/my
| #(Config::Patch-mypatch-append)
| ...
*-------------------------------------------
# later on, to remove the patch:
$patcher->remove();
Config::Patch helps changing configuration files, remembering the changes,
and undoing them if necessary.
Every change (patch) is marked by a key, which must be unique for the change, in order allow undoing it later on.
To facilitate its usage, Config::Patch comes with a command line script
that performs all functions:
# Append a patch
echo "my patch text" | config-patch -a -k key -f textfile
# Patch a file by search-and-replace
echo "none:" | config-patch -s 'all:.*' -k key -f config_file
# Comment out sections matched by a regular expression:
config-patch -c '(?ms-xi:^all:.*?\n\n)' -k key -f config_file
# Remove a previously applied patch
config-patch -r -k key -f textfile
Note that 'patch' doesn't refer to a patch in the format used by the patch
program, but to an arbitrary section of text inserted into a file. Patches
are line-based, Config::Patch always adds/removes entire lines.
Config::Patch assumes that lines starting with a comment
character are ignored by their applications. This is important,
since Config::Patch uses comment lines to hides vital patch
information in them for recovering from patches later on.
By default, this comment character is '#', usable for file formats like YAML, Makefiles, and Perl. To change this default and use a different character, specify the comment character like
my $patcher = Config::Patch->new(
comment_char => ";", # comment char is now ";"
# ...
);
in the constructor call. The command line script config-patch
expects a different comment character with the -C option,
check its manpage for details.
Make sure to use the same comment character
for patching and unpatching, otherwise chaos will ensue.
Other than that, Config::Patch is format-agnostic.
If you need to pay attention
to the syntax of the configuration file to be patched, create a subclass
of Config::Patch and put the format specific logic there.
You can only patch a file once with a given key. Note that a single
patch might result in multiple patched sections within a file
if you're using the replace() or comment_out() methods.
To apply different patches to the same file, use different keys. They can be can rolled back separately.
$patcher = Config::Patch->new(file => $file, key => $key)
Creates a new patcher object. Optionally, exclusive updates are ensured
by flocking if the flock parameter is set to 1:
my $patcher = Config::Patch->new(
file => $file,
key => $key,
flock => 1,
);
$patcher->append($textstring)
Appends a text string to the config file.
$patcher->prepend($textstring)
Adds a text string to the beginning of the file.
$patcher->remove()
Remove a previously applied patch.
The patch key has either been provided
with the constructor call previously or can be
supplied as key => $key.
$patcher->patched()
Checks if a patch with the given key was applied to the file already.
The patch key has either been provided
with the constructor call previously or can be
supplied as key => $key.
$patcher->replace($search, $replace)
Patches by searching for a given pattern $search (regexp) and replacing
it by the text string $replace. Example:
# Replace the 'all:' target in a Makefile and all
# of its production rules by a dummy rule.
$patcher->replace(qr(^all:.*?\n\n)sm,
"all:\n\techo 'all is gone!'\n");
Note that the replace command will replace the entire line if it finds that a regular expression is matching a partial line.
CAUTION: Make sure your $search patterns only cover the areas
you'd like to replace. Multiple matches within one line are ignored,
and so are matches that overlap with areas patched with different
keys (forbidden zones).
$patcher->insert($search, $replace, $after)
Patches by searching for a given pattern $search (regexp) and inserting
the text string $replace. By default, the inserted text will appear
on the line above the regex. If $after is defined, then the text is
inserted below the regex line. Example:
# Insert "myoption" into "[section]".
$patcher->insert(qr([section]),
"myoption", "after");
CAUTION: Make sure your $search patterns only cover the areas
you'd like to insert. Multiple matches within one line are ignored,
and so are matches that overlap with areas patched with different
keys (forbidden zones).
$patcher->comment_out($search)
Patches by commenting out config lines matching the regular expression
$search. Example:
# Remove the 'all:' target and its production rules
# from a makefile
$patcher->comment_out(qr(^all:.*?\n\n)sm);
Commenting out is just a special case of replace(). Check its
documentation for details.
$patcher->key($key)
Set a new patch key for applying subsequent patches.
($arrayref, $hashref) = $patcher->patches()
Examines the file and locates all patches.
It returns two results:
$arrayref, a reference to an array, mapping patch keys to the
text of the patched sections:
$arrayref = [ ['key1', 'patchtext1'], ['key2', 'patchtext2'],
['key2', 'patchtext3'] ];
Note that there can be several patched sections appearing under
the same patch key (like the two non-consecutive sections under
key2 above).
The second result is a reference $hashref to a hash, holding all
patch keys as keys. Its values are the number of patch sections
appearing under a given key.
Config::Patch assumes that a hashmark (#) at the beginning of a line
in the configuration file marks a comment.
Copyright 2005 by Mike Schilli. This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Thanks to Steve McNeill for adding insert(), which adds patches
before or after line matches.
2005, Mike Schilli <cpan@perlmeister.com>