racket/collects/planet2/name.rkt
Matthew Flatt 381d9d84d6 raco pkg: switch from "METADATA.rktd" to "info.rkt"
For now, "METADATA.rktd" is still recognized as a fallback.

Also, rewrite package source type and name inference,
make ".zip" the default format for `raco pkg create',
and many doc edits.
2012-11-30 19:09:19 -07:00

104 lines
3.7 KiB
Racket

#lang racket/base
(require racket/list
net/url)
(provide package-source->name+type
package-source->name)
(define rx:package-name #rx"^[-_a-zA-Z0-9]+$")
(define rx:archive #rx"[.](plt|zip|tar|tgz|tar[.]gz)$")
(define (validate-name name)
(and name
(regexp-match? rx:package-name name)
name))
(define (extract-archive-name name+ext)
(validate-name
(path->string
(if (regexp-match #rx#"[.]tar[.]gz$" (if (path? name+ext)
(path->bytes name+ext)
name+ext))
(path-replace-suffix (path-replace-suffix name+ext #"") #"")
(path-replace-suffix name+ext #"")))))
(define (last-non-empty p)
(cond
[(null? p) #f]
[else (or (last-non-empty (cdr p))
(and (not (equal? "" (path/param-path (car p))))
(car p)))]))
(define (package-source->name+type s type)
;; returns (values inferred-name inferred-type);
;; if `type' is given it should be returned, but name can be #f;
;; type should not be #f for a non-#f name
(cond
[(if type
(eq? type 'name)
(regexp-match? rx:package-name s))
(values (and (regexp-match? rx:package-name s) s) 'name)]
[(and (eq? type 'github)
(not (regexp-match? #rx"^github://" s)))
(package-source->name+type
(string-append "github://github.com/" s)
'github)]
[(if type
(or (eq? type 'github)
(eq? type 'file-url)
(eq? type 'dir-url))
(regexp-match? #rx"^(https?|github)://" s))
(define url (with-handlers ([exn:fail? (lambda (exn) #f)])
(string->url s)))
(define-values (name name-type)
(if url
(let ([p (url-path url)])
(cond
[(if type
(eq? type 'github)
(equal? (url-scheme url) "github"))
(define name
(and (pair? p)
(let ([p (if (equal? "" (path/param-path (last p)))
(reverse (cdr (reverse p)))
p)])
(and ((length p) . >= . 3)
(validate-name
(if (= (length p) 3)
(path/param-path (second (reverse p)))
(path/param-path (last-non-empty p))))))))
(values name (or type (and name 'github)))]
[(if type
(eq? type 'file-url)
(and (pair? p)
(regexp-match? rx:archive (path/param-path (last p)))))
(values (and (pair? p)
(extract-archive-name (path/param-path (last-non-empty p))))
'file-url)]
[else
(values (validate-name (path/param-path (last-non-empty p))) 'dir-url)]))
(values #f #f)))
(values (validate-name name) (or type (and name name-type)))]
[(and (not type)
(regexp-match? #rx"^[a-zA-Z]*://" s))
(values #f #f)]
[(if type
(eq? type 'file)
(and (path-string? s)
(regexp-match rx:archive s)))
(define-values (base name+ext dir?) (split-path s))
(define name (extract-archive-name name+ext))
(values name 'file)]
[(if type
(or (eq? type 'dir) (eq? type 'link))
(path-string? s))
(define-values (base name dir?) (split-path s))
(define dir-name (and (path? name) (path->string name)))
(values (validate-name dir-name) (or type (and dir-name 'dir)))]
[else
(values #f #f)]))
(define (package-source->name s)
(define-values (name type) (package-source->name+type s #f))
name)