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