File Coverage

lib/File/Atomism/utils.pm
Criterion Covered Total %
statement 48 92 52.1
branch 2 8 25.0
condition 1 18 5.5
subroutine 17 22 77.2
pod 0 12 0.0
total 68 152 44.7


line stmt bran cond sub pod time code
1             package File::Atomism::utils;
2              
3             =head1 NAME
4              
5             File::Atomism::utils - Misc file handling stuff
6              
7             =head1 SYNOPSIS
8              
9             Utilities for manipulating and creating filenames.
10              
11             =head1 DESCRIPTION
12              
13             A collection of standard perl functions and utilities for messing
14             with filenames. These are generally useful for manipulating files
15             in an 'atomised' directory, see L.
16              
17             =cut
18              
19 3     3   9720 use strict;
  3         9  
  3         116  
20 3     3   17 use warnings;
  3         5  
  3         96  
21              
22 3     3   8159 use File::stat;
  3         58482  
  3         29  
23 3     3   251 use File::Spec;
  3         8  
  3         352  
24 3     3   16 use Exporter;
  3         6  
  3         144  
25 3     3   16 use File::Path qw /mkpath/;
  3         6  
  3         224  
26 3     3   4706 use Sys::Hostname qw /hostname/;
  3         13697  
  3         242  
27 3     3   3913 use Time::HiRes qw /gettimeofday/;
  3         30147  
  3         24  
28 3     3   930 use Cwd qw /abs_path/;
  3         7  
  3         484  
29              
30             our $CONFDIR = $ENV{ATOMISM_CONF} || $ENV{HOME} ."/.atomism";
31              
32 3     3   28 use vars qw /@ISA @EXPORT_OK/;
  3         6  
  3         4282  
