File Coverage

blib/lib/Sys/Config/Manage.pm
Criterion Covered Total %
statement 30 490 6.1
branch 0 202 0.0
condition 0 9 0.0
subroutine 10 30 33.3
pod 19 19 100.0
total 59 750 7.8


line stmt bran cond sub pod time code
1             package Sys::Config::Manage;
2              
3 1     1   20757 use warnings;
  1         3  
  1         35  
4 1     1   6 use strict;
  1         2  
  1         31  
5 1     1   884 use Sys::Hostname;
  1         1327  
  1         54  
6 1     1   968 use File::Copy;
  1         5095  
  1         68  
7 1     1   9 use File::Find;
  1         2  
  1         53  
8 1     1   6 use File::Basename;
  1         2  
  1         80  
9 1     1   7 use File::Path 'make_path';
  1         2  
  1         49  
10 1     1   5 use Cwd 'abs_path';
  1         1  
  1         50  
11 1     1   826 use String::ShellQuote;
  1         884  
  1         62  
12 1     1   9 use base 'Error::Helper';
  1         2  
  1         791  
13              
14             =head1 NAME
15              
16             Sys::Config::Manage - Manages system configuration information.
17              
18             =head1 VERSION
19              
20             Version 0.3.1
21              
22             =cut
23              
24             our $VERSION = '0.3.1';
25              
26             =head1 SYNOPSIS
27              
28             use Sys::Config::Manage;
29              
30             my $foo = Sys::Config::Manage->new();
31             ...
32              
33             =head1 METHODS
34              
35             =head2 new
36              
37             =head3 args hash
38              
39             =head4 addCommand
40              
41             This is the command to call on the file once it is copied over.
42              
43             If not defined, nothing will be attempted after it is copied over.
44              
45             =head4 autoCreateConfigDir
46              
47             If this is specified, the configuration directory will automatically
48             be created under the base directory if needed.
49              
50             This defaults to false, 0.
51              
52             =head4 baseDir
53              
54             The base directory the config base is stored in.
55              
56             =head4 hostnameFallback
57              
58             If the regexp selection method is being used, the hostname method will
59             be used.
60              
61             =head4 selectionMethod
62              
63             This is the selection method to use for selecting a system directory.
64              
65             The valid methods are listed below.
66              
67             hostname
68             regexp
69              
70             If not specified, the hostname method is used.
71              
72             my $foo=$Sys::Config::Manage->new(\%args);
73             if($foo->error){
74             warn('error:'.$foo->error.': '.$foo->errorString);
75             }
76              
77             =cut
78              
79             sub new{
80 0     0 1   my %args;
81 0 0         if(defined($_[1])){
82 0           %args= %{$_[1]};
  0            
83             };
84 0           my $method='new';
85              
86 0           my $self = {
87             module=>'Sys-Config-Manage',
88             perror=>undef,
89             error=>undef,
90             errorString=>"",
91             addCommand=>undef,
92             baseDir=>undef,
93             selectionMethod=>'hostname',
94             autoCreateConfigDir=>0,
95             hostnameFallback=>1,
96             };
97 0           bless $self;
98              
99             #make sure a base directory is set
100 0 0         if (!defined( $args{baseDir} )) {
101 0           $self->{perror}=1;
102 0           $self->{error}=1;
103 0           $self->{errorString}='No base directory specified';
104 0           $self->warn;
105 0           return $self;
106             }
107 0           $self->{baseDir}=$args{baseDir};
108              
109             #clean it up
110 0           $self->{baseDir} =~ s/\/\/*/\//g;
111              
112             #makes sure the base directory
113 0 0         if (! -d $self->{baseDir}) {
114 0           $self->{perror}=1;
115 0           $self->{error}=4;
116 0           $self->{errorString}='"'.$self->{baseDir}.'" does not exist or is not a directory';
117 0           $self->warn;
118 0           return $self;
119             }
120              
121             #copies the addcommand if needed
122 0 0         if (defined( $args{addCommand} )) {
123 0           $self->{addCommand}=$args{addCommand};
124             }
125              
126             #copies the hostnameFallback if needed
127 0 0         if (defined( $args{hostnameFallback} )) {
128 0           $self->{hostnameFallback}=$args{hostnameFallback};
129             }
130              
131             #sets the autoCreateConfigDir value if needed
132 0 0         if (defined( $args{autoCreateConfigDir} )) {
133 0           $self->{autoCreateConfigDir}=$args{autoCreateConfigDir};
134             }
135              
136             #make sure the selection
137 0 0         if (defined( $args{selectionMethod} )) {
138 0 0 0       if (
139             ( $args{selectionMethod} ne 'hostname' ) &&
140             ( $args{selectionMethod} ne 'regexp' )
141             ) {
142 0           $self->{perror}=1;
143 0           $self->{error}=2;
144 0           $self->{errorString}='"'.$args{selectionMethod}.'" is not a valid selection method';
145 0           $self->warn;
146 0           return $self;
147             }
148 0           $self->{selectionMethod}=$args{selectionMethod};
149             }
150              
151             #gets the hostname as it will be used later most likely...
152 0           $self->{hostname}=hostname;
153              
154 0           return $self;
155             }
156              
157             =head2 add
158              
159             This adds a new file.
160              
161             Two arguments are taken. The first is the file to added
162             and the second is the configuration directory to use. If
163             no configuration directory is specified, one will
164             automatically selected.
165              
166             #add it with a automatically selected config dir
167             $foo->add($file);
168             if($foo->error){
169             warn('error:'.$foo->error.': '.$foo->errorString);
170             }
171            
172             #add it with a automatically specified config dir
173             $foo->add($file, $configDir);
174             if($foo->error){
175             warn('error:'.$foo->error.': '.$foo->errorString);
176             }
177              
178             =cut
179              
180             sub add{
181 0     0 1   my $self=$_[0];
182 0           my $file=$_[1];
183 0           my $configDir=$_[2];
184 0           my $method='add';
185              
186             #blank any previous errors
187 0 0         if (!$self->errorblank) {
188 0           return undef;
189             }
190              
191             #make sure we have a file
192 0 0         if (!defined($file)) {
193 0           $self->{error}=7;
194 0           $self->{errorString}='No file specified';
195 0           $self->warn;
196 0           return undef;
197             }
198              
199             #make sure it is a file and it exists
200 0 0         if (! -f $file ) {
201 0           $self->{error}=8;
202 0           $self->{errorString}='"'.$file.'" does not exist or is not a file';
203 0           $self->warn;
204 0           return undef;
205             }
206              
207             #make sure we have a directory to use
208 0 0         if (!defined($configDir)) {
209 0           $configDir=$self->selectConfigDir;
210 0 0         if ($self->error) {
211 0           warn($self->{module}.' '.$method.': Unable to select a config dir');
212 0           return undef;
213             }
214             }
215              
216             #make sure the config directory is valid
217 0           my $valid=$self->validConfigDirName($configDir);
218 0 0         if ($self->error) {
219 0           warn($self->{module}.' '.$method.':'.$self->error.': Errored checking if the configuration directory name is valid');
220 0           return undef;
221             }
222 0 0         if (defined( $valid )) {
223 0           $self->{error}=6;
224 0           $self->{errorString}='The configuration directory name '.$valid;
225 0           $self->warn;
226 0           return undef;
227             }
228              
229             #makes sure the specified config directory is not a file
230 0 0         if ( -f $self->{baseDir}.'/'.$configDir ) {
231 0           $self->{error}=13;
232 0           $self->{errorString}='"'.$self->{baseDir}.'/'.$configDir.'" is a file and thusly can not be used as a configuration directory';
233 0           $self->warn;
234 0           return undef;
235             }
236              
237             #makes sure it exists
238 0 0         if ( ! -d $self->{baseDir}.'/'.$configDir ) {
239 0 0         if ( $self->getAutoCreateConfigDir ) {
240 0 0         if (! mkdir( $self->{baseDir}.'/'.$configDir ) ) {
241 0           $self->{error}=14;
242 0           $self->{errorString}='"'.$self->{baseDir}.'/'.$configDir.'" could not be created';
243 0           $self->warn;
244 0           return undef;
245             }
246             }else {
247 0           $self->{error}=15;
248 0           $self->{errorString}='"'.$self->{baseDir}.'/'.$configDir.'" could not be created as autoCreateConfigDir is set to false';
249 0           $self->warn;
250 0           return undef;
251             }
252             }
253              
254             #get the full path
255 0           $file=abs_path($file);
256              
257             #makes the new path
258 0           my $newfile=$self->{baseDir}.'/'.$configDir.'/'.$file;
259 0           $newfile=~s/\/\/*/\//g;
260              
261             #figures out what the new directory will be
262 0           my ($name,$path,$suffix) = fileparse( $file );
263 0           my $newpath=$self->{baseDir}.'/'.$configDir.'/'.$path;
264 0           $newfile=~s/\/\/*/\//g;
265              
266             #make sure the new path does not exist as a file
267             #while this may look stupid, it makes sure i
268 0 0         if ( -f $newpath ) {
269 0           $self->{error}=9;
270 0           $self->{errorString}='"'.$newpath.'" is a file, so unable to create the directory';
271 0           $self->warn;
272 0           return undef;
273             }
274              
275             #handles it if the directory path does not yet exist in the configuration directory
276 0 0         if (! -d $newpath ) {
277 0 0         if (! make_path($newpath) ) {
278 0           $self->{error}=10;
279 0           $self->{errorString}='The path "'.$newpath.'" could not be created';
280 0           $self->warn;
281 0           return undef;
282             }
283             }
284              
285             #copies the file
286 0 0         if (! copy($file, $newfile) ) {
287 0           $self->{error}=11;
288 0           $self->{errorString}='Unable to copy "'.$file.'" to "'.$newfile.'"';
289 0           $self->warn;
290 0           return undef;
291             }
292              
293             #adds it
294 0 0         if (defined( $self->{addCommand} )) {
295 0           my $command=$self->{addCommand};
296 0           $newfile=shell_quote($newfile);
297            
298 0           $command=~s/\%\%\%file\%\%\%/$newfile/g;
299 0           system($command);
300 0           my $exit = $?<<8;
301 0 0         if ($exit ne '0') {
302 0           $self->{error}=12;
303 0           $self->{errorString}='The add command failed. command="'.$command.'" exit="'.$exit.'"';
304 0           $self->warn;
305 0           return undef;
306             }
307             }
308              
309             #it has been added now
310 0           return 1;
311             }
312              
313             =head2 configDirExists
314              
315             This verifies that the specified config directory exists.
316              
317             my $returned=$foo->configDirExists($dir);
318             if($foo->error){
319             warn('error:'.$foo->error.': '.$foo->errorString);
320             }
321             if (!$returned){
322             warn('The config dir does not exist or is not a directory');
323             }
324              
325             =cut
326              
327             sub configDirExists{
328 0     0 1   my $self=$_[0];
329 0           my $configDir=$_[1];
330 0           my $method='getSelectionMethod';
331              
332             #blank any previous errors
333 0 0         if (!$self->errorblank) {
334 0           return undef;
335             }
336              
337             #it does not exist or is not a directory
338 0 0         if (! -d $self->{baseDir}.'/'.$configDir) {
339 0           return undef;
340             }
341              
342             #it exists
343 0           return 1;
344             }
345              
346             =head2 downSync
347              
348             This syncs the configs down from the configuration
349             directory to the system.
350              
351             Two arguments can be used.
352              
353             The first is the configuration directory. If not specified, it will
354             be automaticallly choosen.
355              
356             The second is the files to sync. If not specifiedm, all files will
357             be synced.
358              
359             #sync the specified files
360             $foo->downSync( $configDir, \@files);
361             if($foo->error){
362             warn('error:'.$foo->error.': '.$foo->errorString);
363             }
364              
365             #syncs all the files
366             $foo->downSync
367             if($foo->error){
368             warn('error:'.$foo->error.': '.$foo->errorString);
369             }
370              
371             =cut
372              
373             sub downSync{
374 0     0 1   my $self=$_[0];
375 0           my $configDir=$_[1];
376 0           my @files;
377 0 0         if (defined($_[2])) {
378 0           @files=@{$_[2]};
  0            
379             }
380 0           my $method='downSync';
381              
382             #blank any previous errors
383 0 0         if (!$self->errorblank) {
384 0           return undef;
385             }
386              
387             #make sure we have a directory to use
388 0 0         if (!defined($configDir)) {
389 0           $configDir=$self->selectConfigDir;
390 0 0         if ($self->error) {
391 0           warn($self->{module}.' '.$method.': Unable to select a config dir');
392 0           return undef;
393             }
394             }
395              
396             #make sure the config directory is valid
397 0           my $valid=$self->validConfigDirName($configDir);
398 0 0         if ($self->error) {
399 0           warn($self->{module}.' '.$method.':'.$self->error.': Errored checking if the configuration directory name is valid');
400 0           return undef;
401             }
402 0 0         if (defined( $valid )) {
403 0           $self->{error}=6;
404 0           $self->{errorString}='The configuration directory name '.$valid;
405 0           $self->warn;
406 0           return undef;
407             }
408              
409             #makes sure it exists
410 0 0         if ( ! -d $self->{baseDir}.'/'.$configDir ) {
411 0           $self->{error}=16;
412 0           $self->{errorString}='The configuration directory, "'.$self->{baseDir}.'/'.$configDir.'", does not exist';
413 0           $self->warn;
414 0           return undef;
415             }
416              
417             #get the files if if none is specified
418 0 0         if (!defined( $files[0] )) {
419 0           @files=$self->listConfigFiles($configDir);
420             }
421            
422             #get the files if if none is specified
423 0           my @allFiles=$self->listConfigFiles($configDir);
424              
425             #makes sure all the files exist
426 0           my $int=0;
427 0           while (defined( $files[$int] )) {
428 0           my $matched=0;
429 0           my $int2=0;
430 0           while (defined( $allFiles[$int2] )) {
431 0 0         if ( $files[$int] eq $allFiles[$int2] ) {
432 0           $matched=1;
433             }
434            
435 0           $int2++;
436             }
437            
438             #figures out what the new directory will be and checks
439 0           my ($name,$path,$suffix) = fileparse( $files[$int] );
440 0 0         if( -f $path ){
441 0           $self->{error}=19;
442 0           $self->{errorString}='"'.$path.'" should be a directory, but it is a file ';
443 0           $self->warn;
444 0           return undef;
445             }
446            
447             #make sure it is matched
448 0 0         if (!$matched) {
449 0           $self->{error}=18;
450 0           $self->{errorString}='"'.$files[$int].'" is not tracked';
451 0           $self->warn;
452 0           return undef;
453             }
454            
455 0           $int++;
456             }
457              
458             #copies each file from the repo to the FS
459 0           $int=0;
460 0           while( defined( $files[$int] ) ){
461 0           my $repofile=$self->{baseDir}.'/'.$configDir.'/'.$files[$int];
462 0           $repofile=~s/\/\/*/\//g;
463            
464             #figures out what the new directory will be
465 0           my ($name,$path,$suffix) = fileparse( $files[$int] );
466            
467             #make the path if it does not exist
468 0 0         if(! -e $path){
469 0 0         if(!make_path( $path )){
470 0           $self->{error}=10;
471 0           $self->{errorString}='"'.$path.'" could not be created as a directory';
472 0           $self->warn;
473 0           return undef;
474             }
475             }
476            
477             #
478 0 0         if(! copy($repofile, $files[$int]) ){
479 0           $self->{error}=19;
480 0           $self->{errorString}='"'.$files[$int].'" could not be synced';
481 0           $self->warn;
482 0           return undef;
483             }
484            
485 0           $int++;
486             }
487              
488 0           return 1;
489             }
490              
491             =head2 getAddCommand
492              
493             This returns the current add command.
494              
495             If none is set, undef will be returned.
496              
497             my $addCommand=$foo->getAddCommand;
498             if($foo->error){
499             warn('error:'.$foo->error.': '.$foo->errorString);
500             }
501              
502             =cut
503              
504             sub getAddCommand{
505 0     0 1   my $self=$_[0];
506 0           my $method='getAddCommand';
507              
508             #blank any previous errors
509 0 0         if (! $self->errorblank) {
510 0           return undef;
511             }
512              
513 0           return $self->{addCommand};
514             }
515              
516             =head2 getAutoCreateConfigDir
517              
518             This returns the autoCreateConfigDir value.
519              
520             my $autoCreateConfigDir=$foo->getBaseDir;
521             if($foo->error){
522             warn('error:'.$foo->error.': '.$foo->errorString);
523             }
524              
525             =cut
526              
527             sub getAutoCreateConfigDir{
528 0     0 1   my $self=$_[0];
529 0           my $method='autoCreateConfigDir';
530              
531             #blank any previous errors
532 0 0         if (! $self->errorblank) {
533 0           return undef;
534             }
535              
536 0           return $self->{autoCreateConfigDir};
537             }
538              
539             =head2 getBaseDir
540              
541             This returns what the base directory is set to.
542              
543             my $baseDir=$foo->getBaseDir;
544             if($foo->error){
545             warn('error:'.$foo->error.': '.$foo->errorString);
546             }
547              
548             =cut
549              
550             sub getBaseDir{
551 0     0 1   my $self=$_[0];
552 0           my $method='getBaseDir';
553              
554             #blank any previous errors
555 0 0         if (!$self->errorblank) {
556 0           return undef;
557             }
558              
559 0           return $self->{baseDir};
560             }
561              
562              
563             =head2 getHostnameFallback
564              
565             This returns the current value for hostnameFallback.
566              
567             my $hostnameFallback=$foo->getHostnameFallback;
568             if($foo->error){
569             warn('error:'.$foo->error.': '.$foo->errorString);
570             }
571              
572             =cut
573              
574             sub getHostnameFallback{
575 0     0 1   my $self=$_[0];
576 0           my $method='getHostnameFallback';
577              
578             #blank any previous errors
579 0 0         if (!$self->errorblank) {
580 0           return undef;
581             }
582              
583 0           return $self->{baseDir};
584             }
585              
586             =head2 getSelectionMethod
587              
588             This returns the current selection method.
589              
590             my $selectionMethod=$foo->getSelectionMethod;
591             if($foo->error){
592             warn('error:'.$foo->error.': '.$foo->errorString);
593             }
594              
595             =cut
596              
597             sub getSelectionMethod{
598 0     0 1   my $self=$_[0];
599 0           my $method='getSelectionMethod';
600              
601             #blank any previous errors
602 0 0         if (!$self->errorblank) {
603 0           return undef;
604             }
605              
606 0           return $self->{selectionMethod};
607             }
608              
609             =head2 listConfigDirs
610              
611             This lists the available configuration directories.
612              
613             my @dirs=$foo->listConfigDirs;
614             if($foo->error){
615             warn('error:'.$foo->error.': '.$foo->errorString);
616             }
617              
618             =cut
619              
620             sub listConfigDirs{
621 0     0 1   my $self=$_[0];
622 0           my $method='listConfigDirs';
623              
624             #blank any previous errors
625 0 0         if (!$self->errorblank) {
626 0           return undef;
627             }
628              
629             #opens the directory for reading
630 0           my $dh=undef;
631 0 0         if (! opendir( $dh, $self->{baseDir} ) ) {
632 0           $self->{error}=5;
633 0           $self->{errorString}='Unable to open "'.$self->{baseDir}.'"';
634 0           $self->warn;
635 0           return undef;
636             }
637              
638             #reads each entry and check if it should be added
639 0           my @dirs;
640 0           my $entry=readdir($dh);
641 0           while ( defined($entry) ) {
642 0 0 0       if (
643             ( $entry ne '.SysConfigManage' ) &&
644             ( -d $entry )
645             ) {
646 0           push( @dirs, $entry );
647             }
648              
649 0           $entry=readdir($dh);
650             }
651              
652             #close the directory
653 0           closedir($dh);
654              
655 0           return @dirs;
656             }
657              
658             =head2 listConfigFiles
659              
660             This lists the various config files that are currently being tracked.
661              
662             my @files=$foo->listConfigFiles;
663             if($foo->error){
664             warn('error:'.$foo->error.': '.$foo->errorString);
665             }
666              
667             =cut
668              
669             sub listConfigFiles{
670 0     0 1   my $self=$_[0];
671 0           my $configDir=$_[1];
672 0           my $method='listConfigFiles';
673              
674             #blank any previous errors
675 0 0         if (!$self->errorblank) {
676 0           return undef;
677             }
678              
679             #make sure we have a directory to use
680 0 0         if (!defined($configDir)) {
681 0           $configDir=$self->selectConfigDir;
682 0 0         if ($self->error) {
683 0           warn($self->{module}.' '.$method.':'.$self->error.': Unable to select a directory');
684 0           return undef;
685             }
686             }
687              
688             #make sure the config directory is valid
689 0           my $valid=$self->validConfigDirName($configDir);
690 0 0         if ($self->error) {
691 0           warn($self->{module}.' '.$method.':'.$self->error.': Errored checking if the configuration directory name is valid');
692 0           return undef;
693             }
694 0 0         if (defined( $valid )) {
695 0           $self->{error}=6;
696 0           $self->{errorString}='The configuration directory name '.$valid;
697 0           $self->warn;
698 0           return undef;
699             }
700              
701             #makes sure it exists
702 0 0         if ( ! -d $self->{baseDir}.'/'.$configDir ) {
703 0           $self->{error}=16;
704 0           $self->{errorString}='The configuration directory, "'.$self->{baseDir}.'/'.$configDir.'", does not exist';
705 0           $self->warn;
706 0           return undef;
707             }
708              
709             #holds what will be returned
710 0           my @found;
711              
712             #find the file
713             find( {
714             wanted => sub{
715             #don't match .svn stuff
716 0 0   0     if ( $_ eq ".svn" ) {
717 0           return;
718             }
719 0 0         if($File::Find::dir =~ /\.svn$/){
720 0           return;
721             }
722 0 0         if($File::Find::dir =~ /\.svn\//){
723 0           return;
724             }
725              
726             #don't match .SysConfigManage stuff
727 0 0         if ( $_ eq ".SysConfigManage" ) {
728 0           return;
729             }
730 0 0         if($File::Find::dir =~ /\.SysConfigManage$/){
731 0           return;
732             }
733 0 0         if($File::Find::dir =~ /\.SysConfigManage\//){
734 0           return;
735             }
736              
737             #don't match .git stuff
738 0 0         if ( $_ eq ".git" ) {
739 0           return;
740             }
741 0 0         if($File::Find::dir =~ /\.git$/){
742 0           return;
743             }
744 0 0         if($File::Find::dir =~ /\.git\//){
745 0           return;
746             }
747              
748             #only list files
749 0 0         if ( ! -f $_ ) {
750 0           return;
751             }
752              
753 0           my $foundfile=$File::Find::dir."/".$_;
754             #$foundfile=~s/\/\//\//g;
755 0           my $regexp='^'.$self->{baseDir}.'/'.$configDir;
756 0           $foundfile=~s/$regexp//;
757              
758 0           push(@found, $foundfile);
759              
760             }
761 0           }, $self->{baseDir}.'/'.$configDir
762             );
763              
764 0           return @found;
765             }
766              
767             =head2 notUnderBase
768              
769             This makes sure that the a file is not under the base directory.
770              
771             If it returns true, then the file is not under the base directory.
772              
773             If it returns false, then it is under the base directory.
774              
775             my $returned=$foo->notUnderBase($file);
776             if($foo->error){
777             warn('error:'.$foo->error.': '.$foo->errorString);
778             }
779             if ( ! $returned ){
780             print "The file is under the base directory.\n".
781             }
782              
783             =cut
784              
785             sub notUnderBase{
786 0     0 1   my $self=$_[0];
787 0           my $file=$_[1];
788 0           my $method='notUnderBase';
789              
790             #blank any previous errors
791 0 0         if (!$self->errorblank) {
792 0           return undef;
793             }
794              
795             #make sure we have a file specified
796 0 0         if( ! defined( $file ) ){
797 0           $self->{error}=7;
798 0           $self->{errorString}='No file specified';
799 0           $self->warn;
800             }
801              
802             #clean up the path
803 0           $file=~s/\/\/*/\//g;
804              
805 0           my $regexp="^".quotemeta($self->{baseDir}."/");
806 0           $regexp=~s/\/\/*/\//g;
807              
808             #if it matches, then it
809 0 0         if( $file =~ /$regexp/ ){
810 0           return 0;
811             }
812              
813 0           return 1;
814             }
815              
816             =head2 regexpSelectConfigDir
817              
818             This reads $baseDir.'/.mapping' and returns the selected configuration
819             directory.
820              
821             A optional hostname may be specified to check for.
822              
823             A return of undef with out a error means it was not matched
824              
825             my $configDir=$foo->regexpSelect;
826             if($foo->error){
827             warn('error:'.$foo->error.': '.$foo->errorString);
828             }else{
829             if(!defined(configDir)){
830             warn('No match found');
831             }
832             }
833              
834             =cut
835              
836             sub regexpSelectConfigDir{
837 0     0 1   my $self=$_[0];
838 0           my $hostname=$_[1];
839 0           my $method='regexpSelectSelectConfigDir';
840              
841             #blank any previous errors
842 0 0         if (!$self->errorblank) {
843 0           return undef;
844             }
845              
846 0 0         if (!defined( $hostname )) {
847 0           $hostname=$self->{hostname};
848             }
849              
850             #make sure it exists or is readable
851 0 0         if ( -f $self->{baseDir}.'/.mapping' ) {
852 0           $self->{error}=5;
853 0           $self->{error}='"'.$self->{baseDir}.'/.mapping" does not exist or is not a file';
854 0           $self->warn;
855 0           return undef;
856             }
857              
858             #tries to open it
859 0           my $dh;
860 0 0         if ( ! open( $dh, '<', $self->{baseDir}.'/.mapping' ) ) {
861 0           $self->{error}=6;
862 0           $self->{error}='"'.$self->{baseDir}.'/.mapping" could not be opened';
863 0           $self->warn;
864 0           return undef;
865             }
866              
867             #read it and close it
868 0           my @lines=<$dh>;
869 0           close $dh;
870              
871             #process each line
872 0           my $int=0;
873 0           while ( defined( $lines[$int] ) ) {
874 0           my ($dir, $regexp)=split(/ /, $lines[$int], 2);
875              
876 0 0         if ( $hostname =~ /$regexp/ ) {
877              
878 0           return $dir;
879             }
880              
881 0           $int++;
882             }
883              
884 0           return undef;
885             }
886              
887             =head2 selectConfigDir
888              
889             This selects the configuration directory to use.
890              
891             my $configDir=$foo->selectConfigDir;
892             if($foo->error){
893             warn('error:'.$foo->error.': '.$foo->errorString);
894             }
895              
896             =cut
897              
898             sub selectConfigDir{
899 0     0 1   my $self=$_[0];
900 0           my $method='setSelectionMethod';
901              
902             #blank any previous errors
903 0 0         if (!$self->errorblank) {
904 0           return undef;
905             }
906              
907 0           my $selectionMethod=$self->getSelectionMethod;
908              
909 0 0         if( $selectionMethod eq 'hostname' ){
910 0           return lc(hostname);
911             }
912              
913 0 0         if ( $selectionMethod eq 'regexp' ){
914 0           my $configDir=$self->regexpSelect;
915 0 0         if ( $self->error ) {
916 0           warn($self->{module}.' '.$method.': regexpSelect failed');
917 0           return undef;
918             }
919 0 0         if (!defined($configDir)) {
920 0 0         if ($self->getHostnameFallback) {
921 0           return hostname;
922             }
923 0           $self->{error}=17;
924 0           $self->{errorString}='Hostname is disabled and regexp selection did not find any thing';
925 0           $self->warn;
926 0           return undef;
927             }
928 0           return $configDir;
929             }
930              
931 0           return undef;
932             }
933              
934             =head2 setAddCommand
935              
936             This changes the add command.
937              
938             If nothing is specified, it will be set to undef, meaning
939             nothing will be done to add it.
940              
941             #sets nothing to be added
942             $foo->setAddMethod();
943             if($foo->error){
944             warn('error:'.$foo->error.': '.$foo->errorString);
945             }
946              
947             #sets it to 'svn add --parents %%%file%%%'
948             $foo->setAddMethod('svn add --parents %%%file%%%');
949             if($foo->error){
950             warn('error:'.$foo->error.': '.$foo->errorString);
951             }
952              
953             =cut
954              
955             sub setAddCommand{
956 0     0 1   my $self=$_[0];
957 0           my $command=$_[1];
958 0           my $method='setAddCommand';
959              
960             #blank any previous errors
961 0 0         if (!$self->errorblank) {
962 0           return undef;
963             }
964              
965 0           $self->{addCommand}=$command;
966              
967 0           return 1;
968             }
969              
970             =head2 setAutoCreateConfigDir
971              
972             This changes the add command.
973              
974             If nothing is specified, it will be set to undef, meaning
975             nothing will be done to add it.
976              
977             #sets nothing to be added
978             $foo->setAddMethod();
979             if($foo->error){
980             warn('error:'.$foo->error.': '.$foo->errorString);
981             }
982              
983             #sets it to 'svn add --parents %%%file%%%'
984             $foo->setAddMethod('svn add --parents %%%file%%%');
985             if($foo->error){
986             warn('error:'.$foo->error.': '.$foo->errorString);
987             }
988              
989             =cut
990              
991             sub setAutoCreateConfigDir{
992 0     0 1   my $self=$_[0];
993 0           my $autocreate=$_[1];
994 0           my $method='setAutoCreateConfigDir';
995            
996             #blank any pre1;3Avious errors
997 0 0         if (!$self->errorblank) {
998 0           return undef;
999             }
1000            
1001 0           $self->{autoCreateConfigDir}=$autocreate;
1002            
1003 0           return 1;
1004             }
1005              
1006             =head2 setSelectionMethod
1007              
1008             This sets the selection method to use.
1009              
1010             The valid methods are listed below.
1011              
1012             hostname
1013             regexp
1014              
1015             $foo->setSelectionMethod($method);
1016             if($foo->error){
1017             warn('error:'.$foo->error.': '.$foo->errorString);
1018             }
1019              
1020             =cut
1021              
1022             sub setSelectionMethod{
1023 0     0 1   my $self=$_[0];
1024 0           my $selectionMethod=$_[1];
1025 0           my $method='setSelectionMethod';
1026              
1027             #blank any previous errors
1028 0 0         if (!$self->errorblank) {
1029 0           return undef;
1030             }
1031              
1032             #make sure a method is specified
1033 0 0         if (!defined($selectionMethod)) {
1034 0           $self->{error}=3;
1035 0           $self->{errorString}='No selection method specified';
1036 0           $self->warn;
1037 0           return undef;
1038             }
1039              
1040             #make sure it is valid
1041 0 0 0       if (
1042             ( $selectionMethod ne 'hostname' ) &&
1043             ( $selectionMethod ne 'regexp' )
1044             ) {
1045 0           $self->{error}=2;
1046 0           $self->{errorString}='"'.$selectionMethod.'" is not a valid selection method';
1047 0           $self->warn;
1048 0           return undef;
1049             }
1050              
1051             #saves the selection method
1052 0           $self->{selectionMethod}=$selectionMethod;
1053              
1054 0           return 1;
1055             }
1056              
1057             =head2 upSync
1058              
1059             This syncs the configs up from the system to the configuration
1060             directory
1061              
1062             Two arguments can be used.
1063              
1064             The first is the configuration directory. If not specified, it will
1065             be automaticallly choosen.
1066              
1067             The second is the files to sync. If not specifiedm, all files will
1068             be synced.
1069              
1070             #sync the specified files
1071             $foo->downSync( $configDir, \@files);
1072             if($foo->error){
1073             warn('error:'.$foo->error.': '.$foo->errorString);
1074             }
1075              
1076             #syncs all the files
1077             $foo->downSync($configDir);
1078             if($foo->error){
1079             warn('error:'.$foo->error.': '.$foo->errorString);
1080             }
1081              
1082             =cut
1083              
1084             sub upSync{
1085 0     0 1   my $self=$_[0];
1086 0           my $configDir=$_[1];
1087 0           my @files;
1088 0 0         if (defined($_[2])) {
1089 0           @files=@{$_[2]};
  0            
1090             }
1091 0           my $method='downSync';
1092              
1093             #blank any previous errors
1094 0 0         if (!$self->errorblank) {
1095 0           return undef;
1096             }
1097              
1098             #make sure we have a directory to use
1099 0 0         if (!defined($configDir)) {
1100 0           $configDir=$self->selectConfigDir;
1101 0 0         if ($self->error) {
1102 0           warn($self->{module}.' '.$method.': Unable to select a config dir');
1103 0           return undef;
1104             }
1105             }
1106              
1107             #make sure the config directory is valid
1108 0           my $valid=$self->validConfigDirName($configDir);
1109 0 0         if ($self->error) {
1110 0           warn($self->{module}.' '.$method.':'.$self->error.': Errored checking if the configuration directory name is valid');
1111 0           return undef;
1112             }
1113 0 0         if (defined( $valid )) {
1114 0           $self->{error}=6;
1115 0           $self->{errorString}='The configuration directory name '.$valid;
1116 0           $self->warn;
1117 0           return undef;
1118             }
1119              
1120             #makes sure it exists
1121 0 0         if ( ! -d $self->{baseDir}.'/'.$configDir ) {
1122 0           $self->{error}=16;
1123 0           $self->{errorString}='The configuration directory, "'.$self->{baseDir}.'/'.$configDir.'", does not exist';
1124 0           $self->warn;
1125 0           return undef;
1126             }
1127              
1128             #get the files if if none is specified
1129 0 0         if (!defined( $files[0] )) {
1130 0           @files=$self->listConfigFiles($configDir);
1131             }
1132              
1133             #get the files if if none is specified
1134 0           my @allFiles=$self->listConfigFiles($configDir);
1135              
1136             #makes sure all the files exist
1137 0           my $int=0;
1138 0           while (defined( $files[$int] )) {
1139 0           my $matched=0;
1140 0           my $int2=0;
1141 0           while (defined( $allFiles[$int2] )) {
1142 0 0         if ( $files[$int] eq $allFiles[$int2] ) {
1143 0           $matched=1;
1144             }
1145            
1146 0           $int2++;
1147             }
1148            
1149             #figures out what the new directory will be and checks
1150 0           my ($name,$path,$suffix) = fileparse( $files[$int] );
1151 0 0         if( -f $path ){
1152 0           $self->{error}=19;
1153 0           $self->{errorString}='"'.$path.'" should be a directory, but it is a file ';
1154 0           $self->warn;
1155 0           return undef;
1156             }
1157            
1158             #make sure it is matched
1159 0 0         if (!$matched) {
1160 0           $self->{error}=18;
1161 0           $self->{errorString}='"'.$files[$int].'" is not tracked';
1162 0           $self->warn;
1163 0           return undef;
1164             }
1165            
1166 0           $int++;
1167             }
1168              
1169             #copies each file from the fs to the repo
1170 0           $int=0;
1171 0           while( defined( $files[$int] ) ){
1172 0           my $repofile=$self->{baseDir}.'/'.$configDir.'/'.$files[$int];
1173 0           $repofile=~s/\/\/*/\//g;
1174              
1175             #figures out what the new directory will be
1176 0           my ($name,$path,$suffix) = fileparse( $files[$int] );
1177            
1178             #copy it back up from the FS and into the repo
1179 0 0         if(! copy($files[$int], $repofile) ){
1180 0           $self->{error}=19;
1181 0           $self->{errorString}='"'.$files[$int].'" could not be synced';
1182 0           $self->warn;
1183 0           return undef;
1184             }
1185            
1186 0           $int++;
1187             }
1188              
1189 0           return 1;
1190             }
1191              
1192             =head2 validConfigDirName
1193              
1194             This checks to make sure configuration directory name
1195             is valid.
1196              
1197             my $returned=$foo->validConfigDirName($name);
1198             if($foo->error){
1199             warn('error:'.$foo->error.': '.$foo->errorString);
1200             }
1201             if(defined( $returned )){
1202             print 'Invalid name... '.$returned."\n";
1203             }
1204              
1205             =cut
1206              
1207             sub validConfigDirName{
1208 0     0 1   my $self=$_[0];
1209 0           my $name=$_[1];
1210 0           my $method='validConfigDirName';
1211              
1212             #blank any previous errors
1213 0           $self->errorblank; # don't really care if a permanent error is set here
1214              
1215              
1216             #always needs defined...
1217 0 0         if (!defined( $name )) {
1218 0           return 'not defined'
1219             }
1220              
1221             #make sure it is not not contain a slash
1222 0 0         if ( $name =~ /^\// ) {
1223 0           return 'matched /^\//';
1224             }
1225              
1226              
1227             #makes sure the mapping file is not specified
1228 0 0         if ($name eq '.mapping' ) {
1229 0           return 'matched ".mapping"';
1230              
1231             }
1232              
1233             #can't be any where in the path
1234 0 0         if ( $name =~ /\.SysConfigManage/ ) {
1235 0           return 'matched /\.SysConfigManage/';
1236             }
1237              
1238             #make sure it does not start with a period
1239 0 0         if ( $name =~ /^\./ ) {
1240 0           return 'mathced /^\./';
1241             }
1242              
1243 0           return undef;
1244             }
1245              
1246             =head1 ERROR CODES
1247              
1248             =head2 1
1249              
1250             No base directory specified.
1251              
1252             =head2 2
1253              
1254             No valid selection method specified.
1255              
1256             =head2 3
1257              
1258             Selection method not specified.
1259              
1260             =head2 4
1261              
1262             The specified directory does not exist or is not a directory.
1263              
1264             =head2 5
1265              
1266             The $baseDir.'/.mapping' file does not exist or is not a file.
1267              
1268             =head2 6
1269              
1270             Invalid config name.
1271              
1272             =head2 7
1273              
1274             No file specified.
1275              
1276             =head2 8
1277              
1278             The specified file does not exist or is not a file.
1279              
1280             =head2 9
1281              
1282             Makes sure the new path under the configuration directory is not a file.
1283              
1284             =head2 10
1285              
1286             The new path could not be created.
1287              
1288             =head2 11
1289              
1290             Copying the file failed.
1291              
1292             =head2 12
1293              
1294             The add command exited with a non-zero.
1295              
1296             =head2 13
1297              
1298             The selected configuration directory is a file.
1299              
1300             =head2 14
1301              
1302             The selected configuration directory could not be created.
1303              
1304             =head2 15
1305              
1306             The selected configuration directory does not exist and autoCreateConfigDir set to false.
1307              
1308             =head2 16
1309              
1310             The configuration directory does not exist.
1311              
1312             =head2 17
1313              
1314             Regexp selection did not match any thing and hostname fallback is not enabled.
1315              
1316             =head2 18
1317              
1318             One of the specified config files is not tracked.
1319              
1320             =head2 19
1321              
1322             Failed to copy a file for syncing.
1323              
1324             =head1 Config Storage
1325              
1326             Each config is stored under $baseDir.'/'.$configDir and then each config
1327             is saved under the the configuration directory with the path on the file
1328             system mapped onto the configuration directory.
1329              
1330             Lets say the base directory is '/root/configs/' and the configuration
1331             directory is 'foo.bar', with a config file of '/etc/rc.conf', then the
1332             resulting path of the added file is '/root/configs/foo.bar/etc/rc.conf'.
1333              
1334             The configuration directory can then be selected by three different methods.
1335             The first method is manually, the third is the regexp method, and the third
1336             is the hostname method. The name of the configuration directory may not
1337             contain any forward slashes or start with a period.
1338              
1339             The regexp method reads $baseDir.'/.mapping'. Each line contains two fields.
1340             The first field is the configuration directory under the base directory. The
1341             next field is a regular expression. If the regular expression matches the
1342             hostname, the configuration directory in the first field is used. The first
1343             match is used. Any line starting with a "#" is a comment.
1344              
1345             The hostname method uses the hostname for the configuration directory. It also
1346             converts the hostname to lowercase.
1347              
1348             Any where in the path, the regexp /\.SysConfigManage/ maynot be found. This
1349             is a reserved directory that will be used some time in the future.
1350              
1351             After a file is added, a add command can be used. The add command prior to being
1352             ran will have any instance of '%%%file%%%' replaced with a escaped file name.
1353              
1354             Lets say the base directory is '/root/configs/' and the configuration
1355             directory is 'foo.bar', with a config file of '/etc/rc.conf', and a add command
1356             of 'svn add --parents %%%file%%%', then the executed command will be
1357             'svn add --parents /root/configs/foo.bar/etc/rc.conf'.
1358              
1359             To help integrate with subversion and git, directories matching /^.git$/ and
1360             /^.svn$/ are ignored.
1361              
1362             =head2 Ownership Storage
1363              
1364             The path under which the configuration file is stored, under the configuration directory,
1365             has a '.SysConfigManage/UID/' and '.SysConfigManage/GID/' directory. Each directory
1366             contains a corresponding file that mirrors the name of the file in question.
1367              
1368             Each file contains either the numeric GID or UID of the file in question.
1369              
1370             =head2 Permission Storage
1371              
1372             The path under which the configuration file is stored, under the configuration directory,
1373             has a '.SysConfigManage/Perms/'. The directory contains a corresponding file that mirrors
1374             the name of the file in question.
1375              
1376             Each file contains either the numeric mode of the file in question.
1377              
1378             The regexp below is used for verification.
1379              
1380             /^[01246][01234567][01234567][01234567]$/
1381              
1382             =head1 AUTHOR
1383              
1384             Zane C. Bowers-Hadley, C<< >>
1385              
1386             =head1 BUGS
1387              
1388             Please report any bugs or feature requests to C, or through
1389             the web interface at L. I will be notified, and then you'll
1390             automatically be notified of progress on your bug as I make changes.
1391              
1392              
1393              
1394              
1395             =head1 SUPPORT
1396              
1397             You can find documentation for this module with the perldoc command.
1398              
1399             perldoc Sys::Config::Manage
1400              
1401              
1402             You can also look for information at:
1403              
1404             =over 4
1405              
1406             =item * RT: CPAN's request tracker
1407              
1408             L
1409              
1410             =item * AnnoCPAN: Annotated CPAN documentation
1411              
1412             L
1413              
1414             =item * CPAN Ratings
1415              
1416             L
1417              
1418             =item * Search CPAN
1419              
1420             L
1421              
1422             =back
1423              
1424              
1425             =head1 ACKNOWLEDGEMENTS
1426              
1427              
1428             =head1 LICENSE AND COPYRIGHT
1429              
1430             Copyright 2011 Zane C. Bowers-Hadley.
1431              
1432             This program is free software; you can redistribute it and/or modify it
1433             under the terms of either: the GNU General Public License as published
1434             by the Free Software Foundation; or the Artistic License.
1435              
1436             See http://dev.perl.org/licenses/ for more information.
1437              
1438              
1439             =cut
1440              
1441             1; # End of Sys::Config::Manage