#lang scheme/base (provide get-svn-tree get-plt-svn-tree) (require "tree.rkt" scheme/system scheme/match xml) (define svn-exe (find-executable-path "svn")) (define (svn . args) ;; runs an svn command, just returns its stdout to be used to its end (define-values [p pout pin perr] (apply subprocess #f #f (current-error-port) svn-exe args)) (close-output-port pin) pout) ;; ---------------------------------------------------------------------------- ;; Reading a tree from a subversion url (define ((starts-with sym) x) (and (pair? x) (eq? sym (car x)) x)) (define (get-svn-tree url) (let* ([data (read-xml (svn "ls" "-R" "--xml" url))] [data (xml->xexpr (document-element data))] [data (ormap (starts-with 'list) (cddr data))] [data (filter (starts-with 'entry) (cddr data))] [data (map (lambda (x) (match x [(list _ `([kind ,kind]) _ ... `(name () ,name) _ ...) (cons (string->symbol kind) (regexp-split #rx#"/" (string->bytes/utf-8 name)))])) data)]) ;; utilities (define (listbytes/utf-8 url) #"/")]) (let dloop ([items '()]) (let ([tail (and (pair? data) (subtract-prefix (cdar data) pathlist))]) (if tail (let* ([kind (caar data)] [pathlist (cdar data)] [name (if (= 1 (length tail)) (car tail) (error 'get-svn-tree "got an element without parent dir: ~e" (cdar data)))] [name (if (eq? 'dir kind) (bytes-append name #"/") name)] [path (bytes-append path name)]) (pop!) (dloop (cons (case kind [(dir) (loop name pathlist path)] [(file) (make-tree name #f path)] [else (error 'get-svn-tree "got an element with ~a: ~e" "an unexpected kind" kind)]) items))) (make-tree name (reverse items) path))))))) ;; ---------------------------------------------------------------------------- ;; Reading the PLT tree (define (get-plt-svn-tree) (get-svn-tree "http://svn.plt-scheme.org/plt/trunk/")) #| (tree-for-each (lambda (t) (printf "~a\n" (tree-path t))) (time (get-svn-tree "file:///home/svn/plt/trunk/"))) |#