main.ss
#lang scheme/base

(require (for-syntax scheme/base)
         (only-in (lib "etc.ss") this-expression-source-directory)
         scheme/file)

(provide list-permutation?
         keep-new-directories?
         in-new-directory
         in-this-directory)

(define (remove-first x ls [equiv? eq?])
  (let loop ([ls ls] [result '()])
    (cond
      [(null? ls) #f]
      [(equiv? (car ls) x) (append (reverse result) (cdr ls))]
      [else (loop (cdr ls) (cons (car ls) result))])))

(define (list-permutation? ls1 ls2 [equiv? eq?])
  (let loop ([ls1 ls1] [ls2 ls2])
    (cond
      [(and (null? ls1) (null? ls2)) #t]
      [(or (null? ls1) (null? ls2)) #f]
      [(remove-first (car ls1) ls2 equiv?)
       => (lambda (ls2*)
            (loop (cdr ls1) ls2*))]
      [else #f])))

(define-syntax (in-this-directory stx)
  (syntax-case stx ()
    [(_ e1 e2 ...)
     (with-syntax ([cwd (syntax/loc stx
                          (this-expression-source-directory e1))])
       #'(parameterize ([current-directory cwd])
           e1 e2 ...))]))

(define (rm-rf path)
  (when (or (file-exists? path) (directory-exists? path))
    (delete-directory/files path)))

(define keep-new-directories?
  (make-parameter #f (lambda (new-b)
                       (if (not (boolean? new-b))
                           (raise-type-error 'keep-new-directories? "boolean" new-b)
                           new-b))))

(define-syntax in-new-directory
  (syntax-rules ()
    [(_ dir-e e1 e2 ...)
     (let ([dir dir-e])
       (dynamic-wind
        void
        (lambda ()
          (when (directory-exists? dir)
            (error 'in-new-directory "can't create directory ~a; directory exists" dir))
          (make-directory* dir)
          (parameterize ([current-directory dir]
                         [keep-new-directories? #t])
            e1 e2 ...))
        (lambda ()
          (unless (keep-new-directories?)
            (rm-rf dir)))))]))