File Coverage

blib/lib/Wrangler/FileSystem/Layers.pm
Criterion Covered Total %
statement 6 151 3.9
branch 0 46 0.0
condition 0 3 0.0
subroutine 2 39 5.1
pod 0 37 0.0
total 8 276 2.9


line stmt bran cond sub pod time code
1             package Wrangler::FileSystem::Layers;
2              
3 1     1   6 use strict;
  1         3  
  1         38  
4 1     1   6 use warnings;
  1         2  
  1         3079  
5              
6             our @filesystems;
7              
8             sub new {
9 0     0 0   my $class = shift;
10 0           my $self = bless({ @_ }, $class);
11              
12             # hardcoded for now
13 0           require Wrangler::FileSystem::Linux;
14 0           push(@filesystems, Wrangler::FileSystem::Linux->new() );
15              
16 0           return $self;
17             }
18              
19             sub get_property {
20 0     0 0   warn('Layers does not offer a get_property() method, well, for now. You probably want to use richproperty() with a narrow wishlist!');
21             }
22              
23             my $regex_case1 = qr/^Extended Attributes::/;
24             my $regex_case2 = qr/^MIME/;
25             my $regex_case3 = qr/^Filesystem::/;
26             my $regex_case4 = qr/mode$|Modified$|Filename$|Basename$|Suffix$/;
27             sub can_mod {
28 0     0 0   my $self = shift;
29 0           my $metakey = shift;
30 0 0         return 1 if $metakey =~ $regex_case1;
31 0 0         return 0 if $metakey =~ $regex_case2;
32 0 0 0       return 1 if $metakey =~ $regex_case3 && $metakey =~ $regex_case4;
33 0           return 0;
34             }
35              
36             sub can_del {
37 0     0 0   my $self = shift;
38 0           my $metakey = shift;
39             # Wrangler::debug("Layers::can_del: $metakey 1 ") if $metakey =~ $regex_case1;
40 0 0         return 1 if $metakey =~ $regex_case1;
41 0           return 0;
42             }
43              
44             sub set_property {
45 0     0 0   my ($self, $path, $metakey, $newval) = @_;
46              
47 0 0         unless($path){ warn 'path missing!'; return 0; }
  0            
  0            
48 0 0         unless($metakey){ warn 'metadata-key missing!'; return 0; }
  0            
  0            
49              
50 0 0         unless( $self->can_mod($metakey) ){ warn "set_property can't modify property: '$metakey' on '$path'"; return 0; }
  0            
  0            
51              
52 0 0         if($metakey =~ $regex_case1){
53 0           my $ns = 'Extended Attributes';
54 0           $metakey =~ s/$regex_case1//;
55 0           Wrangler::debug("Layers::set_property: $path : $ns : $metakey = $newval");
56 0           return $filesystems[0]->setfattr($path, $metakey, $newval );
57             }else{
58 0           warn 'Unimplemented or unknown namespace!';
59 0           return 0;
60             }
61             }
62              
63             my $regex_asterisk = qr/\*/;
64             sub del_property {
65 0     0 0   my ($self, $path, $metakey) = @_;
66              
67 0 0         unless($path){ warn 'path missing!'; return 0; }
  0            
  0            
68 0 0         unless($metakey){ warn 'metadata-key missing!'; return 0; }
  0            
  0            
69              
70             # allow globbing for del_property
71 0           my @metakeys = ();
72 0 0         if($metakey =~ $regex_asterisk){
73 0           Wrangler::debug("Layers::del_property: globbed metakey $path : $metakey");
74              
75 0           my $richproperties = $self->richproperties($path);
76 0           $metakey =~ s/\./\\./g;
77 0           for(keys %$richproperties){
78             # Wrangler::debug("Layers::del_property: adding globbed $_") if $_ =~ /^$metakey/;
79 0 0         push(@metakeys, $_) if $_ =~ /^$metakey/;
80             }
81             }else{
82 0           push(@metakeys, $metakey);
83             }
84              
85 0           my @errors;
86              
87             # be more atomic
88 0           for my $metakey (@metakeys){
89 0 0         push(@errors, "set_property can't delete property: $metakey on $path") unless $self->can_del($metakey);
90             }
91              
92 0 0         return @errors ? 0 : 1 if @errors;
    0          
93              
94 0           for my $metakey (@metakeys){
95 0 0         if($metakey =~ $regex_case1){
96 0           my $ns = 'Extended Attributes';
97 0           $metakey =~ s/$regex_case1//;
98 0           Wrangler::debug("Layers::del_property: $path : $ns : $metakey");
99 0 0         $filesystems[0]->delfattr($path, $metakey ) or push(@errors, $!);
100             }else{
101 0           push(@errors, "Unimplemented or unknown namespace: $metakey");
102             }
103             }
104              
105 0 0         return @errors ? 0 : 1;
106             }
107              
108             sub available_properties {
109 0     0 0   my $self = shift;
110 0           my $path = shift;
111              
112             # call each dimension's available_properties (todo, one dimension for now)
113 0           my $prop_ref = $filesystems[0]->available_properties($path);
114              
115 0           return $prop_ref;
116             }
117              
118             sub richproperties {
119             # my $self = shift;
120             # my $path = shift;
121             # my $wishlist = shift;
122              
123             # call each dimension's properties (todo, one dimension for now)
124 0     0 0   my $prop_ref = $filesystems[0]->properties($_[1],$_[2]);
125              
126 0           return $prop_ref;
127             }
128              
129              
130             sub richlist {
131 0     0 0   my $self = shift;
132 0           my $path = Cwd::abs_path(shift); # see note on abs_path in list()
133 0           my $wishlist = shift;
134             # Wrangler::debug("Layers::richlist: @$wishlist") if $wishlist;
135              
136             # call each dimension's properties (todo, one dimension for now)
137             # on error, an array-ref blessed with 'error' is returned
138 0           my $richlist = $filesystems[0]->list($path,$wishlist);
139              
140 0 0         return wantarray ? ($richlist,$path) : $richlist;
141             }
142              
143             sub renderer {
144 0     0 0   my %renderer = (
145             'Filesystem::Size' => \&nice_filesize_KB,
146             'Filesystem::Accessed' => \&HTTP::Date::time2iso,
147             'Filesystem::Modified' => \&HTTP::Date::time2iso,
148             'Filesystem::Changed' => \&HTTP::Date::time2iso,
149             );
150              
151 0 0         return defined($renderer{$_[1]}) ? $renderer{$_[1]} : undef;
152             }
153              
154             ## a value "renderer"
155             sub nice_filesize_KB {
156 0     0 0   my $size = shift;
157              
158 0 0         if( $size == 0 ){
159 0           return "0 KB";
160             }
161              
162 0 0         if( $size < 1000 ){
163 0           $size = '1';
164             }else{
165 0           $size = int(($size + 500) / 1000);
166             # $size = $size;
167             }
168              
169 0 0         if(length($size) > 3){
170 0           $size = reverse($size);
171 0           $size = substr($size, 0,3) . "." . substr($size, 3,length($size));
172 0           $size = reverse($size);
173             }
174              
175 0           return "$size KB";
176             }
177              
178             ## a value "renderer"
179             sub nice_filesize_MB {
180 0     0 0   my $size = shift;
181              
182 0           $size = sprintf("%.2f", ($size / 1000000));
183              
184 0           return "$size MB";
185             }
186              
187             sub ask_vfs {
188 0     0 0   return 'ask_vfs';
189             }
190              
191              
192             ## other wrappers (todo, as currently most return early)
193             sub cwd {
194 0     0 0   shift(@_); # put away self for now
195 0           return $filesystems[0]->cwd(@_);
196             }
197              
198             sub fileparse {
199 0     0 0   shift(@_); # put away self for now
200 0           return $filesystems[0]->fileparse(@_);
201             }
202              
203             sub catfile {
204 0     0 0   shift(@_); # put away self for now
205 0           return $filesystems[0]->catfile(@_);
206             }
207              
208             sub mount {
209 0     0 0   shift(@_); # put away self for now
210 0           for(@filesystems){
211 0           return $_->mount(@_);
212             }
213             }
214              
215             sub unmount {
216 0     0 0   shift(@_); # put away self for now
217 0           for(@filesystems){
218 0           return $_->unmount(@_);
219             }
220             }
221              
222             sub mounts {
223 0     0 0   shift(@_); # put away self for now
224 0           for(@filesystems){
225 0           return $_->mounts(@_);
226             }
227             }
228              
229             sub parent {
230 0     0 0   shift(@_); # put away self for now
231 0           for(@filesystems){
232 0           return $_->parent(@_);
233             }
234             }
235              
236             sub test {
237 0     0 0   shift(@_); # put away self for now
238 0           for(@filesystems){
239 0           return $_->test(@_);
240             }
241             }
242              
243             sub list {
244 0     0 0   warn('Layers does not offer a list() method, use richlist() instead!');
245             }
246              
247             sub stat {
248 0     0 0   warn('Layers does not offer a stat() method, use richproperties() instead!');
249             }
250              
251             sub delete {
252 0     0 0   shift(@_); # put away self for now
253 0           for(@filesystems){
254 0           return $_->delete(@_);
255             }
256             }
257              
258             sub symlink {
259 0     0 0   shift(@_); # put away self for now
260 0           for(@filesystems){
261 0           return $_->symlink(@_);
262             }
263             }
264              
265             sub mknod {
266 0     0 0   shift(@_); # put away self for now
267 0           for(@filesystems){
268 0           return $_->mknod(@_);
269             }
270             }
271              
272             sub mkdir {
273 0     0 0   shift(@_); # put away self for now
274 0           for(@filesystems){
275 0           return $_->mkdir(@_);
276             }
277             }
278              
279             sub rmdir {
280 0     0 0   shift(@_); # put away self for now
281 0           for(@filesystems){
282 0           return $_->rmdir(@_);
283             }
284             }
285              
286             sub trash {
287 0     0 0   shift(@_); # put away self for now
288 0           for(@filesystems){
289 0           return $_->trash(@_);
290             }
291             }
292              
293             sub rename {
294 0     0 0   shift(@_); # put away self for now
295 0           for(@filesystems){
296             # print "Layers::rename: @_\n";
297 0           return $_->rename(@_);
298             }
299             }
300              
301             sub move {
302 0     0 0   shift(@_); # put away self for now
303 0           for(@filesystems){
304             # print "Layers::move: @_\n";
305 0           return $_->move(@_);
306             }
307             }
308              
309             sub copy {
310 0     0 0   shift(@_); # put away self for now
311 0           for(@filesystems){
312 0           return $_->copy(@_);
313             }
314             }
315              
316             # todo: Layers shouldn't offer a utime at all. Todo: make sure it's used nowhere and force set_property
317             sub utime {
318 0     0 0   shift(@_); # put away self for now
319 0           for(@filesystems){
320 0           return $_->utime(@_);
321             }
322             }
323              
324             sub listfattr {
325 0     0 0   warn('Layers does not offer any low-level xattr methods, use richproperties() instead!');
326             }
327              
328             sub getfattr {
329 0     0 0   warn('Layers does not offer any low-level xattr methods, use get_property() instead!');
330             }
331              
332             sub setfattr {
333 0     0 0   warn('Layers does not offer any low-level xattr methods, use set_property() instead!');
334             }
335              
336             sub delfattr {
337 0     0 0   warn('Layers does not offer any low-level xattr methods, use del_property() instead!');
338             }
339              
340             our %exts = ( # possibly no 'x-something', as per RFC 6648
341             '3ds' => '3D Studio Mesh File',
342             '6rn' => 'Rendition Image',
343             a3d => 'MegaGamma 3D LUT File',
344             aac => 'AAC Audio File',
345             aaf => ['Advanced Authoring Format File', 'application/aaf'],
346             acf => 'ACF Curve File',
347             acv => 'Adobe Photoshop Curve File',
348             aiff => 'AIFF Audio File',
349             als => 'Alias Image',
350             ani => ['Windows Animated Cursor Image', 'image/x-icon'], # mime unknown; not exactly ico/cur, but usually apps able to read the latter read it
351             arw => ['Sony RAW Image', 'image/x-sony-arw'],
352             asf => 'Windows Media Audio/Video File',
353             asx => 'ASX Playlist',
354             au => ['Basic Audio File', 'audio/basic'],
355             avi => 'Microsoft AVI File',
356             bat => 'Batch Script',
357             bak => 'Backup File',
358             bef => 'Unified Color HDR Image',
359             bmp => 'Bitmap Graphic',
360             bz2 => 'bzip2 Archive',
361             blend => ['Blender 3D File', 'application/blender'],
362             blend1 => ['Blender 3D Backup File', 'application/blender'],
363             blend2 => ['Blender 3D Backup File', 'application/blender'],
364             cals => 'CALS (Continuous Acquisition and Life-cycle Support) Image',
365             cel => 'Autodesk Animator (Intermediate) Image', # an extended single frame .fli or .flc
366             cin => 'Kodak Cineon Image', # similar to DPX
367             cur => ['Windows Cursor Image', 'image/x-icon'], # same as .ico with header declaring it as .cur
368             cr2 => ['Canon Raw Image', 'image/x-canon-cr2'],
369             crw => ['Canon Raw Image', 'image/x-canon-crw'],
370             cws => 'Combustion Workspace File',
371             db => 'Database File',
372             dat => ['KUKA Robot Language .dat File', 'text/plain'],
373             dcm => ['DICOM Image', 'application/dicom'],
374             dicom => ['DICOM Image', 'application/dicom'],
375             dcr => ['Kodak Digital Camera RAW File', 'image/raw'],
376             divx => 'DivX Video',
377             dng => ['Digital Negative Image', 'image/adobe-dng'],
378             doc => 'Microsoft Word Document',
379             docm => 'Office Open XML Document',
380             docx => 'Office Open XML Document',
381             dpx => 'Digital Picture Exchange Image',
382             droid => ['EditDroid Session-db Dump', 'application/editdroid'],
383             dxf => ['Drawing Interchange File', 'image/vnd.dxf'],
384             edl => ['Edit Decision List/CMX3600', 'text/plain'],
385             eps => 'Encapsulated PostScript File',
386             exe => 'Executable',
387             exr => 'OpenEXR HDR Image',
388             fcp => 'Final Cut Pro File',
389             fdr => 'Final Draft File', # old version 5 - 7 format
390             fdx => 'Final Draft 8 File', # version 8, 9 ... format
391             flac => ['Free Lossless Audio File', 'audio/flac'],
392             fli => 'Autodesk Animator Animation', # max 320x200
393             flc => 'Autodesk Animator Pro Animation',
394             flv => ['Flash Video', 'video/x-flv'],
395             flx => 'Autodesk Image/Animation File', # 3DStudio MAX, also Tempra Pro
396             fs => 'Framestore Image',
397             gbf => 'Panavision Binary Format (settings) File',
398             gif => 'GIF Image',
399             graphml => ['GraphML File', 'application/graphml+xml'],
400             gz => 'gzip Archive',
401             h264 => 'h264 Video',
402             hdr => 'Radiance RGBE HDR Image',
403             hgignore => 'Mercurial .hgignore File',
404             htm => 'HTML Markup File',
405             html => 'HTML Markup File',
406             ico => ['Windows Icon Image', 'image/x-icon'], # compare .cur; sometimes image/vnd.microsoft.icon
407             iff => 'Interchange File Format', # also Autodesk Maya IFF variant
408             ion => 'Descript.ion File',
409             iso => 'ISO Disk Image',
410             jif => 'Jeffs Image Format', # patent-free GIF alternative
411             jls => 'JPEG-LS Image',
412             jp2 => ['JPEG 2000 Image', 'image/jp2'],
413             jpg => ['JPEG Image', 'image/jpeg'],
414             jpe => ['JPEG Image', 'image/jpeg'],
415             jpeg => ['JPEG Image', 'image/jpeg'],
416             jpx => ['JPEG 2000 Image', 'image/jpx'],
417             lnk => ['Internet URL', 'text/plain'],
418             lut => 'Thomson Luther 3D LUT File',
419             lwo => 'Lightwave Object',
420             lws => 'Lightwave Scene',
421             m2ts => ['Blu-ray Disc Audio-Video MPEG-2 Transport Stream (BDAV+M2TS)', 'video/MP2T'], # RFC3555
422             m2p => ['MPEG Program Stream', 'video/MP2P'], # RFC3555
423             m3u => 'M3U Playlist',
424             m3u8 => ['M3U Playlist (UTF-8)', 'application/x-mpegURL'], # also vnd.apple.mpegURL
425             m4a => 'MP4 AAC Audio',
426             m4p => 'MP4 Protected Audio',
427             max => '3D Studio MAX File',
428             mid => ['MIDI File', 'audio/midi'],
429             midi => ['MIDI File', 'audio/midi'],
430             md => ['Markdown File', 'text/markdown'],
431             mkv => ['Matroska Video', 'video/x-matroska'],
432             mk3d => ['Matroska 3D Video', 'video/x-matroska'],
433             mka => ['Matroska Audio File', 'audio/x-matroska'],
434             mov => 'Apple QuickTime Media Container',
435             motn => 'Apple Shake Motion Project File',
436             movie => ['Silicon Graphics Video', 'video/x-sgi-movie'],
437             mp3 => 'MP3 Audio File',
438             mp4 => 'MP4 Audio-/Video File',
439             mpg => 'MPEG-1 Video',
440             mpeg => 'MPEG-2 Video',
441             mrw => 'Sony (Minolta) Raw Image',
442             mxf => ['Material Exchange Format File','application/mxf'],
443             nar => 'Nikon Capture Advanced Raw Image',
444             ncv => 'Nikon Capture Curves File',
445             nef => ['Nikon RAW Image', 'image/x-nikon-nef'],
446             nid => 'Nikon IPTC Data',
447             nk => 'Nuke File',
448             nrw => 'Nikon Raw Image',
449             nut => ['NUT Open Container Format File', 'application/octet-stream'], # mime type?
450             nwb => 'Nikon White Balance File',
451             ogg => 'OGG Media',
452             omf => ['Open Media Framework Interchange File', 'application/avid-omf'],
453             on2 => 'On2 VP6 Video',
454             part => 'Incomplete Download',
455             pbm => 'Portable Anymap Bitmap Image',
456             pcs => 'Apple PICS Animation',
457             pct => ['Apple PICT Image', 'image/x-pict'],
458             pcx => ['PC Exchange/Paintbrush Image', 'image/x-pcx'],
459             pdf => 'Portable Document Format File',
460             pgm => 'Portable Anymap Graymap Image',
461             php => 'PHP Dynamic HTML',
462             php3 => 'PHP Dynamic HTML',
463             pix => 'Alias Raster Image',
464             pic => ['Apple PICT Image', 'image/x-pict'], # also Autodesk Softimage
465             pict => ['Apple PICT Image', 'image/x-pict'],
466             pl => 'Perl Script',
467             png => 'PNG Image',
468             pnm => 'Portable Anymap Image',
469             pm => 'Perl Module',
470             ppm => 'Portable Anymap Pixmap Image',
471             ps => 'PostScript File',
472             ppt => 'Microsoft PowerPoint Presentation',
473             pptm => 'Office Open XML Presentation',
474             pptx => 'Office Open XML Presentation',
475             psd => 'Photoshop Format Image',
476             pxr => ['Pixar Image', 'image/pixar'], # 24/33 bit per pixel log format tiff variant
477             py => ['Python Script', 'text/x-python'],
478             pyc => ['Python Compiled Bytecode', 'application/x-python-code'],
479             pyo => ['Python Compiled Bytecode', 'application/x-python-code'],
480             qtl => 'QuickTime Playlist',
481             rar => 'rar Archive',
482             raw => 'Raw Image or Audio Data',
483             r3d => 'RED Camera Redcode Raw File',
484             rgb => ['SGI IRIS Image', 'image/x-rgb'],
485             rla => 'Wavefront Advanced Visualizer Image', # RLE compressed
486             rsx => 'RED Camera metadata file',
487             save => 'nano Editor Backup File',
488             sct => 'Scitex CT (Continuous Tone) Image',
489             sgi => ['SGI IRIS Image', 'image/sgi'],
490             smil => 'Smil Playlist',
491             sr2 => ['Sony Raw Image File', 'image/x-sony-sr2'],
492             src => ['KUKA Robot Language .src File', 'text/plain'],
493             srf => 'Sony Raw Image File',
494             stp => 'STEP 3D File',
495             'sub' => ['Close Captioning/ Subtitle File', 'image/vnd.dvb.subtitle'],
496             sun => ['SUN Raster Image', 'image/sun-raster'],
497             svg => ['Scalable Vector Graphics File', 'image/svg+xml'],
498             svgz => ['Compressed Scalable Vector Graphics File', 'image/svg+xml'],
499             swf => 'Shockwave Flash File',
500             sys => 'Microsoft System File',
501             shtml => 'Dynamic HTML',
502             tdi => 'Thompson Digital Image', # similar/same Maja IFF
503             tiff => ['Tagged Image File Format Image', 'image/tiff'], # image/tiff, image/tiff-fx
504             tif => ['Tagged Image File Format Image', 'image/tiff'], # image/tiff, image/tiff-fx
505             tga => ['Targa Image File', 'image/targa'], # image/x-targa, image/x-tga
506             tgz => 'tar/gzip Archive',
507             thm => ['Canon Thumbnail Image', 'image/jpeg'],
508             tpic => ['Targa Image File', 'image/targa'], # image/x-targa, image/x-tga
509             ts => ['MPEG-2 Transport Stream', 'video/mp2ts'], # http://www.ietf.org/mail-archive/web/ietf-types/current/msg01593.html
510             txt => 'Text Document',
511             veg => ['Sony Vegas Project File', 'application/vegas80'], # application/vegas81, application/vegas90, ...
512             vcf => 'vCard File',
513             vff => 'Sun TAAC Image',
514             vob => ['DVD Video File', 'video/dvd'],
515             wav => ['Waveform Audio File Format File', 'audio/wav'], # audio/vnd.wave, audio/wave
516             webm => ['WebM Audio-/Video File', 'video/webm'], # also audio/webm
517             webp => ['WebP Image', 'image/webp'],
518             wfl => ['Wrangler Field Layout', 'application/json'], # exported/imported by FormEditor, is application/json
519             wma => ['Windows Media Audio', 'audio/ms-wma'],
520             wmv => ['Windows Media Video', 'audio/ms-wmv'],
521             xbm => 'X Bitmap File',
522             xmp => ['Extensible Metadata Platform File', 'application/rdf+xml'],
523             xcf => 'GIMP Image',
524             xls => 'Microsoft Excel Spreadsheets',
525             xlsm => 'Office Open XML Spreadsheets',
526             xlsx => 'Office Open XML Spreadsheets',
527             yaml => 'YAML Markup File',
528             zip => 'zip Archive',
529             );
530              
531             1;
532              
533             __END__