%PDF- %PDF-
Direktori : /usr/share/perl5/vendor_perl/App/Ack/ |
Current File : //usr/share/perl5/vendor_perl/App/Ack/ConfigFinder.pm |
package App::Ack::ConfigFinder; =head1 NAME App::Ack::ConfigFinder =head1 DESCRIPTION A module that contains the logic for locating the various configuration files. =head1 LOCATING CONFIG FILES First, ack looks for a global ackrc. =over =item On Windows, this is `ackrc` in either COMMON_APPDATA or APPDATA. If `ackrc` is present in both directories, ack uses both files in that order. =item On a non-Windows OS, this is `/etc/ackrc`. =back Then, ack looks for a user-specific ackrc if the HOME environment variable is set. This is either F<$HOME/.ackrc> or F<$HOME/_ackrc>. Then, ack looks for a project-specific ackrc file. ack searches up the directory hierarchy for the first `.ackrc` or `_ackrc` file. If this is one of the ackrc files found in the previous steps, it is not loaded again. It is a fatal error if a directory contains both F<.ackrc> and F<_ackrc>. After ack loads the options from the found ackrc files, ack looks at the C<ACKRC_OPTIONS> environment variable. Finally, ack takes settings from the command line. =cut use strict; use warnings; use App::Ack (); use App::Ack::ConfigDefault; use Cwd 3.00 (); use File::Spec 3.00; use if ($^O eq 'MSWin32'), 'Win32'; =head1 METHODS =head2 new Creates a new config finder. =cut sub new { my ( $class ) = @_; return bless {}, $class; } sub _remove_redundancies { my @configs = @_; my %seen; foreach my $config (@configs) { my $key = $config->{path}; if ( not $App::Ack::is_windows ) { # On Unix, uniquify on inode. my ($dev, $inode) = (stat $key)[0, 1]; $key = "$dev:$inode" if defined $dev; } undef $config if $seen{$key}++; } return grep { defined } @configs; } sub _check_for_ackrc { return unless defined $_[0]; my @files = grep { -f } map { File::Spec->catfile(@_, $_) } qw(.ackrc _ackrc); die File::Spec->catdir(@_) . " contains both .ackrc and _ackrc.\n" . "Please remove one of those files.\n" if @files > 1; return wantarray ? @files : $files[0]; } # end _check_for_ackrc =head2 $finder->find_config_files Locates config files, and returns a list of them. =cut sub find_config_files { my @config_files; if ( $App::Ack::is_windows ) { push @config_files, map { +{ path => File::Spec->catfile($_, 'ackrc') } } ( Win32::GetFolderPath(Win32::CSIDL_COMMON_APPDATA()), Win32::GetFolderPath(Win32::CSIDL_APPDATA()), ); } else { push @config_files, { path => '/etc/ackrc' }; } if ( $ENV{'ACKRC'} && -f $ENV{'ACKRC'} ) { push @config_files, { path => $ENV{'ACKRC'} }; } else { push @config_files, map { +{ path => $_ } } _check_for_ackrc($ENV{'HOME'}); } my $cwd = Cwd::getcwd(); return () unless defined $cwd; # XXX This should go through some untainted cwd-fetching function, and not get untainted brute-force like this. $cwd =~ /(.+)/; $cwd = $1; my @dirs = File::Spec->splitdir( $cwd ); while(@dirs) { my $ackrc = _check_for_ackrc(@dirs); if(defined $ackrc) { push @config_files, { project => 1, path => $ackrc }; last; } pop @dirs; } # We only test for existence here, so if the file is deleted out from under us, this will fail later. return _remove_redundancies( @config_files ); } =head2 read_rcfile Reads the contents of the .ackrc file and returns the arguments. =cut sub read_rcfile { my $file = shift; return unless defined $file && -e $file; my @lines; open( my $fh, '<', $file ) or App::Ack::die( "Unable to read $file: $!" ); while ( my $line = <$fh> ) { chomp $line; $line =~ s/^\s+//; $line =~ s/\s+$//; next if $line eq ''; next if $line =~ /^\s*#/; push( @lines, $line ); } close $fh or App::Ack::die( "Unable to close $file: $!" ); return @lines; } 1;