From b25e9fd0d4415e48dcf9b8bff98416a570ffa6c5 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Fri, 2 May 2014 10:18:35 -0600 Subject: [PATCH] raco setup: check package version deps and multiple module declarations The package dependency checking process was already gathering all the reelvant information, or nearly all of it, so it's relatively cheap to add the checks. --- .../racket-doc/scribblings/raco/setup.scrbl | 12 +- racket/collects/setup/private/pkg-deps.rkt | 197 +++++++++++++----- 2 files changed, 148 insertions(+), 61 deletions(-) diff --git a/pkgs/racket-pkgs/racket-doc/scribblings/raco/setup.scrbl b/pkgs/racket-pkgs/racket-doc/scribblings/raco/setup.scrbl index e350c9b5ee..bf7ddd5ab6 100644 --- a/pkgs/racket-pkgs/racket-doc/scribblings/raco/setup.scrbl +++ b/pkgs/racket-pkgs/racket-doc/scribblings/raco/setup.scrbl @@ -170,11 +170,13 @@ flags: @item{@DFlag{avoid-main} --- refrain from any setup actions that affect the installation, as opposed to user-specific actions.} - @item{@DFlag{no-pkg-deps} or @Flag{K} --- refrain from checking whether dependencies among - libraries are properly reflected by package-level dependency - declarations. The check uses compiled bytecode and associated - @filepath{.dep} files, and it checks only files are setup against - only packages that include files that are setup.} + @item{@DFlag{no-pkg-deps} or @Flag{K} --- refrain from checking + whether dependencies among libraries are properly reflected by + package-level dependency declarations, whether modules are declared + by multiple packages, and whether package version dependencies are + satisfied. Dependency checking uses compiled bytecode and associated + @filepath{.dep} files, and it checks only files that are setup + against only packages that include files that are setup.} @item{@DFlag{fix-pkg-deps} --- attempt to correct dependency mismatches by adjusting package @filepath{info.rkt} files (which makes diff --git a/racket/collects/setup/private/pkg-deps.rkt b/racket/collects/setup/private/pkg-deps.rkt index 1891793136..3c3ec8c403 100644 --- a/racket/collects/setup/private/pkg-deps.rkt +++ b/racket/collects/setup/private/pkg-deps.rkt @@ -10,7 +10,8 @@ racket/file racket/path setup/dirs - setup/doc-db) + setup/doc-db + version/utils) (provide check-package-dependencies) @@ -37,6 +38,9 @@ (define pkg-implies (make-hash)) ; for checking unused (define pkg-reps (make-hash)) ; for union-find on external deps (define mod-pkg (make-hash)) + (define dup-mods (make-hash)) ; modules that are provided by multiple packages + (define pkg-version-deps (make-hash)) ; save version dependencies + (define pkg-versions (make-hash)) ; save declared versions (define path-cache (make-hash)) (define metadata-ns (make-base-namespace)) @@ -75,6 +79,25 @@ (hash-set! pkg-reps rep-a-pkg rep-b-pkg)) rep-b-pkg) + ;; ---------------------------------------- + ;; Check whether another package has already declared a module: + (define (check-module-declaration mod pkg) + (let ([already-pkg (hash-ref mod-pkg mod #f)]) + (when already-pkg + (setup-fprintf* (current-error-port) #f + (string-append + "module provided by multiple packages:\n" + " module: ~s\n" + " providing package: ~s\n" + " other providing package: ~s\n") + mod + pkg + already-pkg) + (hash-update! dup-mods mod + (lambda (ht) + (hash-set (hash-set ht pkg #t) already-pkg #t)) + #hash())))) + ;; ---------------------------------------- ;; Get a package's info, returning its deps and implies: (define (get-immediate-pkg-info! pkg) @@ -82,29 +105,39 @@ (unless dir (error 'check-dependencies "package not installed: ~s" pkg)) ;; Get package information: - (define-values (checksum mods deps+build-deps) + (define-values (checksum mods deps+build-deps+vers) (get-pkg-content (pkg-desc (if (path? dir) (path->string dir) dir) 'dir pkg #f #f) #:namespace metadata-ns #:extract-info (lambda (i) - (if (and i - (or (i 'deps (lambda () #f)) - (i 'build-deps (lambda () #f)))) - (cons - (extract-pkg-dependencies i - #:build-deps? #f - #:filter? #t) - (extract-pkg-dependencies i - #:filter? #t)) - #f)))) + (cons + (if (and i + (or (i 'deps (lambda () #f)) + (i 'build-deps (lambda () #f)))) + (cons + (extract-pkg-dependencies i + #:build-deps? #f + #:filter? #t + #:versions? #t) + (extract-pkg-dependencies i + #:filter? #t + #:versions? #t)) + #f) + (and i (i 'version (lambda () #f))))))) + (define vers (cdr deps+build-deps+vers)) + (define deps+build-deps (car deps+build-deps+vers)) (unless deps+build-deps (hash-set! skip-pkgs pkg #t) (setup-printf #f "package declares no dependencies: ~s" pkg)) - (define deps (if deps+build-deps - (filter-map package-source->name (cdr deps+build-deps)) - '())) + (define deps+vers (if deps+build-deps + (filter-map (lambda (p) + (define n (package-source->name (car p))) + (and n (cons n (cadr p)))) + (cdr deps+build-deps)) + '())) + (define deps (map car deps+vers)) (define runtime-deps (if deps+build-deps (list->set (filter-map package-source->name - (car deps+build-deps))) + (map car (car deps+build-deps)))) (set))) (define implies (list->set (let ([i (get-info/full dir #:namespace metadata-ns)]) @@ -123,19 +156,25 @@ pkg i)))) (for ([mod (in-list mods)]) + (check-module-declaration mod pkg) (hash-set! mod-pkg mod pkg)) ;; Save immediate dependencies, initialize external dependencies: (hash-set! pkg-reps pkg pkg) (hash-set! pkg-immediate-deps pkg (list (set-add runtime-deps pkg) - (set-add (list->set deps) + (set-add (list->set deps) pkg))) + (hash-set! pkg-version-deps pkg (for/list ([d (in-list deps+vers)] + #:when (cdr d)) + d)) (hash-set! pkg-external-deps pkg (set-add (set-intersect implies (set-add runtime-deps 'core)) pkg)) + (when vers + (hash-set! pkg-versions pkg vers)) (when check-unused? (hash-set! pkg-implies pkg implies)) (values deps implies)) @@ -402,6 +441,27 @@ ;; Treat all (direct) documentation links as 'build mode: (register-or-check-docs #t pkg path coll-main?)))) + ;; check version dependencies: + (hash-set! pkg-versions "racket" (version)) + (define bad-version-dependencies + (for*/fold ([ht #hash()]) ([(pkg deps) (in-hash pkg-version-deps)] + [d (in-list deps)]) + (define dep-pkg (car d)) + (define dep-vers (cdr d)) + (define decl-vers (hash-ref pkg-versions dep-pkg "1.0")) + (cond + [(version