raco pkg: change --scope-dir search-path handling

Formerly, `--scope-dir` would include only the specified directory in
the search path for already installed packages, etc., which means that
it would only work right as a kind of installation scope that is a
step beyond "installation" on the "user"-to-"installation" spectrum.
The `'pkgs-search-dirs` confiugration entry, meanwhile, provides more
control over search ordering in installation scope. Make `--scope-dir`
work more consistently with that search-path configration.

This change also makes "instllation"-scope operations use the search
path more consistently, since some actions used to use the whole
search list while others pruned any prefix before the main
installation directory in the search list.
This commit is contained in:
Matthew Flatt 2018-09-10 06:14:34 -06:00
parent 292dac4e51
commit 0e2ad7d596
5 changed files with 88 additions and 33 deletions

View File

@ -398,9 +398,13 @@ all users of the Racket installation.
A directory path can be used as a @tech{package scope}, in which case
package operations affect the set of packages installations in the
directory. An installation can be configured to include the
directory in its search path for installed packages (see
@secref["config-file" #:doc raco-doc]).
directory. An installation can be configured to include the directory
in its search path for installed packages (see @secref["config-file"
#:doc raco-doc]). When a directory path is used as a @tech{package
scope}, operations such as dependency checking will use all paths in
the configured search path starting with the one that is designed as a
@tech{package scope}; if the designated path is not in the configured
search path, then the dierctory by itself is used as the search path.
Conflict checking disallows installation of the same or conflicting
package in different scopes, but if such a configuration is forced,

View File

@ -78,10 +78,22 @@ directory}:
"pkg/scribblings/pkg.scrbl")]{package scope}. It defaults to
@filepath{pkgs} in the main shared-file directory.}
@item{@indexed-racket['pkgs-search-dirs] --- like
@racket['lib-search-dirs], but for packages in @exec{installation}
@tech[#:doc '(lib "pkg/scribblings/pkg.scrbl")]{package
scope}.}
@item{@indexed-racket['pkgs-search-dirs] --- similar to
@racket['lib-search-dirs], but for packages in roughly
@exec{installation} @tech[#:doc '(lib
"pkg/scribblings/pkg.scrbl")]{package scope}. More precisely, a
@racket[#f] value in the list is replaced with the directory
specified by @racket['pkgs-dir], and that point in the search
list corresponds to @exec{installation} scope. Paths before or
after a @racket[#f] value in the list can be selected as a
scopes to start searches at that path's point in the list.
Directories listed in @racket['pkgs-search-dirs] typically oblige
a corresponding entry in @racket['links-search-files], where
the corresponding entry is @filepath{links.rktd} within the
directory.
@history[#:changed "7.0.0.19" @elem{Adapt the package-search path in
a general way for a directory scope.}]}
@item{@indexed-racket['bin-dir] --- a path, string, or byte string for the
installation's directory containing executables. It defaults to a

View File

@ -0,0 +1,27 @@
#lang racket/base
(require racket/cmdline
setup/dirs)
;; This module is meant to be run via "tests-scope.rkt". It adds the
;; given paths to the package-search list, and it adds "links.rktd" in
;; those paths to the links-search list.
(command-line
#:args
path
(unless (null? path)
(let ([paths path]
[file (build-path (find-config-dir) "config.rktd")])
(define ht (call-with-input-file* file read))
(define new-ht
(hash-set (hash-set ht
'pkgs-search-dirs
(append paths (hash-ref ht 'pkgs-search-dirs '(#f))))
'links-search-files
(append (for/list ([path (in-list paths)])
(path->string (build-path path "links.rktd")))
(hash-ref ht 'links-search-files '(#f)))))
(call-with-output-file*
file
#:exists 'truncate/replace
(lambda (o) (write new-ht o))))))

View File

@ -3,7 +3,8 @@
"util.rkt"
pkg/lib
setup/dirs
racket/format)
racket/format
racket/file)
(this-test-is-run-by-the-main-test)
@ -78,4 +79,22 @@
$ "racket -l racket/base -l pkg-test1/number -e '(number)'" =stdout> "2\n"
$ "raco pkg remove pkg-test1" =stdout> #rx"Inferred package scope: installation")
(initialize-catalogs)
(define alone-dir (make-temporary-file "alone~a" 'directory))
(define in-search-dir (make-temporary-file "in-search~a" 'directory))
(shelly-case
"directory as a package scope"
$ "raco pkg config -i --set catalogs http://localhost:9990 http://localhost:9991"
$ "raco pkg install -i pkg-test1"
$ "racket -l pkg-test1" =stdout> #rx"main loaded"
;; won't find "base" on catalog:
$ (~a "raco pkg install --scope-dir "alone-dir" --auto pkg-test2") =exit> 1 =stderr> #rx"cannot find package.*base"
$ "racket -l pkg-test2" =exit> 1 =stderr> #rx"collection not found"
$ (~a "racket -l tests/pkg/test-scope-add "in-search-dir)
;; will install "pkg-test2" without an extra "pkg-test1" or "base":
$ (~a "raco pkg install --scope-dir "in-search-dir" --auto pkg-test2")
$ "racket -l pkg-test2" =stdout> #rx"pkg-test2/main loaded")
(delete-directory/files alone-dir)
(delete-directory/files in-search-dir)
)))

View File

@ -37,20 +37,10 @@
;; read all packages in this scope or wider
(define (merge-pkg-dbs [scope (current-pkg-scope)])
(define (merge-next-pkg-dbs scope)
(parameterize ([current-pkg-scope scope])
(merge-pkg-dbs scope)))
(if (path? scope)
(read-pkg-db)
(case scope
[(installation)
(for*/hash ([dir (in-list (get-pkgs-search-dirs))]
[(k v) (read-pkgs-db dir)])
(values k v))]
[(user)
(define db (read-pkgs-db 'user (current-pkg-scope-version)))
(for/fold ([ht (merge-next-pkg-dbs 'installation)]) ([(k v) (in-hash db)])
(hash-set ht k v))])))
(for/fold ([ht #hash()]) ([m-scope (in-list (reverse (get-scope-list scope)))])
(define db (read-pkgs-db m-scope (current-pkg-scope-version)))
(for/fold ([ht ht]) ([(k v) (in-hash db)])
(hash-set ht k v))))
;; Finds the scope, in which `pkg-name' is installed; returns 'dir,
;; 'installation, a path, or #f (where #f means "not installed"). If
@ -149,19 +139,22 @@
(and (path? scope)
(build-path scope "links.rktd")))
(define (get-scope-list)
(define (get-scope-list [current-scope (current-pkg-scope)])
;; Get a list of scopes suitable for searches with respect to
;; the current scope
(define current-scope (current-pkg-scope))
(if (path? current-scope)
(list current-scope)
(or
;; Exploit the fact that `member` returns a list starting
;; with the found element:
(member current-scope
(append '(user)
(let ([main (find-pkgs-dir)])
(for/list ([d (get-pkgs-search-dirs)])
(if (equal? d main)
'installation
d)))))))
d)))))
;; In case the specified scope wasn't in the list,
;; then make a search path that has just that scope:
(list current-scope)))
(define (pkg-directory pkg-name #:cache [cache #f])
;; Warning: takes locks individually.