=head1 NAME

File::RdistByRsync - read rdist distfiles, emulate using rsync

=head1 SYNOPSIS

	use File::RdistByRsync

	@dist_blocks = parse_rdist($distfile, %options)

	($args, $extras, @dist_blocks) = rdist(@ARGV);

	rsync(@ARGV)

	perl -MFile::RdistByRsync -e 'rsync(qw/rdist command flags/)'

=head1 DESCRIPTION

File::RdistByRsync parses and understands rdist distfiles and 
command lines.

It can share it's understanding by returning what it got
(C<parse_rdist()> and C<rdist()>) or it can attempt to
emulate rdist using rsync.

Why?

Well, because rdist is so slow it's unusable and 
rsync has such a limited interface that it's unusable.
I'm sure a better specification language than rdist's 
could be developed, but rdist's language already exists
so I used it to drive rsync.

=head1 WARNING

As of this writing, this code is still green.  Use the C<-D> C<-n> and C<-v>
options and look at the output.  Look carefully.  If it looks good,
then try running it for real.  If it deletes all your files, then
you didn't look carefully enough.  Don't blame me.  See the
LICENSE.

=head1 DATA STRUCTURE

The main return value from rdist is an array of distribution blocks.

They look like:

	{
		HOSTS		=> [ host1 user@host2 host3 etc...],
		FILES		=> [ /etc/rc.* /etc/hosts /usr etc...],
		EXCEPT		=> [
			# tuples of type & file
			EXCEPT_PAT	/etc/p.*d	# regular expression
			EXCEPT		/etc/rc.local	# glob
			RSYNC_EXCLUDE	/etc/rc.loc*	# glob-style pattern exclusions
			RSYNC_INCLUDE	/etc/rc.*	# glob-style pattern inclusions
		]
		SPECIAL		=> [
			    {
				FILES	=> /etc/login.conf	# glob okay
				COMMAND => "cap_mkdb $FILE"	# a command to run
			    },
			    {
				FILES	=> /etc/named.conf	# glob okay
				COMMAND => "ndc reload"		# a command to run
			    },
			]
		RSYNC_OPTION	=> [ --dry-run --verbose ]
		INSTALL		=> [
			    {
				DESTINATION => /usr		# where to install
				FLAGS 	    => {
					R => 1,			# remove extra
					w => 1,			# append whole path
				}
			    }
		TSFILE		=> /some/file			# touch file name
	}

=head1 DETAILS

	@dist_blocks = parse_rdist($distfile, %options)

There is one "dist_block" for each C<::> or C<-E<gt>> entry in 
the distfile.

The options supported by parse_rdist are C<DEFINES =E<gt> {}> which
override variable definitions made in the distfile and
C<TARGETS =E<gt> []> which filters the results so that
entries that don't match label targets (if any match) and files
that don't match file targets are removed.

	($args, $extras, @dist_blocks) = rdist(@ARGV);

C<$args> comes from L<Getopt::Declare>.  See the grammer inside 
File::RdistByRsync for full details, but basically C<$args->{"-y"}>
is true if C<@ARGV> contained C<-y>.

C<$extras> is a hash of a few items that are sometimes useful.
C<$extras->{HOSTS}> is the list of hosts specified with the C<-m>
option.  C<$extras->{DEFINES}> is a hash of C<-d> variable 
definitions.  C<$extras->{RSYNCOPT}> is a list of rsync options
specified in C<@ARGV>.  C<$extra->{TARGETS}> is a list of distfile
entries (by label) or filenames given in C<@ARGV> to limit the
scope of the invocation.  C<$extra->{CFLAG}> is a dist_block 
created if there is a command-line style distfile.

	rsync(@ARGV)

The C<rsync()> function does the whole job.  The C<@ARGV> parameter
should be an rdist-style command line.

=head1 COMPATABILITY

All rdist switches except C<-i> are honored.  The output is quite
different from rdist.  Multiple invocations of rsync can be
required to do a single rdist.

Two features of rdist are currently ignored: email notification
and timestamp checking with C<::> productions.

There are some additional features that are useful when using
C<rsync()>.

First, the long-form of rsync command line arguments are noticed 
by C<rdist()> and used by C<rsync()>.

Second, in the C<-E<gt>> productions, three new commands are available:

	'rsync_options'	<options> ';'
	'rsync_include'	<name list> ';'
	'rsync_exclude'	<name list> ';'

Rsync_options will be passed to any rsync commands called by
C<rsync()> that operate on the block in question.

Rsync_include and rsync_exclude will be passed to rsync with
"- " prepended for the excludes and "+ " prepended for the
includes.  When building rsync exclusion lists, the order of
the 'rsync_include', 'rsync_exclude', 'except', and 'except_pat'
are taken into account and preserved.

=head1 LICENSE  

Copyright (C) 2002 David Muir Sharnoff.  License hereby
granted for anyone to use, modify or redistribute this module at 
their own risk.  Use of this module consitutes an agreement to
indemnify and hold harmless the author(s) for whatever
might happen when using this code. Please feed useful changes back 
to muir@idiom.com.

