|
232 | 232 | (equal? p s))))
|
233 | 233 | #t))
|
234 | 234 |
|
| 235 | +(define pkg-lock-held (make-parameter #f)) |
| 236 | + |
235 | 237 | (define (with-pkg-lock* read-only? t)
|
236 |
| - (define d (pkg-dir)) |
237 |
| - (unless read-only? (make-directory* d)) |
238 |
| - (if (directory-exists? d) |
239 |
| - ;; If the directory exists, assume that a lock file is |
240 |
| - ;; available or creatable: |
241 |
| - (call-with-file-lock/timeout |
242 |
| - #f (if read-only? 'shared 'exclusive) |
243 |
| - t |
244 |
| - (λ () (pkg-error (~a "could not acquire package lock\n" |
245 |
| - " lock file: ~a") |
246 |
| - (pkg-lock-file))) |
247 |
| - #:lock-file (pkg-lock-file)) |
248 |
| - ;; Directory does not exist; we must be in read-only mode. |
249 |
| - ;; Run `t' under the claim that no database is available |
250 |
| - ;; (in case the database is created concurrently): |
251 |
| - (parameterize ([current-no-pkg-db #t]) |
252 |
| - (t)))) |
| 238 | + (define mode (if read-only? 'shared 'exclusive)) |
| 239 | + (define held-mode (pkg-lock-held)) |
| 240 | + (if (or (eq? mode held-mode) |
| 241 | + (eq? 'exclusive held-mode)) |
| 242 | + (t) |
| 243 | + (let ([d (pkg-dir)]) |
| 244 | + (unless read-only? (make-directory* d)) |
| 245 | + (if (directory-exists? d) |
| 246 | + ;; If the directory exists, assume that a lock file is |
| 247 | + ;; available or creatable: |
| 248 | + (call-with-file-lock/timeout |
| 249 | + #f |
| 250 | + mode |
| 251 | + (lambda () |
| 252 | + (parameterize ([pkg-lock-held mode]) |
| 253 | + (t))) |
| 254 | + (λ () (pkg-error (~a "could not acquire package lock\n" |
| 255 | + " lock file: ~a") |
| 256 | + (pkg-lock-file))) |
| 257 | + #:lock-file (pkg-lock-file)) |
| 258 | + ;; Directory does not exist; we must be in read-only mode. |
| 259 | + ;; Run `t' under the claim that no database is available |
| 260 | + ;; (in case the database is created concurrently): |
| 261 | + (parameterize ([current-no-pkg-db #t]) |
| 262 | + (parameterize ([pkg-lock-held mode]) |
| 263 | + (t))))))) |
253 | 264 | (define-syntax-rule (with-pkg-lock e ...)
|
254 | 265 | (with-pkg-lock* #f (λ () e ...)))
|
255 | 266 | (define-syntax-rule (with-pkg-lock/read-only e ...)
|
|
269 | 280 | "https://planet-compat.racket-lang.org")]))))
|
270 | 281 |
|
271 | 282 | (define (pkg-config-indexes)
|
272 |
| - (read-pkg-cfg/def "indexes")) |
| 283 | + (with-pkg-lock/read-only |
| 284 | + (read-pkg-cfg/def "indexes"))) |
273 | 285 |
|
274 | 286 | (define (pkg-indexes)
|
275 | 287 | (or (current-pkg-indexes)
|
|
449 | 461 | [else 'user]))
|
450 | 462 | (define (default-pkg-scope-as-string)
|
451 | 463 | (parameterize ([current-pkg-scope 'installation])
|
452 |
| - (define cfg (read-pkg-cfg)) |
453 |
| - (hash-ref cfg "default-scope" "user"))) |
| 464 | + (with-pkg-lock/read-only |
| 465 | + (define cfg (read-pkg-cfg)) |
| 466 | + (hash-ref cfg "default-scope" "user")))) |
454 | 467 |
|
455 | 468 | (struct pkg-info (orig-pkg checksum auto?) #:prefab)
|
456 | 469 | (struct install-info (name orig-pkg directory clean? checksum))
|
|
463 | 476 | [checksum op]))
|
464 | 477 |
|
465 | 478 | (define (pkg-directory pkg-name)
|
466 |
| - (match-define (pkg-info orig-pkg checksum _) |
467 |
| - (package-info pkg-name)) |
468 |
| - (match orig-pkg |
469 |
| - [`(link ,orig-pkg-dir) |
470 |
| - orig-pkg-dir] |
471 |
| - [_ |
472 |
| - (build-path (pkg-installed-dir) pkg-name)])) |
| 479 | + (for/or ([scope (in-list '(user shared installation))]) |
| 480 | + (parameterize ([current-pkg-scope scope]) |
| 481 | + (with-pkg-lock/read-only |
| 482 | + (define info (package-info pkg-name #f)) |
| 483 | + (and info |
| 484 | + (let () |
| 485 | + (match-define (pkg-info orig-pkg checksum _) info) |
| 486 | + (match orig-pkg |
| 487 | + [`(link ,orig-pkg-dir) |
| 488 | + orig-pkg-dir] |
| 489 | + [_ |
| 490 | + (build-path (pkg-installed-dir) pkg-name)]))))))) |
| 491 | + |
| 492 | +(define (path->pkg given-p) |
| 493 | + (define (explode p) |
| 494 | + (explode-path |
| 495 | + (normal-case-path |
| 496 | + (simple-form-path p)))) |
| 497 | + (define (sub-path? < p d) |
| 498 | + (and ((length d) . <= . (length p)) |
| 499 | + (for/and ([de (in-list d)] |
| 500 | + [pe (in-list p)]) |
| 501 | + (equal? de pe)))) |
| 502 | + (define p (explode given-p)) |
| 503 | + (for/or ([scope (in-list '(user shared installation))]) |
| 504 | + (parameterize ([current-pkg-scope scope]) |
| 505 | + (with-pkg-lock/read-only |
| 506 | + (define d (explode (pkg-installed-dir))) |
| 507 | + (cond |
| 508 | + [(sub-path? < p d) |
| 509 | + ;; Under the installation mode's package directory. |
| 510 | + ;; We assume that no one else writes there, so the |
| 511 | + ;; next path element is the package name. |
| 512 | + (path-element->string (list-ref p (length d)))] |
| 513 | + [else |
| 514 | + ;; Maybe it's a linked package |
| 515 | + (for/or ([(k v) (in-hash (read-pkg-db))]) |
| 516 | + (match (pkg-info-orig-pkg v) |
| 517 | + [`(link ,orig-pkg-dir) |
| 518 | + (and (sub-path? <= p (explode orig-pkg-dir)) |
| 519 | + k)] |
| 520 | + [else #f]))]))))) |
473 | 521 |
|
474 | 522 | (define (remove-package pkg-name)
|
475 | 523 | (printf "Removing ~a\n" pkg-name)
|
|
1666 | 1714 | (parameter/c (or/c #f (listof url?)))]
|
1667 | 1715 | [pkg-directory
|
1668 | 1716 | (-> string? path-string?)]
|
| 1717 | + [path->pkg |
| 1718 | + (-> path-string? (or/c #f string?))] |
1669 | 1719 | [pkg-desc
|
1670 | 1720 | (-> string?
|
1671 | 1721 | (or/c #f 'file 'dir 'link 'file-url 'dir-url 'github 'name)
|
|
0 commit comments