I know there is the function copy-directory/files
, but I want a function that while descending directories performs some tasks before copying (see actions-on-dir
). Here is the code I have written so far.
#lang racket
(provide (prefix-out charon: recursive-copy))
;; Isn't there a builtin function for this?
(define path-basename
(compose last explode-path))
;; Try to perform an action. If any failure occurs, just print the
;; error and go ahead as if nothing happened.
(define-syntax-rule (try-and-go-on action)
(with-handlers ([exn:fail?
(λ (e) (printf "ERROR: ~a\n" (exn-message e)))])
action))
;; Copy a file into a given directory. Modification times are
;; considered to avoid copying when the copy is already up to date.
(define (copy-file-to-directory src-file dest)
(try-and-go-on
(let* ([name (path-basename src-file)]
[copy (build-path dest name)])
(if (file-exists? copy)
(let ([mt1 (file-or-directory-modify-seconds src-file)]
[mt2 (file-or-directory-modify-seconds copy)])
(when (> mt1 mt2)
(copy-file src-file copy #:exists-ok? #t)))
(copy-file src-file copy #:exists-ok? #t)))))
(define (ls dir)
(map path->string (directory-list dir)))
(define (actions-on dir)
(current-directory dir)
(let* ([dir-cont (ls dir)]
[exts (map path-get-extension dir-cont)])
(cond
;; project managed with `make`
[(member "Makefile" dir-cont)
(printf "INFO: running \"make clean\" in ~a...\n" dir)
(system "make clean")]
;; Haskell projects
[(member ".stack-work" dir-cont)
(printf "INFO: running \"stack purge\" in ~a...\n" dir)
(system "stack purge")]
[(member #".cabal" exts)
(printf "INFO: running \"cabal clean\" in ~a...\n" dir)
(system "cabal clean")])))
(define (recursive-copy src dest)
(if (file-exists? src)
(copy-file-to-directory src dest)
(begin
(actions-on src)
(let* ([name (path-basename src)]
[new-dest (build-path dest name)])
(make-directory* new-dest)
(for-each
(λ (e) (recursive-copy (build-path src e) new-dest))
(directory-list src))))))
I'm relatively new to Racket: I'm exploring it as I come up with small programs I need for some routine work. Is this decent, or can be made more simple? In particular, there is a function I don't get how it works but I think it might be useful here: the function fold-files.