33             @ISA = qw /Exporter/;
34             @EXPORT_OK = qw /Hostname Pid Inode Unixdate Dir File Extension TempFilename PermFilename Journal Undo Redo/;
35              
36             =pod
37              
38             =head1 USAGE
39              
40             Access some values useful for constructing temporary filenames:
41              
42             my $hostname = Hostname();
43             my $pid = Pid();
44             my $unixdate = Unixdate();
45              
46             =cut
47              
48             sub Hostname
49             {
50 1 50   1 0 738 eval {hostname} || 'localhost.localdomain';
  1         6  
51             }
52              
53             sub Pid
54             {
55 1     1 0 192 $$;
56             }
57              
58             sub Unixdate
59             {
60 1     1 0 226 time;
61             }
62              
63             =pod
64              
65             Retrieve the inode of a file like so:
66              
67             my $inode = Inode ('/path/to/my-house.jpg');
68              
69             =cut
70              
71             sub Inode
72             {
73 1     1 0 317 my $filename = shift;
74 1   50     6 my $stat = stat ($filename) || return 0;
75 1         461 $stat->ino;
76             }
77              
78             =pod
79              
80             Access the directory and filename given a path:
81              
82             Dir ('/path/to/my-house.jpg');
83             File ('/path/to/my-house.jpg');
84              
85             .returns '/path/to/' and 'my-house.jpg' respectively.
86              
87             =cut
88              
89             sub Dir
90             {
91 1     1 0 334 my $path = shift;
92 1         30 my ($volume, $dir, $file) = File::Spec->splitpath ($path);
93 1         6 return $dir;
94             }
95              
96             sub File
97             {
98 1     1 0 631 my $path = shift;
99 1         17 my ($volume, $dir, $file) = File::Spec->splitpath ($path);
100 1         4 return $file;
101             }
102              
103             =pod
104              
105             Retrieve the file extension (.doc, .txt, .jpg) of a file like so:
106              
107             my $extension = Extension ('my-house.jpg');
108              
109             =cut
110              
111             sub Extension
112             {
113 1     1 0 356 my $filename = shift;
114 1 50       11 return 0 unless ($filename =~ /[^.]\.[a-z0-9_]+$/);
115 1         7 $filename =~ s/.*\.//;
116 1         4 $filename =~ s/[^a-z0-9_]//gi;
117 1         4 return $filename;
118             }
119              
120             =pod
121              
122             Ask for a temporary filename like so:
123              
124             my $tempname = TempFilename ('/path/to/');
125             or
126             my $tempname = TempFilename ('/path/to/myfile.yml');
127              
128             A unique filepath based on the directory, hostname, current PID and
129             extension (if supplied, otherwise .tmp will be appended) will be
130             returned:
131              
132             /path/to/.foo.example.com-666.tmp
133             /path/to/.foo.example.com-666.yml
134              
135             =cut
136              
137             sub TempFilename
138             {
139 0     0 0   my $path = shift;
140 0   0       my $ext = Extension ($path) || 'tmp';
141              
142 0           Dir ($path) .".". Hostname ."-". Pid .".". $ext;
143             }
144              
145             =pod
146              
147             Ask for a permanent filename like so:
148              
149             my $filename = PermFilename ('/path/to/.foo.example.com-666.yml');
150              
151             A unique filepath based on the hostname, current PID, inode of the
152             temporary file, date and file extension will be supplied:
153              
154             /path/to/foo.example.com-666-1234-1095026759.yml
155              
156             Alternatively you can specify the final extension as a second
157             parameter:
158              
159             my $filename = PermFilename ('/path/to/.foo.example.com-666.tmp', 'yml');
160              
161             =cut
162              
163             sub PermFilename
164             {
165 0     0 0   my $path = shift;
166 0   0       my $ext = shift || Extension ($path);
167              
168 0           Dir ($path) . Hostname ."-". Pid ."-". Inode ($path) ."-". Unixdate .".". $ext;
169             }
170              
171             =pod
172              
173             Write to the undo buffer like so:
174              
175             Journal ([['persistent-file1.yml', '.temp-file1.yml'], [ ... ] ]);
176              
177             =cut
178              
179             sub Journal
180             {
181 0     0 0   my $list = shift;
182              
183             # figure out where to put the journal from the first pair of files
184 0   0       my $dir = Dir (abs_path ($list->[0]->[0])) || Dir (abs_path ($list->[0]->[1]));
185              
186 0           my $undodir = $CONFDIR ."/UNDO". $dir;
187 0           my $redodir = $CONFDIR ."/REDO". $dir;
188 0           mkpath ([$undodir, $redodir]);
189              
190 0           my $journal = $undodir . join (".", gettimeofday) .".patch";
191              
192 0           for my $item (@{$list})
  0            
193             {
194 0   0       my $old = abs_path ($item->[0]) || '/dev/null';
195 0   0       my $new = abs_path ($item->[1]) || '/dev/null';
196              
197 0           `diff -u $old $new >> $journal;`;
198             }
199 0           system 'sync';
200             }
201              
202             =pod
203              
204             Undo the most recent change to the journal by supplying a directory
205             path to the Undo() method:
206              
207             Undo ('/path/to');
208              
209             =cut
210              
211             sub Undo
212             {
213 0     0 0   my $dir = abs_path (shift);
214 0           my $undodir = $CONFDIR ."/UNDO". $dir;
215 0           my $redodir = $CONFDIR ."/REDO". $dir;
216              
217 0 0         opendir (DIR, $undodir) or warn "$!";
218 0           my @files = sort (readdir (DIR));
219 0           @files = grep !/^\./, @files;
220 0   0       my $file = pop (@files) || return;
221              
222 0           my $undo = $undodir ."/". $file;
223 0           my $redo = $redodir ."/". $file;
224              
225 0           `cd $dir; patch -p0 --batch --no-backup < $undo; cd -`;
226 0           rename $undo, $redo;
227 0           system 'sync';
228              
229 0           closedir (DIR);
230             }
231              
232             =pod
233              
234             Undo the most recent undo() with the Redo() method. Usage is the
235             same as for Undo():
236              
237             Redo ('/path/to');
238              
239             =cut
240              
241             sub Redo
242             {
243 0     0 0   my $dir = abs_path (shift);
244 0           my $undodir = $CONFDIR ."/UNDO". $dir;
245 0           my $redodir = $CONFDIR ."/REDO". $dir;
246              
247 0 0         opendir (DIR, $redodir) or warn "$!";
248 0           my @files = sort (readdir (DIR));
249 0           @files = grep !/^\./, @files;
250 0   0       my $file = shift (@files) || return;
251              
252 0           my $undo = $undodir ."/". $file;
253 0           my $redo = $redodir ."/". $file;
254              
255 0           `cd $dir; patch -p0 --force --no-backup < $redo; cd -`;
256 0           rename $redo, $undo;
257 0           system 'sync';
258              
259 0           closedir (DIR);
260             }
261              
262             1;