FTP-editing: A 15 month old story done in one hour

Padre’s trac still contains ticket #12 “Add remote editing capability via ftp and ssh” which is 15 month old.

7 weeks ago, Padre::File was added, which should take over all file activity within Padre.

I just started Padre::File::FTP yesterday night which plugs in an FTP server as file storage . Net::FTP was easy to use and I wondered that basic FTP support including write access was not only started, but finished within an hour.

Changeset 9096 added the FTP module including many TODO’s. Here is a quick walkthrough:

                if ($url !~ /ftp\:\/?\/?((.+?)(\:(.+?))?\@)?([a-z0-9\-\.]+)(\:(\d+))?(\/.+)$/i) {
	                # URL parsing failed
	                # TODO: Warning should go to a user popup not to the text console
	                warn 'Unable to parse '.$url;
	                return;
	        }
	        # Login data
	        if (defined($2)) {
	         $self->{_user} = $2;
	         $self->{_pass} = $4 if defined($4);
	        } else {
	         $self->{_user} = 'ftp';
	         $self->{_pass} = 'padre_user@devnull.perlide.org';
	        }
	        # Host & port
	        $self->{_host} = $5;
	        $self->{_port} = $7 || 21;
	        # Path & filename
	        $self->{_file} = $8;

Padre should be able to open everything in one-line-URL-format. The URL parsing regular expression accepts optional username/passwort, a server, a optional port and a filename. If no username is defined, the module switches to hard-coded anonymous FTP values. Everything is stored into the blessed “self” hash as individual keys for easy access.

 $self->{_ftp} = Net::FTP->new(
 Host => $self->{_host},
 Port => $self->{_port},
 Timeout => 120, # TODO: Make this configurable
 Passive => 1, # TODO: Make this configurable
 );

Host and port are used from the URL, static values for timeout and passive mode are ok for a first start and until there is a configuration dialog for Padre::File preferences. A warning is issues on connection problems (this needs to be improved).

$self->{_file_temp} = File::Temp->new( UNLINK => 1 );
$self->{_tmpfile} = $self->{_file_temp}->filename;

Net::FTP offers direct access for data connections but I preferred the good-old get and put commands for this first basic solution. A local tempfile is required for them and File::Temp provides a good OS-independent way of managing tempfiles. The object needs to be stored as the temp file will be finally removed as soon as the File::Temp object is destroyed.

There are some helper methods (like ->exists or ->size), but file access is the most important thing we need:

	sub read {
	        my $self = shift;
	        $self->{_ftp}->get($self->{_file},$self->{_tmpfile}) or warn $@;
	        open my $tmpfh,$self->{_tmpfile};
	        return join('',<$tmpfh>);
	}

This method downloads the FTP-file into a local temporary file and just returns the local content. Net::FTP lacks an easy way to get a file directly into a variable, but this is also ok – we’re still talking about a first basic solution.

The next step was done in changeset 9097: Adding support for FTP-style URLs to Padre::File.

Everything – including generation of the module, looking up Net::FTP documentation was done in less than one hour. I really didn’t expect it to be this simple and fast but you see – helping on Padre is much less time-consuming than you might think.

Bookmark and Share

Tags: , , ,

Leave a Reply