Thursday, February 28, 2008

Improvements to io.files

Most programming language libraries tend to have pretty weak support for filesystem manipulation compared to what you can find in even the most basic Unix commands.

For example, consider a command like cp (I'll be talking about the GNU variant here). It has three behaviors:
  • You can give it a source file and destination file. It copies it, preserving all attributes if you pass the -a switch.
  • You can give it a source file and a destination directory which already exists. The file is copied into a new file having the same name but inside the destination directory.
  • You can give it a list of source files and a destination directory that must already exist. In this case all the files are copied to the destination directory.

Furthermore, if you use the -r switch you get recursive directory copying.

All the traditional Unix commands, like mv, rm, and so on, support a very rich range of behaviors.

My goal was to recreate this using Factor words. As such, I've beefed up Factor's io.files vocabulary considerably. Unlike the shell, where one command can be overloaded to do various things in a "do what I mean" fashion, programming languages should be somewhat more explicit, in my opinion. So what I've done is implemented the equivalent of various Unix commands where each command maps to several words.

First up is deleting files. Factor already had delete-file and delete-directory for empty directories. What was missing was recursive deletion, so I added delete-tree.

Next up is moving files. Factor had a rename-file word but it could also "rename" it to a different directory, so I changed its name to move-file. I added a move-file-to word which takes a destination directory:
: move-file-to ( from to -- ) over file-name path+ move-file ;

Also I added a move-files-to word which takes a sequence of filenames.

For copying, I already had copy-file. I added copy-file-to and copy-files-to, together with a recursive copy-tree, copy-tree-to, and copy-trees-to.

I'm still thinking about unifying at least some of these words. For example, instead of move-file-to and move-files-to we could have a generic move-to:
GENERIC# move-to 1 ( from to -- )

M: string move-to over file-name path+ move-file ;

M: sequence move-to [ move-to ] curry each ;

Another thing I'm going to add soon is support for globs when deleting, moving and copying files. To do this I just need to add directory globbing to the glob library, which is pretty trivial.

The glob library could add a third method to the above generic:
M: glob move-to >r file-glob r> move-to ;

Once all of this is done, it should be pretty easy for someone to write a portable file manager using the above features. And don't forget portable directory change notification! Factor's I/O capabilities are looking pretty interesting these days indeed...

1 comment:

Anonymous said...

How about "copy-file-into" instead of "copy-file-to"?

I find the distinction between "copy-file" and "copy-file-to" to be pretty subtle. I can imagine saying to myself "copy this file to that file" whereas with "-into", it's clear you mean a directory.