File Coverage

blib/lib/Shell/Config/Generate.pm
Criterion Covered Total %
statement 116 191 60.7
branch 43 86 50.0
condition 14 30 46.6
subroutine 22 30 73.3
pod 16 16 100.0
total 211 353 59.7


line stmt bran cond sub pod time code
1             package Shell::Config::Generate;
2              
3 11     11   2201381 use strict;
  11         71  
  11         281  
4 11     11   101 use warnings;
  11         21  
  11         244  
5 11     11   290 use 5.008001;
  11         37  
6 11     11   2894 use Shell::Guess;
  11         14416  
  11         376  
7 11     11   64 use Carp qw( croak );
  11         20  
  11         486  
8 11     11   59 use Exporter ();
  11         23  
  11         28122  
9              
10             # ABSTRACT: Portably generate config for any shell
11             our $VERSION = '0.34'; # VERSION
12              
13              
14             sub new
15             {
16 24     24 1 444001 my($class) = @_;
17 24         130 bless { commands => [], echo_off => 0 }, $class;
18             }
19              
20              
21             sub set
22             {
23 7     7 1 686 my($self, $name, $value) = @_;
24              
25 7         11 push @{ $self->{commands} }, ['set', $name, $value];
  7         20  
26              
27 7         26 $self;
28             }
29              
30              
31             sub set_path
32             {
33 4     4 1 1797 my($self, $name, @list) = @_;
34              
35 4         9 push @{ $self->{commands} }, [ 'set_path', $name, @list ];
  4         19  
36              
37 4         9 $self;
38             }
39              
40              
41             sub append_path
42             {
43 8     8 1 4078 my($self, $name, @list) = @_;
44              
45 8 50       35 push @{ $self->{commands} }, [ 'append_path', $name, @list ]
  8         43  
46             if @list > 0;
47              
48 8         25 $self;
49             }
50              
51              
52             sub prepend_path
53             {
54 8     8 1 3366 my($self, $name, @list) = @_;
55              
56 8 50       28 push @{ $self->{commands} }, [ 'prepend_path', $name, @list ]
  8         28  
57             if @list > 0;
58              
59 8         20 $self;
60             }
61              
62              
63             sub comment
64             {
65 4     4 1 895 my($self, @comments) = @_;
66              
67 4         9 push @{ $self->{commands} }, ['comment', $_] for @comments;
  5         19  
68              
69 4         10 $self;
70             }
71              
72              
73             sub shebang
74             {
75 4     4 1 9 my($self, $location) = @_;
76 4         8 $self->{shebang} = $location;
77 4         19 $self;
78             }
79              
80              
81             sub echo_off
82             {
83 3     3 1 8 my($self) = @_;
84 3         10 $self->{echo_off} = 1;
85 3         16 $self;
86             }
87              
88              
89             sub echo_on
90             {
91 1     1 1 3 my($self) = @_;
92 1         2 $self->{echo_off} = 0;
93 1         4 $self;
94             }
95              
96             sub _value_escape_csh
97             {
98 0     0   0 my $value = shift() . '';
99 0         0 $value =~ s/([\n!])/\\$1/g;
100 0         0 $value =~ s/(')/'"$1"'/g;
101 0         0 $value;
102             }
103              
104             sub _value_escape_fish
105             {
106 0     0   0 my $value = shift() . '';
107 0         0 $value =~ s/([\n])/\\$1/g;
108 0         0 $value =~ s/(')/'"$1"'/g;
109 0         0 $value;
110             }
111              
112             sub _value_escape_sh
113             {
114 86     86   176 my $value = shift() . '';
115 86         285 $value =~ s/(')/'"$1"'/g;
116 86         243 $value;
117             }
118              
119             sub _value_escape_win32
120             {
121 0     0   0 my $value = shift() . '';
122 0         0 $value =~ s/%/%%/g;
123 0         0 $value =~ s/([&^|<>()])/^$1/g;
124 0         0 $value =~ s/\n/^\n\n/g;
125 0         0 $value;
126             }
127              
128             # `0 Null
129             # `a Alert bell/beep
130             # `b Backspace
131             # `f Form feed (use with printer output)
132             # `n New line
133             # `r Carriage return
134             # `r`n Carriage return + New line
135             # `t Horizontal tab
136             # `v Vertical tab (use with printer output)
137              
138             my %ps = ( # microsoft would have to be different
139             "\0" => '`0',
140             "\a" => '`a',
141             "\b" => '`b',
142             "\f" => '`f',
143             "\r" => '`r',
144             "\n" => '`n',
145             "\t" => '`t',
146             #"\v" => '`v',
147             );
148              
149             sub _value_escape_powershell
150             {
151 3     3   11 my $value = shift() . '';
152 3         19 $value =~ s/(["'`\$#()])/`$1/g;
153 3         15 $value =~ s/([\0\a\b\f\r\n\t])/$ps{$1}/eg;
  0         0  
154 3         25 $value;
155             }
156              
157              
158             sub set_alias
159             {
160 1     1 1 669 my($self, $alias, $command) = @_;
161              
162 1         3 push @{ $self->{commands} }, ['alias', $alias, $command];
  1         10  
163             }
164              
165              
166             sub set_path_sep
167             {
168 9     9 1 4661 my($self, $sep) = @_;
169 9         29 push @{ $self->{commands} }, ['set_path_sep', $sep];
  9         63  
170             }
171              
172              
173             sub generate
174             {
175 54     54 1 553888 my($self, $shell) = @_;
176              
177 54 50       217 if(defined $shell)
178             {
179 54 100       264 if(ref($shell) eq '')
180             {
181 2         5 my $method = join '_', $shell, 'shell';
182 2 50       13 if(Shell::Guess->can($method))
183             {
184 2         9 $shell = Shell::Guess->$method;
185             }
186             else
187             {
188 0         0 croak("unknown shell type: $shell");
189             }
190             }
191             }
192             else
193             {
194 0         0 $shell = Shell::Guess->running_shell;
195             }
196              
197 54         268 $self->_generate($shell);
198             }
199              
200             sub _generate
201             {
202 50     50   124 my($self, $shell) = @_;
203              
204 50         191 my $buffer = '';
205 50 100       1246 my $sep = $shell->is_win32 ? ';' : ':';
206              
207 50 100 100     705 if(exists $self->{shebang} && $shell->is_unix)
208             {
209 3 100       25 if(defined $self->{shebang})
210 1         3 { $buffer .= "#!" . $self->{shebang} . "\n" }
211             else
212 2         6 { $buffer .= "#!" . $shell->default_location . "\n" }
213             }
214              
215 50 100 66     204 if($self->{echo_off} && ($shell->is_cmd || $shell->is_command))
      66        
216             {
217 1         10 $buffer .= '@echo off' . "\n";
218             }
219              
220 50         131 foreach my $args (map { [@$_] } @{ $self->{commands} })
  97         598  
  50         172  
221             {
222 97         195 my $command = shift @$args;
223              
224 97 100       264 if($command eq 'set_path_sep')
225             {
226 18         48 $sep = shift @$args;
227 18         50 next;
228             }
229              
230             # rewrite set_path as set
231 79 100       174 if($command eq 'set_path')
232             {
233 8         37 $command = 'set';
234 8         16 my $name = shift @$args;
235 8         57 $args = [$name, join $sep, @$args];
236             }
237              
238 79 100 100     383 if($command eq 'set')
    100          
    100          
    50          
239             {
240 22         46 my($name, $value) = @$args;
241 22 50 0     349 if($shell->is_c)
    50          
    50          
    0          
    0          
242             {
243 0         0 $value = _value_escape_csh($value);
244 0         0 $buffer .= "setenv $name '$value';\n";
245             }
246             elsif($shell->is_fish)
247             {
248 0         0 $value = _value_escape_fish($value);
249 0         0 $buffer .= "set -x $name '$value';\n";
250             }
251             elsif($shell->is_bourne)
252             {
253 22         1040 $value = _value_escape_sh($value);
254 22         74 $buffer .= "$name='$value';\n";
255 22         69 $buffer .= "export $name;\n";
256             }
257             elsif($shell->is_cmd || $shell->is_command)
258             {
259 0         0 $value = _value_escape_win32($value);
260 0         0 $buffer .= "set $name=$value\n";
261             }
262             elsif($shell->is_power)
263             {
264 0         0 $value = _value_escape_powershell($value);
265 0         0 $buffer .= "\$env:$name = \"$value\"\n";
266             }
267             else
268             {
269 0         0 croak 'don\'t know how to "set" with ' . $shell->name;
270             }
271             }
272              
273             elsif($command eq 'append_path' || $command eq 'prepend_path')
274             {
275 32         156 my($name, @values) = @$args;
276 32 50 0     620 if($shell->is_c)
    50 0        
    0          
    0          
277             {
278 0         0 my $value = join $sep, map { _value_escape_csh($_) } @values;
  0         0  
279 0         0 $buffer .= "test \"\$?$name\" = 0 && setenv $name '$value' || ";
280 0 0       0 if($command eq 'prepend_path')
281 0         0 { $buffer .= "setenv $name '$value$sep'\"\$$name\"" }
282             else
283 0         0 { $buffer .= "setenv $name \"\$$name\"'$sep$value'" }
284 0         0 $buffer .= ";\n";
285             }
286             elsif($shell->is_bourne)
287             {
288 32         930 my $value = join $sep, map { _value_escape_sh($_) } @values;
  64         173  
289 32         96 $buffer .= "if [ -n \"\$$name\" ] ; then\n";
290 32 100       81 if($command eq 'prepend_path')
291 16         37 { $buffer .= " $name='$value$sep'\$$name;\n export $name;\n" }
292             else
293 16         58 { $buffer .= " $name=\$$name'$sep$value';\n export $name\n" }
294 32         54 $buffer .= "else\n";
295 32         90 $buffer .= " $name='$value';\n export $name;\n";
296 32         88 $buffer .= "fi;\n";
297             }
298             elsif($shell->is_fish)
299             {
300 0         0 my $value = join ' ', map { _value_escape_fish($_) } @values;
  0         0  
301 0         0 $buffer .= "if [ \"\$$name\" == \"\" ]; set -x $name $value; else; ";
302 0 0       0 if($command eq 'prepend_path')
303 0         0 { $buffer .= "set -x $name $value \$$name;" }
304             else
305 0         0 { $buffer .= "set -x $name \$$name $value;" }
306 0         0 $buffer .= "end\n";
307             }
308             elsif($shell->is_cmd || $shell->is_command || $shell->is_power)
309             {
310 0 0       0 my $value = join $sep, map { $shell->is_power ? _value_escape_powershell($_) : _value_escape_win32($_) } @values;
  0         0  
311 0 0       0 if($shell->is_power)
312             {
313 0         0 $buffer .= "if(\$env:$name) { ";
314 0 0       0 if($command eq 'prepend_path')
315 0         0 { $buffer .= "\$env:$name = \"$value$sep\" + \$env:$name" }
316             else
317 0         0 { $buffer .= "\$env:$name = \$env:$name + \"$sep$value\"" }
318 0         0 $buffer .= " } else { \$env:$name = \"$value\" }\n";
319             }
320             else
321             {
322 0         0 $buffer .= "if defined $name (set ";
323 0 0       0 if($command eq 'prepend_path')
324 0         0 { $buffer .= "$name=$value$sep%$name%" }
325             else
326 0         0 { $buffer .= "$name=%$name%$sep$value" }
327 0         0 $buffer .=") else (set $name=$value)\n";
328             }
329             }
330             else
331             {
332 0         0 croak 'don\'t know how to "append_path" with ' . $shell->name;
333             }
334             }
335              
336             elsif($command eq 'comment')
337             {
338 10 50 33     178 if($shell->is_unix || $shell->is_power)
    0 0        
339             {
340 10         92 $buffer .= "# $_\n" for map { split /\n/, } @$args;
  10         60  
341             }
342             elsif($shell->is_cmd || $shell->is_command)
343             {
344 0         0 $buffer .= "rem $_\n" for map { split /\n/, } @$args;
  0         0  
345             }
346             else
347             {
348 0         0 croak 'don\'t know how to "comment" with ' . $shell->name;
349             }
350             }
351              
352             elsif($command eq 'alias')
353             {
354 15 100 100     295 if($shell->is_bourne)
    100          
    100          
    100          
    50          
355             {
356 5         57 $buffer .= "alias $args->[0]=\"$args->[1]\";\n";
357             }
358             elsif($shell->is_c)
359             {
360 4         134 $buffer .= "alias $args->[0] $args->[1];\n";
361             }
362             elsif($shell->is_cmd || $shell->is_command)
363             {
364 2         154 $buffer .= "DOSKEY $args->[0]=$args->[1] \$*\n";
365             }
366             elsif($shell->is_power)
367             {
368 3         338 $buffer .= sprintf("function %s { %s \$args }\n", $args->[0], _value_escape_powershell($args->[1]));
369             }
370             elsif($shell->is_fish)
371             {
372 1         139 $buffer .= "alias $args->[0] '$args->[1]';\n";
373             }
374             else
375             {
376 0         0 croak 'don\'t know how to "alias" with ' . $shell->name;
377             }
378             }
379             }
380              
381 50         341 $buffer;
382             }
383              
384              
385             sub generate_file
386             {
387 0     0 1 0 my($self, $shell, $filename) = @_;
388 0         0 my $fh;
389 0 0       0 open($fh, '>', $filename) or die "cannot open $filename: $!";
390 0 0       0 print $fh $self->generate($shell) or die "cannot write $filename: $!";
391 0 0       0 close $fh or die "error closing $filename: $!";
392             }
393              
394             *import = \&Exporter::import;
395              
396             our @EXPORT_OK = qw( win32_space_be_gone cmd_escape_path powershell_escape_path );
397              
398              
399 0     0   0 *_win_to_posix_path = $^O =~ /^(cygwin|msys)$/ ? \&Cygwin::win_to_posix_path : sub { $_[0] };
400 0     0   0 *_posix_to_win_path = $^O =~ /^(cygwin|msys)$/ ? \&Cygwin::posix_to_win_path : sub { $_[0] };
401              
402             sub win32_space_be_gone
403             {
404 1 50   1 1 4973 return @_ if $^O !~ /^(MSWin32|cygwin|msys)$/;
405 0 0         map { /\s/ ? _win_to_posix_path(Win32::GetShortPathName(_posix_to_win_path($_))) : $_ } @_;
  0            
406             }
407              
408              
409             sub cmd_escape_path
410             {
411 0     0 1   my $path = shift() . '';
412 0           $path =~ s/%/%%/g;
413 0           $path =~ s/([&^|<>])/^$1/g;
414 0           $path =~ s/\n/^\n\n/g;
415 0           "\"$path\"";
416             }
417              
418              
419             sub powershell_escape_path
420             {
421 0     0 1   map { my $p = _value_escape_powershell($_); $p =~ s/ /` /g; $p } @_;
  0            
  0            
  0            
422             }
423              
424             1;
425              
426             __END__