###################################################################### Config::Patch 0.07 ###################################################################### NAME Config::Patch - Patch configuration files and unpatch them later SYNOPSIS 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(); DESCRIPTION "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. Specify a different comment character "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. METHODS "$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->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. LIMITATIONS "Config::Patch" assumes that a hashmark (#) at the beginning of a line in the configuration file marks a comment. COPYRIGHT AND LICENSE 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. AUTHOR 2005, Mike Schilli