[plt-scheme] Re: Remove File Operations

From: Paulo J. Matos (pocmatos at gmail.com)
Date: Fri May 1 13:14:32 EDT 2009

On Fri, May 1, 2009 at 11:08 AM, Noel Welsh <noelwelsh at gmail.com> wrote:
> On Fri, May 1, 2009 at 11:36 AM, Paulo J. Matos <pocmatos at gmail.com> wrote:
>> Just noticed the title should have been 'Remote' instead of 'Remove'.
>> Anyway, since nobody replied I assume there's nothing. I shall get
>> something going and come back for comments.
> This would be really handy for automated installs (like Capistrano in
> Ruby). Looking forward to it.
> N.

I must note that there are a few issues I must address and I would
welcome suggestions.
The implementation of this library is due to my need of a customized
backup script and I want to do it in scheme, however, I don't want to
assume scheme is installed in the server.

So the idea is to call ssh/scp with the correct flags to perform
certain operations on the server and return.
I started by implementing a process* that calls a command through ssh:
(define (process/ssh* server login command . args)
  (apply process* (ssh-path)
         "-o" "BatchMode=yes"
         "-p" (number->string (server-port server))
         "-l" login
         (server-host server) command args))

This already assumes that there is no password authentication
involved, meaning the user has to ssh-copy-id first.
Allowing password authentication would generate some issues:
- some servers might need passwords, others might not. (if you had
ssh-copy-id'ed first) so you would end up not knowing when to send the
- Imagine you would try reading the output to see if you had
'Password:' in the port to know if you should send password... this
has also issues... it might not show up as 'Password:' but as 'SSH
Passphrase:' (I have seen this before and I think it has to do with
PAM authentication). Also, if the server doesn't need the password but
instead prints a list of files (if you issued the ls command on the
server) and if the first filename is called Password:, you are in

Anyway, the idea here is to have a library that implements a similar
set of functions as plt scheme in reference/Filesystem.html

whose name is appended with '/server' and accepts 2 keywords
arguments, a structure server (hostname + port) and a string with
login, the first defaulting to localhost:22 and the second to your
current user name in you machine.
So, <filesystem-function>/server with default values for server and
login should act the same as <filesystem-function>.

As an example:
#lang scheme

(require scheme/system

;; Server structure, composed by a name and a port
(define-struct server
  (host port))

(define (serv (name "localhost") (port 22))
  (make-server name port))

(define default-server (make-parameter (serv)))
(define ssh-path (make-parameter (find-executable-path "ssh")))

(define (process/ssh* server login command . args)
  (apply process* (ssh-path)
         "-o" "BatchMode=yes"
         "-p" (number->string (server-port server))
         "-l" login
         (server-host server) command args))

;; Gets the current username
(define (current-username)
  (match-let ([(list pout pin id perr proc) (process*
(find-executable-path "whoami"))])
    (read-line pout)))

(define (find-executable-path/server program-sub related-sub (deepest
#f) #:server (server (default-server)) #:login (login
  (match-let (((list pout pin id perr proc) (process/ssh* server login
"which" program-sub)))
    (string->path (read-line pout))))

Note that find-executable-path/server ignores related-sub and deepest
and I still have to work out the best way to do this, still, it does
assume the existence of which on the server which reduces the
portability to server being a linux box (dunno if it would work on mac
but definitely not on windows unless windows kernel is now similar to
unix. Note that for copying I would need to use 'cp', 'rm' for
removing, etc. If you know of a way to extend the portability to more
systems, let me know.

This is my path for continuing this library. I welcome design
suggestions as well and better ways to implement this.
If you think 'Agrh, it would be much useful if you implemented it in
this way or that way...' let me know what's best.

Example of find-executable-path:
> (find-executable-path/server "rm" #f)
> (find-executable-path "rm" #f)


Paulo Jorge Matos - pocmatos at gmail.com
Webpage: http://www.personal.soton.ac.uk/pocm

Posted on the users mailing list.