#lang scheme/base (provide find-version) (define (find-version base-path vers) (let-values ([(dir name _) (split-path (bytes->path base-path))]) (let ([files (with-handlers ([exn:fail:filesystem? (lambda (exn) null)]) (directory-list dir))]) (and files (let* ([p (path-element->bytes name)] [len (bytes-length p)] [candidate-versions (filter values (map (lambda (file) (let ([s (path-element->bytes file)]) (and (and (len . < . (bytes-length s)) (bytes=? p (subbytes s 0 len))) (let ([ext (let ([m (regexp-match #rx#"([.][a-z]+)?[.](rkt|ss|sls)$" (subbytes s len))]) (and m (or (not (cadr m)) (bytes=? (cadr m) #".mzscheme")) (car m)))]) (and ext (or (and (= (bytes-length s) (+ len (bytes-length ext))) (cons null ext)) (let ([vers (subbytes s len (- (bytes-length s) (bytes-length ext)))]) (and (regexp-match #rx#"^(-[0-9]+)+$" vers) (cons (map string->number (cdr (map bytes->string/latin-1 (regexp-split #rx#"-" vers)))) ext))))))))) files))] [versions (let* ([eo '(#".mzscheme.ss" #".mzscheme.sls" #".ss" #".sls" #".rkt")] [ext< (lambda (a b) (> (length (member a eo)) (length (member b eo))))]) (sort candidate-versions (lambda (a b) (if (equal? (car a) (car b)) (ext< (cdr a) (cdr b)) (let loop ([a (car a)] [b (car b)]) (cond [(null? a) #t] [(null? b) #f] [(> (car a) (car b)) #t] [(< (car a) (car b)) #f] [else (loop (cdr a) (cdr b))]))))))]) (ormap (lambda (candidate-version) (and (version-match? (car candidate-version) vers) (cons (car candidate-version) (bytes->string/latin-1 (cdr candidate-version))))) versions)))))) (define (version-match? cand vers) (cond [(null? vers) #t] [(null? cand) #f] [(eq? (car vers) 'and) (andmap (lambda (v) (version-match? cand v)) (cdr vers))] [(eq? (car vers) 'or) (ormap (lambda (v) (version-match? cand v)) (cdr vers))] [(eq? (car vers) 'not) (not (version-match? cand (cadr vers)))] [(sub-version-match? (car cand) (car vers)) (version-match? (cdr cand) (cdr vers))] [else #f])) (define (sub-version-match? cand subvers) (cond [(number? subvers) (= cand subvers)] [else (case (car subvers) [(>=) (>= cand (cadr subvers))] [(<=) (<= cand (cadr subvers))] [(and) (andmap (lambda (sv) (sub-version-match? cand sv)) (cdr subvers))] [(or) (ormap (lambda (sv) (sub-version-match? cand sv)) (cdr subvers))] [(not) (not (sub-version-match? cand (cadr subvers)))] [else (error "bad subversion")])]))