package Brackup::Config; use strict; use Brackup::ConfigSection; use warnings; use Carp qw(croak); use Fcntl qw(O_WRONLY O_CREAT O_EXCL); sub new { my ($class) = @_; return bless {}, $class; } sub add_section { my ($self, $sec) = @_; $self->{$sec->name} = $sec; } sub load { my ($class, $file) = @_; $file ||= Brackup::Config->default_config_file_name; my $self = bless {}, $class; open (my $fh, $file) or do { if (write_dummy_config($file)) { die "Your config file needs tweaking. I put a commented-out template at: $file\n"; } else { die "No config file at: $file\n"; } }; my $sec = undef; while (my $line = <$fh>) { $line =~ s/^\#.*//; # kill comments starting at beginning of line $line =~ s/\s\#.*//; # kill comments with whitespace before the # (motivation: let # be in regexps) $line =~ s/^\s+//; $line =~ s/\s$//; next unless $line ne ""; if ($line =~ /^\[(.+)\]$/) { my $name = $1; $sec = Brackup::ConfigSection->new($name); die "Duplicate config section '$name'" if $self->{$name}; $self->{$name} = $sec; } elsif ($line =~ /^(\w+)\s*=\s*(.+)/) { die "Declaration of '$1' outside of a section." unless $sec; $sec->add($1, $2); } else { die "Bogus config line: $line"; } } unless ($sec) { die "Your config file needs tweaking. There's a starting template at: $file\n"; } return $self; } sub default_config_file_name { my ($class) = @_; if ($ENV{HOME}) { # Default for UNIX folk return "$ENV{HOME}/.brackup.conf"; } elsif ($ENV{APPDATA}) { # For Windows users return "$ENV{APPDATA}/brackup.conf"; } else { # Fall back on the current directory return "brackup.conf"; } } sub write_dummy_config { my $file = shift; sysopen (my $fh, $file, O_WRONLY | O_CREAT | O_EXCL, 0600) or return; print $fh <{"SOURCE:$name"} or die "Unknown source '$name'\n"; my $root = Brackup::Root->new($conf, $cache); # iterate over config's ignore, and add those foreach my $pat ($conf->values("ignore")) { $root->ignore($pat); } # common things to ignore $root->ignore(qr!~$!); $root->ignore(qr!^\.thumbnails/!); $root->ignore(qr!^\.kde/share/thumbnails/!); $root->ignore(qr!^\.ee/minis/!); $root->ignore(qr!^\.(gqview|nautilus)/thumbnails/!); # abort if the user had any configuration we didn't understand if (my @keys = $conf->unused_config) { die "Aborting, unknown configuration keys in SOURCE:$name: @keys\n"; } return $root; } sub load_target { my ($self, $name) = @_; my $confsec = $self->{"TARGET:$name"} or die "Unknown target '$name'\n"; my $type = $confsec->value("type") or die "Target '$name' has no 'type'"; die "Invalid characters in $name's 'type'" unless $type =~ /^\w+$/; my $class = "Brackup::Target::$type"; eval "use $class; 1;" or die "Failed to load ${name}'s driver: $@\n"; my $target = $class->new($confsec); if (my @unk_config = $confsec->unused_config) { die "Unknown config params in TARGET:$name: @unk_config\n"; } return $target; } 1; __END__ =head1 NAME Brackup::Config - configuration parsing/etc =head1 CONFIGURATION INFO For instructions on how to configure Brackup, see: L L L