fix clone-linked package update on evolving to a multi-package repo

When a package "p" is clone-linked and the repo for "p" changes to be
a multi-package repository (e.g., with "p-lib", "p-doc", and "p"), a
`raco update` would get confused. Unofrtunately, a plain `raco pkg
update p` can't work in that case, because the clone link would still
be a pathless repo URL; the repairs make `raco pkg update --lookup
--clone ..../p` work as is should.

Related: fix inference of package names in the early check for whether
a package is installed.
This commit is contained in:
Matthew Flatt 2015-06-29 17:06:39 -06:00
parent 6f6a792d06
commit 138e16e80f
4 changed files with 94 additions and 23 deletions

View File

@ -161,7 +161,7 @@ the package is should be treated as installed automatically for a
dependency. dependency.
The optional @racket[path] argument is intended for use when The optional @racket[path] argument is intended for use when
@racket[type] is @racket['clone], in which case it specifies< a @racket[type] is @racket['clone], in which case it specifies a
directory containing the repository clone (where the repository itself directory containing the repository clone (where the repository itself
is a directory within @racket[path]). is a directory within @racket[path]).

View File

@ -44,14 +44,15 @@
(define a-dir (build-path tmp-dir "a")) (define a-dir (build-path tmp-dir "a"))
(define (commit-changes-cmd [a-dir a-dir])
(~a "cd " a-dir "; git add .; git commit -m change; git update-server-info"))
;; ---------------------------------------- ;; ----------------------------------------
;; Single-package repository ;; Single-package repository
(make-directory a-dir) (make-directory a-dir)
$ (~a "cd " a-dir "; git init") $ (~a "cd " a-dir "; git init")
(set-file (build-path a-dir "main.rkt") "#lang racket/base 1") (set-file (build-path a-dir "main.rkt") "#lang racket/base 1")
(define (commit-changes-cmd [a-dir a-dir])
(~a "cd " a-dir "; git add .; git commit -m change; git update-server-info"))
$ (commit-changes-cmd) $ (commit-changes-cmd)
(with-fake-root (with-fake-root
@ -186,6 +187,61 @@
(delete-directory/files (build-path clone-dir "a")) (delete-directory/files (build-path clone-dir "a"))
(delete-directory/files a-dir) (delete-directory/files a-dir)
;; ----------------------------------------
;; Single-package repository that becomes multi-package
(define (check-changing try-bogus?)
(shelly-case
"Single-package repository that becomes multi-package"
(make-directory a-dir)
$ (~a "cd " a-dir "; git init")
(set-file (build-path a-dir "main.rkt") "#lang racket/base 1")
$ (commit-changes-cmd)
(with-fake-root
(shelly-begin
(shelly-case
"--clone installation with path into repository"
$ (~a "raco pkg install --clone " (build-path clone-dir "a") " --name one http://localhost:9998/a/.git")
$ "racket -l one" =stdout> "1\n"
$ (~a "ls " (build-path clone-dir "a")))
$ (~a "cd " a-dir "; git rm main.rkt")
(make-directory* (build-path a-dir "one"))
(set-file (build-path a-dir "one" "main.rkt") "#lang racket/base 1")
(set-file (build-path a-dir "one" "info.rkt") "#lang info (define deps '(\"http://localhost:9998/a/.git?path=two\"))")
(make-directory* (build-path a-dir "two"))
(set-file (build-path a-dir "two" "main.rkt") "#lang racket/base 2")
$ (commit-changes-cmd)
(when try-bogus?
;; A `raco pkg update one` at this point effectively
;; breaks the package installation, because the package
;; source will remain pathless. We only try this sometimes,
;; so that we check the next step with an without creating
;; paths "one" and "two" before that step.
(shelly-begin
$ "raco pkg update one"
$ "racket -l one" =exit> 1))
$ (~a "raco pkg update --clone " (build-path clone-dir "a") " --auto --multi-clone convert http://localhost:9998/a/.git?path=one")
$ "racket -l one" =stdout> "1\n"
$ "racket -l two" =stdout> "2\n"
(set-file (build-path a-dir "two" "main.rkt") "#lang racket/base 2.0")
$ (commit-changes-cmd)
$ "racket -l two" =stdout> "2\n"
$ "raco pkg update two"
$ "racket -l two" =stdout> "2.0\n"))
(delete-directory/files (build-path clone-dir "a"))
(delete-directory/files a-dir)))
(check-changing #f)
(check-changing #t)
;; ---------------------------------------- ;; ----------------------------------------
;; Using local changes for metadata ;; Using local changes for metadata

View File

@ -128,7 +128,7 @@
" package: ~a\n" " package: ~a\n"
" given path: ~a\n") " given path: ~a\n")
pkg pkg
name) clone)
(list pkg)] (list pkg)]
[else [else
((pkg-error cmd) ((pkg-error cmd)

View File

@ -83,17 +83,21 @@
pkg-path pkg-path
pkg-name))) pkg-name)))
;; Check installed packages: ;; Check installed packages:
(for ([f (in-directory simple-pkg-path)]) (when (directory-exists? simple-pkg-path) ; might not exist for a clone shifting to a subdir
(define found-pkg (path->pkg f #:cache path-pkg-cache)) (for ([f (in-directory simple-pkg-path)])
(when (and found-pkg (define found-pkg (path->pkg f #:cache path-pkg-cache))
(not (equal? found-pkg pkg-name))) (when (and found-pkg
(pkg-error (~a "cannot link a directory that overlaps with existing packages\n" (not (equal? found-pkg pkg-name))
" existing package: ~a\n" ;; In case a new clone dir would overlap with an old one that is being
" overlapping path: ~a\n" ;; relocated (and if simultaneous installs really overlap, it's caught below):
" attempted package: ~a") (not (hash-ref simultaneous-installs found-pkg #f)))
found-pkg (pkg-error (~a "cannot link a directory that overlaps with existing packages\n"
f " existing package: ~a\n"
pkg-name))) " overlapping path: ~a\n"
" attempted package: ~a")
found-pkg
f
pkg-name))))
;; Check simultaneous installs: ;; Check simultaneous installs:
(for ([(other-pkg other-dir) (in-hash simultaneous-installs)]) (for ([(other-pkg other-dir) (in-hash simultaneous-installs)])
(unless (equal? other-pkg pkg-name) (unless (equal? other-pkg pkg-name)
@ -993,7 +997,7 @@
(pkg-desc-type pkg-name) (pkg-desc-type pkg-name)
#:link-dirs? link-dirs? #:link-dirs? link-dirs?
#:must-infer-name? (not (pkg-desc-name pkg-name)) #:must-infer-name? (not (pkg-desc-name pkg-name))
#:complain (complain-about-source (pkg-desc-name pkg-name)))) #:complain (complain-about-source (pkg-desc-name pkg-name))))
(define name (or (pkg-desc-name pkg-name) (define name (or (pkg-desc-name pkg-name)
inferred-name)) inferred-name))
;; Check that the package is installed, and get current checksum: ;; Check that the package is installed, and get current checksum:
@ -1296,14 +1300,25 @@
(define (early-check-for-installed in-pkgs db #:wanted? wanted?) (define (early-check-for-installed in-pkgs db #:wanted? wanted?)
(for ([d (in-list in-pkgs)]) (for ([d (in-list in-pkgs)])
(define name (define-values (name ignored-type)
(if (pkg-desc? d) (if (pkg-desc? d)
(or (pkg-desc-name d) ;; For install of update:
(package-source->name (pkg-desc-source d) (cond
(if (eq? 'clone (pkg-desc-type d)) [(pkg-desc-name d)
'name (values (pkg-desc-name d) #f)]
(pkg-desc-type d)))) [(and (eq? (pkg-desc-type d) 'clone)
(package-source->name d))) ;; If syntax of the source is a package name, then it's a package name:
(let-values ([(name type) (package-source->name+type (pkg-desc-source d) 'name)])
name))
=> (lambda (name)
(values name #f))]
[else
(package-source->name+type (pkg-desc-source d)
(pkg-desc-type d)
#:must-infer-name? #t
#:complain (complain-about-source #f))])
;; Must be a string package name for update:
(values d #f)))
(define info (package-info name wanted? #:db db)) (define info (package-info name wanted? #:db db))
(when (and info (when (and info
(not wanted?) (not wanted?)