File Coverage

blib/lib/Stow/Util.pm
Criterion Covered Total %
statement 49 55 89.0
branch 10 16 62.5
condition 9 9 100.0
subroutine 12 13 92.3
pod 4 9 44.4
total 84 102 82.3


line stmt bran cond sub pod time code
1             # This file is part of GNU Stow.
2             #
3             # GNU Stow is free software: you can redistribute it and/or modify it
4             # under the terms of the GNU General Public License as published by
5             # the Free Software Foundation, either version 3 of the License, or
6             # (at your option) any later version.
7             #
8             # GNU Stow is distributed in the hope that it will be useful, but
9             # WITHOUT ANY WARRANTY; without even the implied warranty of
10             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11             # General Public License for more details.
12             #
13             # You should have received a copy of the GNU General Public License
14             # along with this program. If not, see https://www.gnu.org/licenses/.
15              
16             package Stow::Util;
17              
18             =head1 NAME
19              
20             Stow::Util - general utilities
21              
22             =head1 SYNOPSIS
23              
24             use Stow::Util qw(debug set_debug_level error ...);
25              
26             =head1 DESCRIPTION
27              
28             Supporting utility routines for L.
29              
30             =cut
31              
32 16     16   103866 use strict;
  16         55  
  16         476  
33 16     16   75 use warnings;
  16         29  
  16         446  
34              
35 16     16   1590 use POSIX qw(getcwd);
  16         22048  
  16         79  
36              
37 16     16   5237 use base qw(Exporter);
  16         31  
  16         15191  
38             our @EXPORT_OK = qw(
39             error debug set_debug_level set_test_mode
40             join_paths parent canon_path restore_cwd adjust_dotfile
41             );
42              
43             our $ProgramName = 'stow';
44             our $VERSION = '2.3.1';
45              
46             #############################################################################
47             #
48             # General Utilities: nothing stow specific here.
49             #
50             #############################################################################
51              
52             =head1 IMPORTABLE SUBROUTINES
53              
54             =head2 error($format, @args)
55              
56             Outputs an error message in a consistent form and then dies.
57              
58             =cut
59              
60             sub error {
61 0     0 1 0 my ($format, @args) = @_;
62 0         0 die "$ProgramName: ERROR: " . sprintf($format, @args) . "\n";
63             }
64              
65             =head2 set_debug_level($level)
66              
67             Sets verbosity level for C.
68              
69             =cut
70              
71             our $debug_level = 0;
72              
73             sub set_debug_level {
74 78     78 1 158 my ($level) = @_;
75 78         177 $debug_level = $level;
76             }
77              
78             =head2 set_test_mode($on_or_off)
79              
80             Sets testmode on or off.
81              
82             =cut
83              
84             our $test_mode = 0;
85              
86             sub set_test_mode {
87 78     78 1 130 my ($on_or_off) = @_;
88 78 50       158 if ($on_or_off) {
89 78         138 $test_mode = 1;
90             }
91             else {
92 0         0 $test_mode = 0;
93             }
94             }
95              
96             =head2 debug($level, $msg)
97              
98             Logs to STDERR based on C<$debug_level> setting. C<$level> is the
99             minimum verbosity level required to output C<$msg>. All output is to
100             STDERR to preserve backward compatibility, except for in test mode,
101             when STDOUT is used instead. In test mode, the verbosity can be
102             overridden via the C environment variable.
103              
104             Verbosity rules:
105              
106             =over 4
107              
108             =item 0: errors only
109              
110             =item >= 1: print operations: LINK/UNLINK/MKDIR/RMDIR/MV
111              
112             =item >= 2: print operation exceptions
113              
114             e.g. "_this_ already points to _that_", skipping, deferring,
115             overriding, fixing invalid links
116              
117             =item >= 3: print trace detail: trace: stow/unstow/package/contents/node
118              
119             =item >= 4: debug helper routines
120              
121             =item >= 5: debug ignore lists
122              
123             =back
124              
125             =cut
126              
127             sub debug {
128 10146     10146 1 15659 my ($level, $msg) = @_;
129 10146 50       21756 if ($debug_level >= $level) {
130 0 0       0 if ($test_mode) {
131 0         0 print "# $msg\n";
132             }
133             else {
134 0         0 warn "$msg\n";
135             }
136             }
137             }
138              
139             #===== METHOD ===============================================================
140             # Name : join_paths()
141             # Purpose : concatenates given paths
142             # Parameters: path1, path2, ... => paths
143             # Returns : concatenation of given paths
144             # Throws : n/a
145             # Comments : factors out redundant path elements:
146             # : '//' => '/' and 'a/b/../c' => 'a/c'
147             #============================================================================
148             sub join_paths {
149 6329     6329 0 27417 my @paths = @_;
150              
151             # weed out empty components and concatenate
152 6329         10104 my $result = join '/', grep {! /\A\z/} @paths;
  13157         34904  
153              
154             # factor out back references and remove redundant /'s)
155 6329         9345 my @result = ();
156             PART:
157 6329         22320 for my $part (split m{/+}, $result) {
158 20764 100       34897 next PART if $part eq '.';
159 20031 100 100     52228 if (@result && $part eq '..' && $result[-1] ne '..') {
      100        
160 103         189 pop @result;
161             }
162             else {
163 19928         33471 push @result, $part;
164             }
165             }
166              
167 6329         35393 return join '/', @result;
168             }
169              
170             #===== METHOD ===============================================================
171             # Name : parent
172             # Purpose : find the parent of the given path
173             # Parameters: @path => components of the path
174             # Returns : returns a path string
175             # Throws : n/a
176             # Comments : allows you to send multiple chunks of the path
177             # : (this feature is currently not used)
178             #============================================================================
179             sub parent {
180 191     191 0 440 my @path = @_;
181 191         397 my $path = join '/', @_;
182 191         792 my @elts = split m{/+}, $path;
183 191         346 pop @elts;
184 191         729 return join '/', @elts;
185             }
186              
187             #===== METHOD ===============================================================
188             # Name : canon_path
189             # Purpose : find absolute canonical path of given path
190             # Parameters: $path
191             # Returns : absolute canonical path
192             # Throws : n/a
193             # Comments : is this significantly different from File::Spec->rel2abs?
194             #============================================================================
195             sub canon_path {
196 171     171 0 1939 my ($path) = @_;
197              
198 171         1367 my $cwd = getcwd();
199 171 50       1395 chdir($path) or error("canon_path: cannot chdir to $path from $cwd");
200 171         1243 my $canon_path = getcwd();
201 171         494 restore_cwd($cwd);
202              
203 171         653 return $canon_path;
204             }
205              
206             sub restore_cwd {
207 292     292 0 523 my ($prev) = @_;
208 292 50       2831 chdir($prev) or error("Your current directory $prev seems to have vanished");
209             }
210              
211             sub adjust_dotfile {
212 17     17 0 33 my ($target) = @_;
213              
214 17         26 my @result = ();
215 17         58 for my $part (split m{/+}, $target) {
216 32 100 100     94 if (($part ne "dot-") && ($part ne "dot-.")) {
217 26         64 $part =~ s/^dot-/./;
218             }
219 32         65 push @result, $part;
220             }
221              
222 17         49 return join '/', @result;
223             }
224              
225             =head1 BUGS
226              
227             =head1 SEE ALSO
228              
229             =cut
230              
231             1;
232              
233             # Local variables:
234             # mode: perl
235             # cperl-indent-level: 4
236             # end:
237             # vim: ft=perl