raco pkg: support platform-specific package dependencies
A platform-specific dependency is useful for triggering installation of a platform-specific library only on the platform where its needed.
This commit is contained in:
parent
37aa091e1c
commit
b47c1857b5
|
@ -172,7 +172,28 @@
|
|||
(and (list? dep)
|
||||
(= 2 (length dep))
|
||||
(package-source? (car dep))
|
||||
(version? (cadr dep))))))
|
||||
(version? (cadr dep)))
|
||||
(and (list? dep)
|
||||
((length dep) . >= . 1)
|
||||
(odd? (length dep))
|
||||
(package-source? (car dep))
|
||||
(let loop ([saw (hash)] [dep (cdr dep)])
|
||||
(cond
|
||||
[(null? dep) #t]
|
||||
[(hash-ref saw (car dep) #f) #f]
|
||||
[else
|
||||
(define kw (car dep))
|
||||
(define val (cadr dep))
|
||||
(and
|
||||
(cond
|
||||
[(eq? kw '#:version) (version? val)]
|
||||
[(eq? kw '#:platform)
|
||||
(or (string? val)
|
||||
(regexp? val)
|
||||
(memq val '(unix windows macosx)))]
|
||||
[else #f])
|
||||
(loop (hash-set saw (car dep) #t)
|
||||
(cddr dep)))]))))))
|
||||
(pkg-error (~a "invalid `deps' specification\n"
|
||||
" specification: ~e")
|
||||
deps)))
|
||||
|
@ -187,9 +208,30 @@
|
|||
(car dep)))
|
||||
|
||||
(define (dependency->version dep)
|
||||
(if (string? dep)
|
||||
#f
|
||||
(cadr dep)))
|
||||
(cond
|
||||
[(string? dep) #f]
|
||||
[(keyword? (cadr dep))
|
||||
(dependency-lookup '#:version dep)]
|
||||
[else (cadr dep)]))
|
||||
|
||||
(define (dependency-lookup kw dep)
|
||||
(cond
|
||||
[(string? dep) #f]
|
||||
[(keyword? (cadr dep))
|
||||
(define p (member kw (cdr dep)))
|
||||
(and p (cadr p))]
|
||||
[else #f]))
|
||||
|
||||
(define (dependency-this-platform? dep)
|
||||
(define p (dependency-lookup '#:platform dep))
|
||||
(if p
|
||||
(if (symbol? p)
|
||||
(eq? p (system-type))
|
||||
(let ([s (path->string (system-library-subpath #f))])
|
||||
(if (regexp? p)
|
||||
(regexp-match? p s)
|
||||
(equal? p s))))
|
||||
#t))
|
||||
|
||||
(define (with-package-lock* read-only? t)
|
||||
(define d (pkg-dir))
|
||||
|
@ -892,6 +934,7 @@
|
|||
(filter-not (λ (dep)
|
||||
(define name (dependency->name dep))
|
||||
(or (equal? name "racket")
|
||||
(not (dependency-this-platform? dep))
|
||||
(hash-ref simultaneous-installs name #f)
|
||||
(hash-has-key? db name)))
|
||||
deps)))
|
||||
|
@ -948,8 +991,11 @@
|
|||
(filter-map (λ (dep)
|
||||
(define name (dependency->name dep))
|
||||
(define req-vers (dependency->version dep))
|
||||
(define this-platform? (dependency-this-platform? dep))
|
||||
(define-values (inst-vers* can-try-update?)
|
||||
(cond
|
||||
[(not this-platform?)
|
||||
(values #f #f)]
|
||||
[(not req-vers)
|
||||
(values #f #f)]
|
||||
[(equal? name "racket")
|
||||
|
@ -964,7 +1010,8 @@
|
|||
(values (get-metadata metadata-ns (package-directory name)
|
||||
'version (lambda () "0.0"))
|
||||
#t)]))
|
||||
(define inst-vers (if (and req-vers
|
||||
(define inst-vers (if (and this-platform?
|
||||
req-vers
|
||||
(not (and (string? inst-vers*)
|
||||
(valid-version? inst-vers*))))
|
||||
(begin
|
||||
|
@ -974,7 +1021,8 @@
|
|||
inst-vers*)
|
||||
"0.0")
|
||||
inst-vers*))
|
||||
(and req-vers
|
||||
(and this-platform?
|
||||
req-vers
|
||||
((version->integer req-vers)
|
||||
. > .
|
||||
(version->integer inst-vers))
|
||||
|
|
|
@ -632,7 +632,15 @@ Package metadata, including dependencies on other packages, is reported
|
|||
by an @filepath{info.rkt} module within the package. This module must be
|
||||
implemented in the @racketmodname[setup/infotab] language.
|
||||
|
||||
The following fields are used by the package manager:
|
||||
For example, a basic @filepath{info.rkt} file might be
|
||||
|
||||
@codeblock{
|
||||
#lang setup/infotab
|
||||
(define version "1.0")
|
||||
(define deps (list _package-source-string ...))
|
||||
}
|
||||
|
||||
The following @filepath{info.rkt} fields are used by the package manager:
|
||||
|
||||
@itemlist[
|
||||
|
||||
|
@ -640,9 +648,42 @@ The following fields are used by the package manager:
|
|||
@tech{version} of a package is @racket["0.0"].}
|
||||
|
||||
@item{@racketidfont{deps} --- a list of dependencies, where each
|
||||
dependency is either a @tech{package source} strings or a list
|
||||
containing a @tech{package source} string and a
|
||||
@tech{version} string.
|
||||
dependency has one of the following forms:
|
||||
|
||||
@itemlist[
|
||||
|
||||
@item{A string for a @tech{package source}.}
|
||||
|
||||
@item{A list of the form
|
||||
@racketblock[(list _package-source-string
|
||||
_keyword-and-spec ...)]
|
||||
where each @racket[_keyword-and-spec] has a
|
||||
distinct keyword in the form
|
||||
@racketgrammar*[#:literals (quote)
|
||||
[keyword-and-spec
|
||||
(code:line '#:version version-string)
|
||||
(code:line '#:platform platform-spec)]
|
||||
[platform-spec string symbol regexp]]
|
||||
|
||||
A @racket[_version-string] specifies a lower bound
|
||||
on an acceptable @tech{version} of the needed package.
|
||||
|
||||
A @racket[_platform-spec] indicates that the dependency
|
||||
applies only for platforms with a matching result from
|
||||
@racket[(system-type)] when @racket[_platforms-spec] is
|
||||
a symbol or @racket[(path->string
|
||||
(system-library-subpath #f))] when
|
||||
@racket[_platform-spec] is a regular expression. For
|
||||
example, platform-specific binaries can be placed into
|
||||
their own packages, with one separate package and one
|
||||
dependency for each supported platform.}
|
||||
|
||||
@item{A list of the form
|
||||
@racketblock[(list _package-source-string _version-string)]
|
||||
which is deprecated and equivalent to
|
||||
@racketblock[(list _package-source-string '#:version _version-string)]}
|
||||
|
||||
]
|
||||
|
||||
Each elements of the @racketidfont{deps} list determines a
|
||||
dependency on the @tech{package} whose name is inferred from
|
||||
|
@ -651,9 +692,6 @@ The following fields are used by the package manager:
|
|||
indicates where to get the package if needed to satisfy the
|
||||
dependency.
|
||||
|
||||
When provided, a @tech{version} string specifies a lower bound
|
||||
on an acceptable @tech{version} of the package.
|
||||
|
||||
Use the package name @racket["racket"] to specify a dependency
|
||||
on the version of the Racket installation.}
|
||||
|
||||
|
@ -667,14 +705,6 @@ The following fields are used by the package manager:
|
|||
|
||||
]
|
||||
|
||||
For example, a basic @filepath{info.rkt} file might be
|
||||
|
||||
@codeblock{
|
||||
#lang setup/infotab
|
||||
(define version "1.0")
|
||||
(define deps (list _package-source-string ...))
|
||||
}
|
||||
|
||||
@; ----------------------------------------
|
||||
|
||||
@section{@|Planet1| Compatibility}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#lang setup/infotab
|
||||
|
||||
(define deps '(("pkg-v" "2.0")
|
||||
(define deps '(("pkg-v" #:version "2.0")
|
||||
("racket" "5.3.1.10")))
|
||||
|
|
|
@ -52,5 +52,6 @@
|
|||
"update-deps"
|
||||
"update-auto"
|
||||
"versions"
|
||||
"platform"
|
||||
"raco"
|
||||
"indexes")
|
||||
|
|
71
collects/tests/pkg/tests-platform.rkt
Normal file
71
collects/tests/pkg/tests-platform.rkt
Normal file
|
@ -0,0 +1,71 @@
|
|||
#lang racket/base
|
||||
(require rackunit
|
||||
racket/file
|
||||
racket/format
|
||||
pkg/util
|
||||
(prefix-in db: pkg/pnr-db)
|
||||
"shelly.rkt"
|
||||
"util.rkt")
|
||||
|
||||
(pkg-tests
|
||||
(shelly-begin
|
||||
(define pkgs-dir (make-temporary-file "~a-pkgs" 'directory))
|
||||
(define db (build-path pkgs-dir "pnr.sqlite"))
|
||||
(define pkg-x-dir (build-path pkgs-dir "pkg-x"))
|
||||
|
||||
(make-directory* pkg-x-dir)
|
||||
(call-with-output-file*
|
||||
(build-path pkg-x-dir "info.rkt")
|
||||
(lambda (o)
|
||||
(displayln "#lang setup/infotab" o)
|
||||
(write `(define deps '(("pkg-x-windows" #:platform windows)
|
||||
("pkg-x-unix" #:platform unix)
|
||||
("pkg-x-macosx" #:platform macosx)
|
||||
("pkg-x-platform1"
|
||||
#:platform
|
||||
,(path->string (system-library-subpath #f)))
|
||||
("pkg-x-platform2" #:platform #rx".")
|
||||
("pkg-x-platform-no" #:platform #rx"no such platform")))
|
||||
o)))
|
||||
|
||||
(parameterize ([db:current-pkg-index-file db])
|
||||
(db:set-indexes! '("local"))
|
||||
(db:set-pkgs! "local"
|
||||
'("pkg-x" "pkg-x-windows" "pkg-x-unix" "pkg-x-macosx"
|
||||
"pkg-x-platform1" "pkg-x-platform2")))
|
||||
|
||||
(define (create-package name)
|
||||
(define pkg-name name)
|
||||
(define dir (build-path pkgs-dir pkg-name))
|
||||
(make-directory* dir)
|
||||
(define coll-dir (build-path dir name))
|
||||
(make-directory* coll-dir)
|
||||
(call-with-output-file*
|
||||
(build-path coll-dir "main.rkt")
|
||||
(lambda (o)
|
||||
(displayln "#lang racket/base" o)))
|
||||
(parameterize ([db:current-pkg-index-file db])
|
||||
(db:set-pkg! pkg-name "local" "author@place" (path->string dir) "123456" "")))
|
||||
|
||||
(create-package "pkg-x")
|
||||
(create-package "pkg-x-unix")
|
||||
(create-package "pkg-x-windows")
|
||||
(create-package "pkg-x-macosx")
|
||||
(create-package "pkg-x-platform1")
|
||||
(create-package "pkg-x-platform2")
|
||||
|
||||
(with-fake-root
|
||||
(shelly-begin
|
||||
$ (~a "raco pkg config --set indexes file://" (path->string db))
|
||||
$ "racket -e '(require pkg-x)'" =exit> 1
|
||||
$ "raco pkg install --deps search-auto pkg-x" =exit> 0
|
||||
$ "racket -e '(require pkg-x)'" =exit> 0
|
||||
$ (~a "racket -e '(require pkg-x-" (system-type) ")'") =exit> 0
|
||||
$ "racket -e '(require pkg-x-platform1)'" =exit> 0
|
||||
$ "racket -e '(require pkg-x-platform2)'" =exit> 0
|
||||
$ "racket -e '(require pkg-x-platform-no)'" =exit> 1
|
||||
$ "raco pkg remove pkg-x"))
|
||||
|
||||
(delete-directory/files pkgs-dir)))
|
||||
|
||||
|
|
@ -140,6 +140,7 @@
|
|||
(file->string "test-pkgs/pkg-test2.zip.CHECKSUM")
|
||||
'source
|
||||
"http://localhost:9999/pkg-test2.zip"))
|
||||
|
||||
(hash-set! *index-ht-2* "pkg-test2-snd"
|
||||
(hasheq 'checksum
|
||||
(file->string "test-pkgs/pkg-test2.zip.CHECKSUM")
|
||||
|
|
Loading…
Reference in New Issue
Block a user