(zilch lang go): introduce proper vfs record
This should hopefully make the code a bit clearer, and is preparation for Rust support.
This commit is contained in:
parent
0c575ca0e4
commit
fc8aea8fb4
5 changed files with 228 additions and 162 deletions
|
|
@ -8,6 +8,7 @@
|
||||||
r7rs
|
r7rs
|
||||||
json
|
json
|
||||||
srfi-152
|
srfi-152
|
||||||
|
srfi-113
|
||||||
srfi-207
|
srfi-207
|
||||||
(callPackage ../../core {})
|
(callPackage ../../core {})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
(set-cdr! loc (cons (cons (go-sum-version line) (delay (vfs-from-dirhash line))) (cdr loc))))))
|
(set-cdr! loc (cons (cons (go-sum-version line) (delay (vfs-from-dirhash line))) (cdr loc))))))
|
||||||
go-sum))
|
go-sum))
|
||||||
(define (add-modules-from-sum nvfs dir)
|
(define (add-modules-from-sum nvfs dir)
|
||||||
(define sumfile (vector-get-kv-value "go.sum" (vector-get-kv-value dir nvfs)))
|
(define sumfile (vfs-file-ref nvfs dir "go.sum"))
|
||||||
(when sumfile
|
(when sumfile
|
||||||
(parse-sumfile (call-with-port (store-path-open sumfile) parse-go-sum-file))))
|
(parse-sumfile (call-with-port (store-path-open sumfile) parse-go-sum-file))))
|
||||||
|
|
||||||
|
|
@ -63,7 +63,7 @@
|
||||||
(fprintf (current-error-port) "Collecting required modules\n")
|
(fprintf (current-error-port) "Collecting required modules\n")
|
||||||
|
|
||||||
(define (find-requires-from-mod vfs dir)
|
(define (find-requires-from-mod vfs dir)
|
||||||
(define modfile (vector-get-kv-value "go.mod" (vector-get-kv-value dir vfs)))
|
(define modfile (vfs-file-ref vfs dir "go.mod"))
|
||||||
(define pathname #f)
|
(define pathname #f)
|
||||||
(when modfile
|
(when modfile
|
||||||
(let*
|
(let*
|
||||||
|
|
@ -88,8 +88,8 @@
|
||||||
pathname)
|
pathname)
|
||||||
(define root-path-name #f)
|
(define root-path-name #f)
|
||||||
(define (handle-vfs nvfs)
|
(define (handle-vfs nvfs)
|
||||||
(add-modules-from-sum nvfs "/")
|
(add-modules-from-sum nvfs "")
|
||||||
(find-requires-from-mod nvfs "/"))
|
(find-requires-from-mod nvfs ""))
|
||||||
|
|
||||||
(for-each
|
(for-each
|
||||||
(lambda (vfs)
|
(lambda (vfs)
|
||||||
|
|
@ -145,27 +145,28 @@
|
||||||
(define go-files (cdr (assoc "goFiles" pairs)))
|
(define go-files (cdr (assoc "goFiles" pairs)))
|
||||||
(define s-files (if (and (assoc "sFiles" pairs) (list? (cdr (assoc "sFiles" pairs)))) (cdr (assoc "sFiles" pairs)) '()))
|
(define s-files (if (and (assoc "sFiles" pairs) (list? (cdr (assoc "sFiles" pairs)))) (cdr (assoc "sFiles" pairs)) '()))
|
||||||
(define imports (cdr (assoc "imports" pairs)))
|
(define imports (cdr (assoc "imports" pairs)))
|
||||||
; format: ((pattern . (fname file dir)))
|
; format: ((pattern . (file-name dir file)))
|
||||||
(define embed-vectors (cdr (assoc "embeds" pairs)))
|
(define embed-vectors (cdr (assoc "embeds" pairs)))
|
||||||
(define embeds (if (vector? embed-vectors) (vector->list embed-vectors) '()))
|
(define embeds (if (vector? embed-vectors) (vector->list embed-vectors) '()))
|
||||||
(define embed-filenames '())
|
(define embed-filenames '())
|
||||||
|
|
||||||
|
; Creates a list of (pattern-text . (filename-1 filename-2 ...)).
|
||||||
(define embed-patterns (map (lambda (pattern) (cons (car pattern) (if (list? (cdr pattern)) (map car (cdr pattern)) '()))) embeds))
|
(define embed-patterns (map (lambda (pattern) (cons (car pattern) (if (list? (cdr pattern)) (map car (cdr pattern)) '()))) embeds))
|
||||||
|
|
||||||
(for-each
|
(for-each
|
||||||
(lambda (pattern)
|
(lambda (pattern)
|
||||||
(when (list? pattern)
|
(when (list? pattern)
|
||||||
(for-each
|
(for-each
|
||||||
(lambda (fname)
|
(lambda (entry)
|
||||||
(define new-fname (cadr fname))
|
(define target-file-name (list-ref entry 2))
|
||||||
(if (string=? "//" new-fname) (set! new-fname "/"))
|
(define target-directory (list-ref entry 1))
|
||||||
(define dir (vector-get-kv-value new-fname vfs))
|
(define file-obj (vfs-file-ref vfs target-directory target-file-name))
|
||||||
(define file-obj (vector-get-kv-value (car (cddr fname)) dir))
|
(unless (assoc (car entry) embed-filenames) (set! embed-filenames (cons (cons (car entry) file-obj) embed-filenames))))
|
||||||
(unless (assoc (car fname) embed-filenames) (set! embed-filenames (cons (cons (car fname) file-obj) embed-filenames))))
|
|
||||||
(cdr pattern))))
|
(cdr pattern))))
|
||||||
embeds)
|
embeds)
|
||||||
(define vfsdir (vector-get-kv-value last-part vfs))
|
|
||||||
(let
|
(let
|
||||||
((collected-files (map (lambda (name) (cons name (vector-get-kv-value name vfsdir))) go-files))
|
((collected-files (map (lambda (name) (cons name (vfs-file-ref vfs last-part name))) go-files))
|
||||||
(collected-assembly-files (map (lambda (name) (cons name (vector-get-kv-value name vfsdir))) s-files))
|
(collected-assembly-files (map (lambda (name) (cons name (vfs-file-ref vfs last-part name))) s-files))
|
||||||
(collected-assembly-includes (if (= (length s-files) 0) '() #~,(string-append #$(force headers) last-part)))
|
(collected-assembly-includes (if (= (length s-files) 0) '() #~,(string-append #$(force headers) last-part)))
|
||||||
(collected-imports (map (lambda (name) (if (is-builtin name) (go-stdlib-ref name) (find-package name)))
|
(collected-imports (map (lambda (name) (if (is-builtin name) (go-stdlib-ref name) (find-package name)))
|
||||||
(filter (lambda (name) (not (member name '("builtin" "unsafe")))) imports))))
|
(filter (lambda (name) (not (member name '("builtin" "unsafe")))) imports))))
|
||||||
|
|
@ -174,30 +175,27 @@
|
||||||
(define packages (mapping (make-default-comparator)))
|
(define packages (mapping (make-default-comparator)))
|
||||||
|
|
||||||
(define (process-packages-for-module root-path vfs)
|
(define (process-packages-for-module root-path vfs)
|
||||||
(define (dir-has-valid-contents contents)
|
(define (list-any filter entries)
|
||||||
(vector-any
|
(cond
|
||||||
(lambda (entry)
|
((eq? entries '()) #f)
|
||||||
(or
|
((filter (car entries)) #t)
|
||||||
(eq? (car entry) "go.mod")
|
(else (list-any filter (cdr entries)))))
|
||||||
(string-suffix? ".go" (car entry))))
|
|
||||||
contents))
|
|
||||||
|
|
||||||
(define module-packages
|
(define module-packages
|
||||||
(find-packages-inside-vfs
|
(find-packages-inside-vfs
|
||||||
(vector-map
|
(vfs-dir-filter-all
|
||||||
(lambda (pair)
|
(lambda (dirname)
|
||||||
(cons
|
(list-any
|
||||||
(car pair)
|
(lambda (entry)
|
||||||
(if (dir-has-valid-contents (cdr pair))
|
(or (eq? (car entry) "go.mod")
|
||||||
(cdr pair)
|
(string-suffix? ".go" (car entry))))
|
||||||
(vector-map (lambda (pair) (cons (car pair) "/dev/null")) (cdr pair)))))
|
(vfs-dir-files vfs dirname)))
|
||||||
vfs)))
|
vfs)))
|
||||||
|
|
||||||
(define headers (delay (vfs-to-store (filter-vfs vfs (lambda (dir fname) (string-suffix? ".h" fname))))))
|
(define headers (delay (vfs-to-store (vfs-dir-filter vfs (lambda (dir fname contents) (string-suffix? ".h" fname))))))
|
||||||
(vector-for-each
|
(vector-for-each
|
||||||
(lambda (pair)
|
(lambda (pair)
|
||||||
(define full-path (string-append root-path (car pair)))
|
(define full-path (string-append root-path (if (string=? (car pair) "") "" "/") (car pair)))
|
||||||
(set! full-path (string-copy full-path 0 (- (string-length full-path) 1)))
|
|
||||||
(define pairs (vector->list (cdr pair)))
|
(define pairs (vector->list (cdr pair)))
|
||||||
(set! packages (mapping-set! packages full-path (delay (process-package vfs (car pair) full-path pairs headers)))))
|
(set! packages (mapping-set! packages full-path (delay (process-package vfs (car pair) full-path pairs headers)))))
|
||||||
module-packages))
|
module-packages))
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
#~,(call-with-port
|
#~,(call-with-port
|
||||||
(open-output-bytevector)
|
(open-output-bytevector)
|
||||||
(lambda (bv)
|
(lambda (bv)
|
||||||
(json-write (vector (cons "GOARCH" (%goarch)) (cons "GOOS" "linux") (cons "files" #$(filter-vfs-for-package-reading vfs))) bv)
|
(json-write (vector (cons "GOARCH" (%goarch)) (cons "GOOS" "linux") (cons "files" #$(vfs-to-json (vfs-filter-for-go-package vfs)))) bv)
|
||||||
(get-output-bytevector bv))))
|
(get-output-bytevector bv))))
|
||||||
(define input-file (zfile input))
|
(define input-file (zfile input))
|
||||||
(define store-path (cdar (store-path-for-ca-drv* "find-packages" "x86_64-linux" #~(#$go-import-parser #$input-file) '() '("out"))))
|
(define store-path (cdar (store-path-for-ca-drv* "find-packages" "x86_64-linux" #~(#$go-import-parser #$input-file) '() '("out"))))
|
||||||
|
|
|
||||||
|
|
@ -14,13 +14,60 @@
|
||||||
(json)
|
(json)
|
||||||
(chicken base) (chicken format) (chicken foreign)
|
(chicken base) (chicken format) (chicken foreign)
|
||||||
(scheme char)
|
(scheme char)
|
||||||
(srfi 4) (srfi 128) (srfi 133) (srfi 146) (srfi 152) (srfi 207)
|
(srfi 4) (srfi 113) (srfi 128) (srfi 133) (srfi 146) (srfi 152) (srfi 207)
|
||||||
(zilch lang go) (zilch lang go core) (zilch lang go stdlib) (zilch lang go sum) (zilch lang go fetch)
|
(zilch lang go) (zilch lang go core) (zilch lang go stdlib) (zilch lang go sum) (zilch lang go fetch)
|
||||||
(chicken foreign))
|
(chicken foreign))
|
||||||
|
|
||||||
(export vfs-from-dirhash vfs-from-directory filter-vfs filter-vfs-for-package-reading vfs-to-store)
|
(export vfs? vfs-dir-files vfs-file-ref vfs-dir-filter vfs-dir-filter-all vfs-from-dirhash vfs-from-directory vfs-filter-for-go-package vfs-to-store vfs-to-json)
|
||||||
|
|
||||||
(begin
|
(begin
|
||||||
|
;; `contents` is a mapping whose keys are a pair (dir . filename) to file contents (e.g. zfile, or store path).
|
||||||
|
;; The file contents may be the symbol 'directory to indicate there's a directory.
|
||||||
|
;;
|
||||||
|
;; The root directory is specified by `dir` being an empty string. There are no trailing or leading slashes.
|
||||||
|
(define-record-type <vfs>
|
||||||
|
(make-vfs contents)
|
||||||
|
vfs?
|
||||||
|
(contents vfs-contents))
|
||||||
|
|
||||||
|
(define (vfs-dir-files vfs dir)
|
||||||
|
(mapping-map->list
|
||||||
|
(lambda (k v) (cons (cdr k) v))
|
||||||
|
(mapping-filter
|
||||||
|
(lambda (key val)
|
||||||
|
(and (not (eq? val 'directory)) (string=? (car key) dir)))
|
||||||
|
(vfs-contents vfs))))
|
||||||
|
|
||||||
|
(define (vfs-file-ref vfs dirname filename)
|
||||||
|
(mapping-ref/default (vfs-contents vfs) (cons dirname filename) #f))
|
||||||
|
|
||||||
|
;; Calls the filter with the dir, filename, and contents, for each file.
|
||||||
|
;; If filter returns #f, the file in the vfs will be replaced by /dev/null.
|
||||||
|
(define (vfs-dir-filter vfs filter)
|
||||||
|
(make-vfs
|
||||||
|
(mapping-map/monotone
|
||||||
|
(lambda (key val)
|
||||||
|
(if (or (eq? val 'directory) (filter (car key) (cdr key) val)) (values key val) (values key "/dev/null")))
|
||||||
|
(make-default-comparator)
|
||||||
|
(vfs-contents vfs))))
|
||||||
|
|
||||||
|
;; Calls the filter for each directory. If the filter returns #f, the directory's files are replaced with `/dev/null`.
|
||||||
|
(define (vfs-dir-filter-all filter vfs)
|
||||||
|
(define to-filter-out (set (make-default-comparator)))
|
||||||
|
(mapping-for-each
|
||||||
|
(lambda (key val)
|
||||||
|
(when (and (eq? val 'directory) (not (filter (string-append (car key) "/" (cdr key)))))
|
||||||
|
(set! to-filter-out (set-adjoin! to-filter-out (string-append (car key) "/" (cdr key))))))
|
||||||
|
(vfs-contents vfs))
|
||||||
|
(define (is-filtered dirname)
|
||||||
|
(set-any? (lambda (v) (string=? v dirname)) to-filter-out))
|
||||||
|
(make-vfs
|
||||||
|
(mapping-map/monotone
|
||||||
|
(lambda (key val)
|
||||||
|
(if (or (eq? val 'directory) (not (is-filtered (car key)))) (values key val) (values key "/dev/null")))
|
||||||
|
(make-default-comparator)
|
||||||
|
(vfs-contents vfs))))
|
||||||
|
|
||||||
(define (read-full-file port)
|
(define (read-full-file port)
|
||||||
(define buf (make-bytevector 2048 0))
|
(define buf (make-bytevector 2048 0))
|
||||||
(call-with-port (open-output-bytevector)
|
(call-with-port (open-output-bytevector)
|
||||||
|
|
@ -43,7 +90,7 @@
|
||||||
(map go-stdlib-ref '("archive/zip" "io" "os"))
|
(map go-stdlib-ref '("archive/zip" "io" "os"))
|
||||||
(list (cons "main.go" (zfile (foreign-value "unzip_one_source" nonnull-c-string)))))))
|
(list (cons "main.go" (zfile (foreign-value "unzip_one_source" nonnull-c-string)))))))
|
||||||
|
|
||||||
(define (rewrite-name name)
|
(define (rewrite-go-package-name-for-url name)
|
||||||
(define out "")
|
(define out "")
|
||||||
(string-for-each (lambda (ch)
|
(string-for-each (lambda (ch)
|
||||||
(if (char-upper-case? ch) (set! out (string-append out (string #\! (char-downcase ch)))) (set! out (string-append out (string ch))))) name)
|
(if (char-upper-case? ch) (set! out (string-append out (string #\! (char-downcase ch)))) (set! out (string-append out (string ch))))) name)
|
||||||
|
|
@ -53,30 +100,31 @@
|
||||||
;; returning a zdir describing the root directory.
|
;; returning a zdir describing the root directory.
|
||||||
(define (vfs-to-store vfs)
|
(define (vfs-to-store vfs)
|
||||||
(define dirmap (mapping (make-default-comparator)))
|
(define dirmap (mapping (make-default-comparator)))
|
||||||
(vector-for-each
|
(mapping-for-each
|
||||||
(lambda (pair)
|
(lambda (k contents)
|
||||||
(define key (car pair))
|
(define dir (car k))
|
||||||
(define separator (if (string=? key "/") 0 (string-index-right key (lambda (ch) (char=? ch #\/)) 0 (- (string-length key) 1))))
|
(define fname (cdr k))
|
||||||
(unless (string=? key "/")
|
(unless (eq? contents 'directory)
|
||||||
(let
|
(set! dirmap (mapping-update!/default dirmap dir (lambda (v) (cons (cons fname (zsymlink contents)) v)) '()))))
|
||||||
((dirname (string-copy key 0 (+ 1 separator)))
|
(vfs-contents vfs))
|
||||||
(fname (string-copy key (+ 1 separator) (- (string-length key) 1))))
|
(mapping-for-each
|
||||||
(set! dirmap (mapping-set! dirmap dirname (cons (cons fname key) (mapping-ref/default dirmap dirname '())))))))
|
(lambda (k contents)
|
||||||
vfs)
|
(define dir (car k))
|
||||||
(define (translate-dir name)
|
(define fname (cdr k))
|
||||||
(define files (vector-any (lambda (f) (and (string=? (car f) name) (cdr f))) vfs))
|
(when (eq? contents 'directory)
|
||||||
(define dirs (mapping-ref/default dirmap name '()))
|
(let*
|
||||||
(zdir (append
|
((name (string-append dir "/" fname))
|
||||||
(map (lambda (kv) (cons (car kv) (zsymlink (cdr kv)))) (vector->list files))
|
(dir (mapping-ref dirmap name)))
|
||||||
(map (lambda (k) (cons (car k) (translate-dir (cdr k)))) dirs))))
|
(set! dirmap (mapping-update!/default dirmap dir (lambda (v) (cons (cons fname (zdir dir)) v)) '())))))
|
||||||
(translate-dir "/"))
|
(vfs-contents vfs))
|
||||||
|
(zdir (mapping-ref/default dirmap "" '())))
|
||||||
|
|
||||||
;; Reads a dirhash from a `go.sum` line. This prefetches the module from
|
;; Reads a dirhash from a `go.sum` line. This prefetches the module from
|
||||||
;; the go module proxy, and then generates the dirhash without unpacking
|
;; the go module proxy, and then generates the dirhash without unpacking
|
||||||
;; said module file.
|
;; said module file.
|
||||||
(define (fetch-dirhash-for-sum sum-line)
|
(define (fetch-dirhash-for-sum sum-line)
|
||||||
(when (go-sum-path sum-line) (error "go.sum line is invalid for fetch-dirhash-for-sum" sum-line))
|
(when (go-sum-path sum-line) (error "go.sum line is invalid for fetch-dirhash-for-sum" sum-line))
|
||||||
(define url (string-append "https://proxy.golang.org/" (rewrite-name (go-sum-module sum-line)) "/@v/" (go-sum-version sum-line) ".zip"))
|
(define url (string-append "https://proxy.golang.org/" (rewrite-go-package-name-for-url (go-sum-module sum-line)) "/@v/" (go-sum-version sum-line) ".zip"))
|
||||||
(define known (fetch-with-known-url "module.zip" url))
|
(define known (fetch-with-known-url "module.zip" url))
|
||||||
(store-path-for-fod "module" "x86_64-linux" #~(#$dirhash-generator) #~(("src" . #$known)) "sha256" (go-sum-hash sum-line) #f))
|
(store-path-for-fod "module" "x86_64-linux" #~(#$dirhash-generator) #~(("src" . #$known)) "sha256" (go-sum-hash sum-line) #f))
|
||||||
|
|
||||||
|
|
@ -84,7 +132,7 @@
|
||||||
;; line.
|
;; line.
|
||||||
(define (vfs-from-dirhash sum-line)
|
(define (vfs-from-dirhash sum-line)
|
||||||
(define dirhash-file (fetch-dirhash-for-sum sum-line))
|
(define dirhash-file (fetch-dirhash-for-sum sum-line))
|
||||||
(define url (string-append "https://proxy.golang.org/" (rewrite-name (go-sum-module sum-line)) "/@v/" (go-sum-version sum-line) ".zip"))
|
(define url (string-append "https://proxy.golang.org/" (rewrite-go-package-name-for-url (go-sum-module sum-line)) "/@v/" (go-sum-version sum-line) ".zip"))
|
||||||
(define zip (fetch-with-known-url "module.zip" url))
|
(define zip (fetch-with-known-url "module.zip" url))
|
||||||
(define lines '())
|
(define lines '())
|
||||||
(define prefix-length (string-length (string-append (go-sum-module sum-line) "@" (go-sum-version sum-line) "/")))
|
(define prefix-length (string-length (string-append (go-sum-module sum-line) "@" (go-sum-version sum-line) "/")))
|
||||||
|
|
@ -96,62 +144,53 @@
|
||||||
(set! hash (hex-string->bytevector (string-copy line 0 64)))
|
(set! hash (hex-string->bytevector (string-copy line 0 64)))
|
||||||
(set! file (string-copy line 66))
|
(set! file (string-copy line 66))
|
||||||
(set! lines (cons (cons file hash) lines))))))
|
(set! lines (cons (cons file hash) lines))))))
|
||||||
(define dirs '())
|
(define output (mapping (make-default-comparator)))
|
||||||
(for-each
|
(for-each
|
||||||
|
; (path . hash)
|
||||||
(lambda (pair)
|
(lambda (pair)
|
||||||
(define fpath (string-copy (car pair) prefix-length))
|
(define file-path (string-copy (car pair) prefix-length))
|
||||||
(define slashindex (string-index-right fpath (lambda (c) (char=? c #\/))))
|
(define hash (cdr pair))
|
||||||
(define dirname "/")
|
|
||||||
(define filename fpath)
|
|
||||||
(when slashindex
|
|
||||||
(set! dirname (string-append "/" (string-copy fpath 0 slashindex) "/"))
|
|
||||||
(set! filename (string-copy fpath (+ slashindex 1))))
|
|
||||||
|
|
||||||
(define dir (assoc dirname dirs))
|
(define last-slash (string-index-right file-path (lambda (c) (char=? c #\/))))
|
||||||
(define file (store-path-for-fod "file" "x86_64-linux" #~(#$unpack-zip #$zip ,(car pair)) '() "sha256" (cdr pair) #f))
|
(define dirname "")
|
||||||
(unless dir
|
(define filename file-path)
|
||||||
(set! dirs (cons (list dirname) dirs))
|
(when last-slash
|
||||||
(set! dir (car dirs)))
|
(set! dirname (string-copy file-path 0 last-slash))
|
||||||
|
(set! filename (string-copy file-path (+ last-slash 1))))
|
||||||
|
|
||||||
|
; Record directory name in the parent directory.
|
||||||
|
(unless last-slash
|
||||||
|
(let ((second-to-last-slash (string-index-right dirname (lambda (c) (char=? c #\/)))))
|
||||||
|
(if second-to-last-slash
|
||||||
|
(set! output (mapping-set! output (cons (string-copy dirname 0 second-to-last-slash) (string-copy dirname (+ second-to-last-slash 1))) 'directory))
|
||||||
|
(unless (string=? dirname "") (set! output (mapping-set! output (cons "" dirname) 'directory))))))
|
||||||
|
|
||||||
|
(define file (store-path-for-fod "file" "x86_64-linux" #~(#$unpack-zip #$zip ,(car pair)) '() "sha256" hash #f))
|
||||||
|
|
||||||
; Skip files we know for sure won't be used.
|
; Skip files we know for sure won't be used.
|
||||||
|
; TODO(puck): this should be moved to vfs-filter-for-go-package?
|
||||||
(unless (or (string-contains dirname "/_") (string-contains dirname "/.") (string-contains dirname "/testdata/") (char=? #\. (string-ref filename 0)) (char=? #\_ (string-ref filename 0)))
|
(unless (or (string-contains dirname "/_") (string-contains dirname "/.") (string-contains dirname "/testdata/") (char=? #\. (string-ref filename 0)) (char=? #\_ (string-ref filename 0)))
|
||||||
(set-cdr! dir (cons (cons filename file) (cdr dir)))))
|
(set! output (mapping-set! output (cons dirname filename) file))))
|
||||||
lines)
|
lines)
|
||||||
(list->vector (map (lambda (pair) (cons (car pair) (list->vector (cdr pair)))) dirs)))
|
(make-vfs output))
|
||||||
|
|
||||||
;; Generates a full VFS structure from an on-disk directory.
|
;; Generates a full VFS structure from an on-disk directory.
|
||||||
(define (vfs-from-directory osdir)
|
(define (vfs-from-directory osdir)
|
||||||
(define iter-dir #f)
|
(define out (mapping (make-default-comparator)))
|
||||||
(define output '())
|
(define (iter-dir dirpath)
|
||||||
(set! iter-dir
|
|
||||||
(lambda (dirpath)
|
|
||||||
(define reldir (string-append osdir "/" dirpath))
|
(define reldir (string-append osdir "/" dirpath))
|
||||||
(define files '())
|
(define contents (directory reldir))
|
||||||
(define contents (directory (string-append osdir dirpath)))
|
|
||||||
(for-each
|
(for-each
|
||||||
(lambda (name)
|
(lambda (name)
|
||||||
(unless (string=? (string-copy name 0 1) ".")
|
(unless (string=? (string-copy name 0 1) ".")
|
||||||
(if (directory-exists? (string-append reldir "/" name))
|
(if (directory-exists? (string-append reldir "/" name))
|
||||||
(iter-dir (string-append dirpath "/" name))
|
(begin
|
||||||
(set! files (cons (cons name (zfile #~,(call-with-input-file (string-append reldir "/" name) read-full-file))) files)))))
|
(iter-dir (if (string=? dirpath "") name (string-append dirpath "/" name)))
|
||||||
contents)
|
(set! out (mapping-set! out (cons dirpath name) 'directory)))
|
||||||
(set! output (cons (cons (string-append dirpath "/") (list->vector files)) output))))
|
(set! out (mapping-set! out (cons dirpath name) (zfile #~,(call-with-input-file (string-append reldir "/" name) read-full-file)))))))
|
||||||
|
contents))
|
||||||
(iter-dir "")
|
(iter-dir "")
|
||||||
(list->vector output))
|
(make-vfs out))
|
||||||
|
|
||||||
;; Calls `filter` for each file in the virtual filesystem, replacing its
|
|
||||||
;; contents with an empty file if `filter` returns false.
|
|
||||||
(define (filter-vfs vfs filter)
|
|
||||||
(vector-map
|
|
||||||
(lambda (dir)
|
|
||||||
(cons (car dir)
|
|
||||||
(vector-map
|
|
||||||
(lambda (pair)
|
|
||||||
(if (filter (car dir) (car pair))
|
|
||||||
(cons (car pair) (cdr pair))
|
|
||||||
(cons (car pair) "/dev/null")))
|
|
||||||
(cdr dir))))
|
|
||||||
vfs))
|
|
||||||
|
|
||||||
;; List extracted from go src/go/build/build.go.
|
;; List extracted from go src/go/build/build.go.
|
||||||
(define good-extensions '("go" "c" "cc" "cpp" "cxx" "m" "h" "hh" "hpp" "hxx" "f" "F" "for" "f90" "s" "S" "sx" "swig" "swigcxx" "syso"))
|
(define good-extensions '("go" "c" "cc" "cpp" "cxx" "m" "h" "hh" "hpp" "hxx" "f" "F" "for" "f90" "s" "S" "sx" "swig" "swigcxx" "syso"))
|
||||||
|
|
@ -162,8 +201,13 @@
|
||||||
|
|
||||||
;; Returns a VFS, filtered down to only contain the contents of files that
|
;; Returns a VFS, filtered down to only contain the contents of files that
|
||||||
;; will be read during the processing of Go packages.
|
;; will be read during the processing of Go packages.
|
||||||
(define (filter-vfs-for-package-reading vfs)
|
(define (vfs-filter-for-go-package vfs)
|
||||||
(filter-vfs vfs
|
(vfs-dir-filter vfs
|
||||||
(lambda (dir fname)
|
(lambda (dir fname contents)
|
||||||
(define extension (extract-extension fname (- (string-length fname) 1)))
|
(define extension (extract-extension fname (- (string-length fname) 1)))
|
||||||
(member extension good-extensions))))))
|
(member extension good-extensions))))
|
||||||
|
|
||||||
|
(define (vfs-to-json vfs)
|
||||||
|
(mapping-map->list
|
||||||
|
(lambda (k v) (list (car k) (cdr k) (if (eq? v 'directory) "" v)))
|
||||||
|
(vfs-contents vfs)))))
|
||||||
|
|
|
||||||
|
|
@ -52,8 +52,8 @@ func (s *DirStat) Sys() any {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Input struct {
|
type Input struct {
|
||||||
// directory -> filename -> path
|
// list of [directory, filename, target path] (target path is empty, if directory marker)
|
||||||
Files map[string]map[string]string `json:"files"`
|
Files [][3]string `json:"files"`
|
||||||
GOARCH string `json:"GOARCH"`
|
GOARCH string `json:"GOARCH"`
|
||||||
GOOS string `json:"GOOS"`
|
GOOS string `json:"GOOS"`
|
||||||
}
|
}
|
||||||
|
|
@ -66,6 +66,11 @@ type Output struct {
|
||||||
Embeds map[string][][]string `json:"embeds"`
|
Embeds map[string][][]string `json:"embeds"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FileOrDir struct {
|
||||||
|
Directory []string
|
||||||
|
File string
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
inputFile, err := os.Open(os.Args[1])
|
inputFile, err := os.Open(os.Args[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -77,6 +82,37 @@ func main() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
files := make(map[string]*FileOrDir)
|
||||||
|
for _, file := range input.Files {
|
||||||
|
directory := file[0]
|
||||||
|
filename := file[1]
|
||||||
|
contents := file[2]
|
||||||
|
|
||||||
|
dirslash := directory
|
||||||
|
|
||||||
|
if directory != "" {
|
||||||
|
dirslash = directory + "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
if contents == "" {
|
||||||
|
_, ok := files[dirslash+filename]
|
||||||
|
if !ok {
|
||||||
|
files[dirslash+filename] = &FileOrDir{}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
files[dirslash+filename] = &FileOrDir{File: contents}
|
||||||
|
}
|
||||||
|
|
||||||
|
parent, ok := files[directory]
|
||||||
|
if !ok {
|
||||||
|
parent = &FileOrDir{}
|
||||||
|
files[directory] = parent
|
||||||
|
}
|
||||||
|
|
||||||
|
parent.Directory = append(parent.Directory, dirslash+filename)
|
||||||
|
}
|
||||||
|
|
||||||
ctx := build.Context{
|
ctx := build.Context{
|
||||||
GOARCH: input.GOARCH,
|
GOARCH: input.GOARCH,
|
||||||
GOOS: input.GOOS,
|
GOOS: input.GOOS,
|
||||||
|
|
@ -89,40 +125,26 @@ func main() {
|
||||||
return nil, fs.ErrNotExist
|
return nil, fs.ErrNotExist
|
||||||
}
|
}
|
||||||
|
|
||||||
dir = path.Clean(dir[5:])
|
dir = path.Clean(dir[5:])[1:]
|
||||||
if dir == "." {
|
|
||||||
dir = "/"
|
|
||||||
}
|
|
||||||
|
|
||||||
if !strings.HasSuffix(dir, "/") {
|
contents, ok := files[dir]
|
||||||
dir += "/"
|
|
||||||
}
|
|
||||||
|
|
||||||
dircontents, ok := input.Files[dir]
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fs.ErrNotExist
|
return nil, fs.ErrNotExist
|
||||||
}
|
}
|
||||||
|
|
||||||
infos := make([]fs.FileInfo, len(dircontents))
|
infos := make([]fs.FileInfo, len(contents.Directory))
|
||||||
i := 0
|
for i, filename := range contents.Directory {
|
||||||
for name, file := range dircontents {
|
file := files[filename]
|
||||||
stat, err := os.Stat(file)
|
if file.File != "" {
|
||||||
|
stat, err := os.Stat(file.File)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
infos[i] = &WrappedStat{FileInfo: stat, newName: name}
|
infos[i] = &WrappedStat{FileInfo: stat, newName: path.Base(filename)}
|
||||||
i = i + 1
|
} else {
|
||||||
}
|
infos[i] = &DirStat{path.Base(filename)}
|
||||||
|
|
||||||
for key := range input.Files {
|
|
||||||
if path.Dir(key) == dir {
|
|
||||||
base := path.Base(key)
|
|
||||||
if strings.HasPrefix(base, ".") || strings.HasPrefix(base, "_") || base == "testdata" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
infos = append(infos, &DirStat{base})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -136,16 +158,13 @@ func main() {
|
||||||
return nil, fs.ErrNotExist
|
return nil, fs.ErrNotExist
|
||||||
}
|
}
|
||||||
|
|
||||||
pth = path.Clean(pth[5:])
|
pth = path.Clean(pth[5:])[1:]
|
||||||
dirname, fname := path.Split(pth)
|
fmt.Printf("-> OpenFile(%q)\n", pth)
|
||||||
if dirname == "." {
|
fil := files[pth]
|
||||||
dirname = "/"
|
|
||||||
}
|
|
||||||
dir := input.Files[dirname]
|
|
||||||
|
|
||||||
data, err := os.Open(dir[fname])
|
data, err := os.Open(fil.File)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return data, fmt.Errorf("OpenFile(%q; %q[%q]; %q): %w", opth, dirname, fname, dir[fname], err)
|
return data, fmt.Errorf("OpenFile(%q; %q): %w", opth, pth, err)
|
||||||
}
|
}
|
||||||
return data, err
|
return data, err
|
||||||
},
|
},
|
||||||
|
|
@ -156,18 +175,11 @@ func main() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
dir = path.Clean(dir[5:])
|
dir = path.Clean(dir[5:])[1:]
|
||||||
if dir == "." {
|
|
||||||
dir = "/"
|
|
||||||
}
|
|
||||||
|
|
||||||
if !strings.HasSuffix(dir, "/") {
|
contents, ok := files[dir]
|
||||||
dir += "/"
|
fmt.Printf("IsDir -> %q, %v, %v\n", dir, contents, ok)
|
||||||
}
|
return ok && contents.File == ""
|
||||||
|
|
||||||
_, ok := input.Files[dir]
|
|
||||||
fmt.Printf("IsDir -> %q, %v\n", dir, ok)
|
|
||||||
return ok
|
|
||||||
},
|
},
|
||||||
|
|
||||||
HasSubdir: func(root, dir string) (rel string, ok bool) {
|
HasSubdir: func(root, dir string) (rel string, ok bool) {
|
||||||
|
|
@ -179,17 +191,21 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var filenames []string
|
var filenames []string
|
||||||
for dirname, files := range input.Files {
|
for _, filedata := range input.Files {
|
||||||
for filename := range files {
|
if filedata[2] != "" {
|
||||||
filenames = append(filenames, filepath.Join(dirname, filename))
|
filenames = append(filenames, filepath.Join(filedata[0], filedata[1]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
files := make(map[string]Output)
|
outfiles := make(map[string]Output)
|
||||||
|
|
||||||
|
for dir, filelist := range files {
|
||||||
|
if filelist.File != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
for dir, filelist := range input.Files {
|
|
||||||
isGo := false
|
isGo := false
|
||||||
for file := range filelist {
|
for _, file := range filelist.Directory {
|
||||||
if strings.HasSuffix(file, ".go") {
|
if strings.HasSuffix(file, ".go") {
|
||||||
isGo = true
|
isGo = true
|
||||||
break
|
break
|
||||||
|
|
@ -203,13 +219,16 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
base := path.Base(dir)
|
base := path.Base(dir)
|
||||||
|
if base == "." {
|
||||||
|
base = ""
|
||||||
|
}
|
||||||
|
|
||||||
if !isGo || strings.HasPrefix(base, "_") || strings.HasPrefix(base, ".") || base == "testdata" {
|
if !isGo || strings.HasPrefix(base, "_") || strings.HasPrefix(base, ".") || base == "testdata" {
|
||||||
fmt.Printf(" skipping (not go)\n")
|
fmt.Printf(" skipping (not go)\n")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
pkg, err := ctx.Import(".", path.Clean("/code"+dir), 0)
|
pkg, err := ctx.Import(".", path.Clean("/code/"+dir), 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if _, ok := err.(*build.NoGoError); ok {
|
if _, ok := err.(*build.NoGoError); ok {
|
||||||
continue
|
continue
|
||||||
|
|
@ -267,13 +286,17 @@ func main() {
|
||||||
sort.Strings(matchedFiles)
|
sort.Strings(matchedFiles)
|
||||||
var split [][]string
|
var split [][]string
|
||||||
for _, match := range matchedFiles {
|
for _, match := range matchedFiles {
|
||||||
split = append(split, []string{match[len(dir):], filepath.Dir(match) + "/", filepath.Base(match)})
|
dirname := filepath.Dir(match)
|
||||||
|
if dirname == "." {
|
||||||
|
dirname = ""
|
||||||
|
}
|
||||||
|
split = append(split, []string{match[len(dir)+1:], dirname, filepath.Base(match)})
|
||||||
}
|
}
|
||||||
|
|
||||||
out.Embeds[pattern] = split
|
out.Embeds[pattern] = split
|
||||||
}
|
}
|
||||||
|
|
||||||
files[dir] = out
|
outfiles[dir] = out
|
||||||
}
|
}
|
||||||
|
|
||||||
out, err := os.OpenFile(os.Getenv("out"), os.O_CREATE|os.O_RDWR, 0666)
|
out, err := os.OpenFile(os.Getenv("out"), os.O_CREATE|os.O_RDWR, 0666)
|
||||||
|
|
@ -281,7 +304,7 @@ func main() {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := json.NewEncoder(out).Encode(files); err != nil {
|
if err := json.NewEncoder(out).Encode(outfiles); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue