File Coverage

blib/lib/Filesys/Virtual/SSH.pm
Criterion Covered Total %
statement 21 21 100.0
branch n/a
condition n/a
subroutine 7 7 100.0
pod n/a
total 28 28 100.0


line stmt bran cond sub pod time code
1             package Filesys::Virtual::SSH;
2 1     1   87239 use strict;
  1         3  
  1         43  
3 1     1   6 use warnings;
  1         2  
  1         37  
4 1     1   5 use File::Basename qw( basename );
  1         7  
  1         99  
5 1     1   6 use Filesys::Virtual::Plain ();
  1         3  
  1         23  
6 1     1   1005 use String::ShellQuote;
  1         842  
  1         61  
7 1     1   6 use IO::File;
  1         2  
  1         158  
8 1     1   6 use base qw( Filesys::Virtual Class::Accessor::Fast );
  1         2  
  1         1827  
9             __PACKAGE__->mk_accessors(qw( cwd root_path home_path host ));
10             our $VERSION = '0.03';
11              
12             =head1 NAME
13              
14             Filesys::Virtual::SSH - remote execution Virtual Filesystem
15              
16             =head1 SYNOPSIS
17              
18             use Filesys::Virtual::SSH;
19             my $fs = Filesys::Virtual::SSH->new({
20             host => 'localhost',
21             cwd => '/',
22             root_path => '/',
23             home_path => '/home',
24             });
25             my @files = $fs->list("/");
26              
27             # a deeply inneffecient equivalent to
28             # my @files = `ls -a /`;
29             # chomp @files;
30              
31              
32             =head1 DESCRIPTION
33              
34             Filesys::Virtual::SSH invokes the ssh command line utility in order to
35             make a remote filesystem have the same api as any other. It's
36             primarily useful for POE::Component::Server::FTP.
37              
38             =cut
39              
40             # HACKY - mixin these from the ::Plain class, they only deal with the
41             # mapping of root_path, cwd, and home_path, so they should be safe
42             *_path_from_root = \&Filesys::Virtual::Plain::_path_from_root;
43             *_resolve_path = \&Filesys::Virtual::Plain::_resolve_path;
44              
45              
46             sub _remote_command {
47             my $self = shift;
48             return "ssh ". $self->host . " ";
49             }
50              
51             sub _remotely {
52             my $self = shift;
53             my $what = shift;
54             my $cmd = $self->_remote_command . shell_quote $what;
55             #warn $cmd;
56             `$cmd`;
57             }
58              
59             sub list {
60             my $self = shift;
61             my $path = $self->_path_from_root( shift );
62              
63             my @files = $self->_remotely( qq{ls -a $path 2> /dev/null} );
64             chomp (@files);
65             return map { basename $_ } @files;
66             }
67              
68             sub list_details {
69             my $self = shift;
70             my $path = $self->_path_from_root( shift );
71              
72             my @lines = $self->_remotely( qq{ls -al $path 2> /dev/null});
73             shift @lines; # I don't care about 'total 42'
74             chomp @lines;
75             return @lines;
76             }
77              
78             sub chdir {
79             my $self = shift;
80             my $to = shift;
81              
82             my $new_cwd = $self->_resolve_path( $to );
83             my $full_path = $self->_path_from_root( $to );
84             # XXX check that full_path is a directory
85             return $self->cwd( $new_cwd );
86             }
87              
88             # well if ::Plain can't be bothered, we can't be bothered either
89             sub modtime { return (0, "") }
90              
91             sub stat {
92             my $self = shift;
93             my $file = $self->_path_from_root( shift );
94              
95             my $stat = $self->_remotely(qq{perl -e'print join ",", stat "$file"'});
96             return split /,/, $stat;
97             }
98              
99             sub size {
100             my $self = shift;
101             return ( $self->stat( shift ))[7];
102             }
103              
104             sub test {
105             my $self = shift;
106             my $test = shift;
107             my $file = $self->_path_from_root( shift );
108             my $stat = $self->_remotely( qq{perl -e'print -$test "$file"'});
109             return $stat;
110             }
111              
112             sub chmod {
113             my $self = shift;
114             my $mode = shift;
115             my $file = $self->_path_from_root( shift );
116             my $ret = $self->_remotely( qq{perl -e'print chmod( $mode, "$file") ? 1 : 0'});
117             return $ret;
118             }
119              
120             sub mkdir {
121             my $self = shift;
122             my $path = $self->_path_from_root( shift );
123             my $ret = $self->_remotely( qq{perl -e'print -d "$path" ? 2 : mkdir( "$path", 0755 ) ? 1 : 0'});
124             return $ret;
125             }
126              
127             sub delete {
128             my $self = shift;
129             my $file = $self->_path_from_root( shift );
130             my $ret = $self->_remotely( qq{perl -e'print unlink("$file") ? 1 : 0'});
131             return $ret;
132             }
133              
134             sub rmdir {
135             my $self = shift;
136             my $path = $self->_path_from_root( shift );
137             my $ret = $self->_remotely( qq{perl -e'print -d "$path" ? rmdir "$path" ? 1 : 0 : unlink "$path" ? 1 : 0'} );
138             return $ret;
139              
140             }
141              
142             # Yeah Yeah, Whatever
143             sub login { 1 }
144              
145             sub open_read {
146             my $self = shift;
147             my $file = $self->_path_from_root( shift );
148             return IO::File->new($self->_remote_command."cat $file |");
149             }
150              
151             sub close_read {
152             my $self = shift;
153             my $fh = shift;
154             close $fh;
155             return 1;
156             }
157              
158             sub open_write {
159             my $self = shift;
160             my $file = $self->_path_from_root( shift );
161             return IO::File->new("|".$self->_remote_command."'cat >> $file'") if @_;
162             return IO::File->new("|".$self->_remote_command."'cat > $file'");
163             }
164              
165             *close_write = \&close_read;
166              
167             1;
168              
169             __END__