SHA-1-based checking of doc dependencies

This commit is contained in:
Matthew Flatt 2010-04-30 16:12:57 -06:00
parent 259edc0780
commit 17c1dc1ab9
4 changed files with 100 additions and 32 deletions

View File

@ -17,7 +17,9 @@
manager-skip-file-handler manager-skip-file-handler
file-stamp-in-collection file-stamp-in-collection
file-stamp-in-paths file-stamp-in-paths
(rename-out [trace manager-trace-handler])) (rename-out [trace manager-trace-handler])
get-file-sha1
get-compiled-file-sha1)
(define manager-compile-notify-handler (make-parameter void)) (define manager-compile-notify-handler (make-parameter void))
(define trace (make-parameter void)) (define trace (make-parameter void))
@ -79,7 +81,7 @@
(or (not date) (or (not date)
(zo-date . > . date))) (zo-date . > . date)))
(cons zo-date (cons zo-date
(delay (get-compiled-sha1 mode (get-zo-path))))] (delay (get-compiled-file-sha1 (get-zo-path) mode)))]
[date [date
(cons date (cons date
(delay (get-source-sha1 (get-path))))] (delay (get-source-sha1 (get-path))))]
@ -574,3 +576,11 @@
"empty use-compiled-file-paths list: " "empty use-compiled-file-paths list: "
modes)) modes))
compilation-manager-load-handler)) compilation-manager-load-handler))
;; Exported:
(define (get-compiled-file-sha1 path)
(try-file-sha1 path (path-replace-suffix path #".dep")))
(define (get-file-sha1 path)
(get-source-sha1 path))

View File

@ -82,12 +82,13 @@ would create only @filepath{compiled/b_scm.zo} and
In addition to a bytecode file, @|mzc| creates a file In addition to a bytecode file, @|mzc| creates a file
@filepath{compiled/@nonterm{name}_@nonterm{ext}.dep} that records @filepath{compiled/@nonterm{name}_@nonterm{ext}.dep} that records
dependencies of the compiled module on other module files. Using this dependencies of the compiled module on other module files and the
dependency information, a re-compilation request via @|mzc| can source file's SHA-1 hash. Using this dependency information, a
consult both the source file's timestamp and the timestamps for the re-compilation request via @|mzc| can consult both the source file's
sources and bytecode of imported modules. Furthermore, imported timestamp/hash and the timestamps/hashes for the bytecode of imported
modules are themselves compiled as necessary, including updating the modules. Furthermore, imported modules are themselves compiled as
bytecode and dependency files for the imported modules, transitively. necessary, including updating the bytecode and dependency files for
the imported modules, transitively.
Continuing the @exec{mzc a.scm} example from the previous section, the Continuing the @exec{mzc a.scm} example from the previous section, the
@|mzc| creates @filepath{compiled/a_scm.dep}, @|mzc| creates @filepath{compiled/a_scm.dep},
@ -96,7 +97,7 @@ the same time as the @filepath{.zo} files. The
@filepath{compiled/a_scm.dep} file records the dependency of @filepath{compiled/a_scm.dep} file records the dependency of
@filepath{a.scm} on @filepath{b.scm}, @filepath{c.scm} and the @filepath{a.scm} on @filepath{b.scm}, @filepath{c.scm} and the
@schememodname[scheme] library. If the @filepath{b.scm} file is @schememodname[scheme] library. If the @filepath{b.scm} file is
modified (so that its timestamp changes), then running modified (so that its timestamp and SHA-1 hash changes), then running
@commandline{mzc a.scm} @commandline{mzc a.scm}
@ -153,7 +154,9 @@ file if
first sub-directory listed in @scheme[use-compiled-file-paths] first sub-directory listed in @scheme[use-compiled-file-paths]
(at the time that (at the time that
@scheme[make-compilation-manager-load/use-compiled-handler] @scheme[make-compilation-manager-load/use-compiled-handler]
was called)} was called), and either no @filepath{.dep} file exists or it
records a source-file SHA-1 hash that differs from the current
version and source-file SHA-1 hash;}
@item{no @filepath{.dep} file exists next to the @filepath{.zo} @item{no @filepath{.dep} file exists next to the @filepath{.zo}
file;} file;}
@ -162,19 +165,28 @@ file if
match the result of @scheme[(version)];} match the result of @scheme[(version)];}
@item{one of the files listed in the @filepath{.dep} file has a @item{one of the files listed in the @filepath{.dep} file has a
@filepath{.zo} timestamp newer than the one recorded in the @filepath{.zo} timestamp newer than the target @filepath{.zo},
@filepath{.dep} file.} and the combined hashes of the dependencies recorded in the
@filepath{.dep} file does not match the combined hash recorded
in the @filepath{.dep} file.}
]} ]}
] ]
If SHA-1 hashes override a timestamp-based decision to recompile the
file, then the target @filepath{.zo} file's timestamp is updated to
the current time.
After the handler procedure compiles a @filepath{.zo} file, it creates After the handler procedure compiles a @filepath{.zo} file, it creates
a corresponding @filepath{.dep} file that lists the current version, a corresponding @filepath{.dep} file that lists the current version
plus the @filepath{.zo} timestamp for every file that is and the identification of every file that is directly
@scheme[require]d by the module in the compiled file. Additional @scheme[require]d by the module in the compiled file. Additional
dependencies can be installed during compilation via dependencies can be installed during compilation via
@schememodname[compiler/cm-accomplice]. @schememodname[compiler/cm-accomplice]. The @filepath{.dep} file also
records the SHA-1 hash of the module's source, and it records a
combined SHA-1 hash of all of the dependencies that includes their
recursive dependencies.
The handler caches timestamps when it checks @filepath{.dep} files, The handler caches timestamps when it checks @filepath{.dep} files,
and the cache is maintained across calls to the same handler. The and the cache is maintained across calls to the same handler. The
@ -266,6 +278,21 @@ Returns the file-modification date and @scheme[delay]ed hash of
This function is intended for use with @scheme[manager-skip-file-handler].} This function is intended for use with @scheme[manager-skip-file-handler].}
@defproc[(get-file-sha1 [p path?]) (or/c string? #f)]{
Computes a SHA-1 hash for the file @racket[p]; the result is
@racket[#f] if @racket[p] cannot be opened.}
@defproc[(get-compiled-file-sha1 [p path?]) (or/c string? #f)]{
Computes a SHA-1 hash for the bytecode file @racket[p], appending any
dependency-describing hash available from a @filepath{.dep} file when
available (i.e., the suffix on @racket[p] is replaced by
@filepath{.dep} to locate dependency information). The result is
@racket[#f] if @racket[p] cannot be opened.}
@; ---------------------------------------------------------------------- @; ----------------------------------------------------------------------
@section{Compilation Manager Hook for Syntax Transformers} @section{Compilation Manager Hook for Syntax Transformers}

View File

@ -2,7 +2,7 @@
@(require scribble/bnf @(require scribble/bnf
"utils.ss") "utils.ss")
@title{@bold{Scribble}: PLT Documentation Tool} @title{@bold{Scribble}: Racket Documentation Tool}
@author["Matthew Flatt" "Eli Barzilay"] @author["Matthew Flatt" "Eli Barzilay"]

View File

@ -10,6 +10,7 @@
scheme/file scheme/file
scheme/fasl scheme/fasl
scheme/serialize scheme/serialize
compiler/cm
syntax/modread syntax/modread
scribble/base-render scribble/base-render
scribble/core scribble/core
@ -379,37 +380,60 @@
(define (make-sci-computed sci) (define (make-sci-computed sci)
(lambda () sci)) (lambda () sci))
(define (file-or-directory-modify-seconds/stamp file
stamp-time stamp-data pos
get-sha1)
(let ([t (file-or-directory-modify-seconds file #f (lambda () +inf.0))])
(cond
[(t . <= . stamp-time) stamp-time]
[(equal? (list-ref stamp-data pos) (get-sha1 file)) stamp-time]
[else t])))
(define ((get-doc-info only-dirs latex-dest auto-main? auto-user? (define ((get-doc-info only-dirs latex-dest auto-main? auto-user?
with-record-error setup-printf) with-record-error setup-printf)
doc) doc)
(let* ([info-out-file (build-path (or latex-dest (doc-dest-dir doc)) "out.sxref")] (let* ([info-out-file (build-path (or latex-dest (doc-dest-dir doc)) "out.sxref")]
[info-in-file (build-path (or latex-dest (doc-dest-dir doc)) "in.sxref")] [info-in-file (build-path (or latex-dest (doc-dest-dir doc)) "in.sxref")]
[stamp-file (build-path (or latex-dest (doc-dest-dir doc)) "stamp.sxref")]
[out-file (build-path (doc-dest-dir doc) "index.html")] [out-file (build-path (doc-dest-dir doc) "index.html")]
[src-zo (let-values ([(base name dir?) (split-path (doc-src-file doc))]) [src-zo (let-values ([(base name dir?) (split-path (doc-src-file doc))])
(build-path base "compiled" (path-add-suffix name ".zo")))] (build-path base "compiled" (path-add-suffix name ".zo")))]
[renderer (make-renderer latex-dest doc)] [renderer (make-renderer latex-dest doc)]
[can-run? (can-build? only-dirs doc)] [can-run? (can-build? only-dirs doc)]
[aux-time (max (file-or-directory-modify-seconds [stamp-time (file-or-directory-modify-seconds stamp-file #f (lambda () -inf.0))]
(build-path (collection-path "scribble") [stamp-data (with-handlers ([exn:fail:filesystem? (lambda (exn) (list "" "" ""))])
"compiled" (let ([v (call-with-input-file* stamp-file read)])
(path-add-suffix (if (and (list? v)
(if latex-dest (= 3 (length v))
"latex-render.ss" (andmap string? v))
"html-render.ss") v
".zo")) (list "" "" ""))))]
#f (lambda () -inf.0)) [renderer-path (build-path (collection-path "scribble")
(file-or-directory-modify-seconds "compiled"
(build-path (collection-path "scribble") (path-add-suffix
"scribble.css") (if latex-dest
#f (lambda () +inf.0)))] "latex-render.rkt"
"html-render.rkt")
".zo"))]
[css-path (build-path (collection-path "scribble")
"scribble.css")]
[aux-time (max (file-or-directory-modify-seconds/stamp
renderer-path
stamp-time stamp-data 1
get-compiled-file-sha1)
(file-or-directory-modify-seconds/stamp
css-path
stamp-time stamp-data 2
get-file-sha1))]
[my-time (file-or-directory-modify-seconds out-file #f (lambda () -inf.0))] [my-time (file-or-directory-modify-seconds out-file #f (lambda () -inf.0))]
[info-out-time (file-or-directory-modify-seconds info-out-file #f (lambda () #f))] [info-out-time (file-or-directory-modify-seconds info-out-file #f (lambda () #f))]
[info-in-time (file-or-directory-modify-seconds info-in-file #f (lambda () #f))] [info-in-time (file-or-directory-modify-seconds info-in-file #f (lambda () #f))]
[info-time (min (or info-out-time -inf.0) (or info-in-time -inf.0))] [info-time (min (or info-out-time -inf.0) (or info-in-time -inf.0))]
[vers (send renderer get-serialize-version)] [vers (send renderer get-serialize-version)]
[src-time (max aux-time [src-time (file-or-directory-modify-seconds/stamp
(file-or-directory-modify-seconds src-zo
src-zo #f (lambda () +inf.0)))] stamp-time stamp-data 0
get-compiled-file-sha1)]
[up-to-date? [up-to-date?
(and info-out-time (and info-out-time
info-in-time info-in-time
@ -535,6 +559,13 @@
(unless latex-dest (unless latex-dest
(render-time "xref-in" (write-in info))) (render-time "xref-in" (write-in info)))
(set-info-need-in-write?! info #f)) (set-info-need-in-write?! info #f))
(when (or (stamp-time . < . aux-time)
(stamp-time . < . src-time))
(let ([data (list (get-compiled-file-sha1 src-zo)
(get-compiled-file-sha1 renderer-path)
(get-file-sha1 css-path))])
(with-output-to-file stamp-file #:exists 'truncate/replace (lambda () (write data)))
(file-or-directory-modify-seconds stamp-file (max aux-time src-time))))
info)))) info))))
(lambda () #f)) (lambda () #f))
#f)))) #f))))