- incorporated the rest of Martin's changes: the library can now be

used to install programs (although the internals still have to be
  cleaned, and the new features documented),
This commit is contained in:
michel-schinz 2004-05-16 14:33:12 +00:00
parent 3eee4ba1a8
commit 2b825f6d36
1 changed files with 173 additions and 42 deletions

View File

@ -1,5 +1,5 @@
;;; Installation library for scsh modules. ;;; Installation library for scsh modules.
;;; $Id: install-lib.scm,v 1.16 2004/05/12 18:39:04 michel-schinz Exp $ ;;; $Id: install-lib.scm,v 1.17 2004/05/16 14:33:12 michel-schinz Exp $
;; TODO ;; TODO
;; - think about --build: does it make sense? ;; - think about --build: does it make sense?
@ -302,7 +302,7 @@
;; Names of all non-shared (i.e. platform-dependent) locations. ;; Names of all non-shared (i.e. platform-dependent) locations.
(define non-shared-locations (define non-shared-locations
'(lib)) '(lib bin))
;; All locations defined for a layout. ;; All locations defined for a layout.
(define all-locations (append shared-locations non-shared-locations)) (define all-locations (append shared-locations non-shared-locations))
@ -378,26 +378,38 @@
(define (fhs-layout pkg) (define (fhs-layout pkg)
(let* ((scsh-version-dir (string-append "scsh-" scsh-version-string)) (let* ((scsh-version-dir (string-append "scsh-" scsh-version-string))
(base (absolute-file-name (package-full-name pkg) (base (paths->file-name "share"
(paths->file-name "share" scsh-version-dir
scsh-version-dir "modules"
"modules")))) (package-full-name pkg))))
`((base . ,base) `((base . ,base)
(misc-shared . ,base) (misc-shared . ,base)
(scheme . ,(absolute-file-name "scheme" base)) (scheme . ,(absolute-file-name "scheme" base))
(lib . ,(absolute-file-name (package-full-name pkg) (lib . ,(paths->file-name "lib"
(paths->file-name scsh-version-dir
"lib" scsh-version-dir "modules"))) "modules"
(doc . ,(absolute-file-name (package-full-name pkg) (package-full-name pkg)))
(paths->file-name (doc . ,(paths->file-name "share"
"share" "doc" scsh-version-dir))) "doc"
(active . ,(paths->file-name scsh-version-dir
"share" scsh-version-dir "modules"))))) (package-full-name pkg)))
(active . ,(paths->file-name "share"
scsh-version-dir
"modules")))))
(define (fhs-program-layout pkg)
(let* ((pkg-share (paths->file-name "share" (package-full-name pkg))))
`((bin . "bin")
(scheme . ,(paths->file-name pkg-share "scheme"))
(doc . ,(paths->file-name "share"
"doc"
(package-full-name pkg))))))
(define predefined-layouts (define predefined-layouts
`(("scsh" . ,scsh-layout-1) `(("scsh" . ,scsh-layout-1)
("scsh-alt" . ,scsh-layout-2) ("scsh-alt" . ,scsh-layout-2)
("fhs" . ,fhs-layout))) ("fhs" . ,fhs-layout)
("fhs-program" . ,fhs-program-layout)))
;; If NAME-OR-LAYOUT refers to a predefined layout, return it. ;; If NAME-OR-LAYOUT refers to a predefined layout, return it.
;; Otherwise, if NAME-OR-LAYOUT is a valid layout definition, parse ;; Otherwise, if NAME-OR-LAYOUT is a valid layout definition, parse
@ -430,7 +442,7 @@
(alist-get ext (package-extensions pkg) #f)) (alist-get ext (package-extensions pkg) #f))
;; List of all defined packages ;; List of all defined packages
(define *packages* (make-fluid #f)) (define *packages* (make-fluid (make-cell '())))
;; Add PKG to the above list of all defined packages. ;; Add PKG to the above list of all defined packages.
(define (add-package pkg) (define (add-package pkg)
@ -446,6 +458,11 @@
(cwd) (cwd)
(lambda () body ...)))))) (lambda () body ...))))))
(define-syntax define-program
(syntax-rules ()
((define-program name version extensions body ...)
(define-package name version extensions body ...))))
;; Load (and evaluate the contents of) the file "pkg-def.scm" in the ;; Load (and evaluate the contents of) the file "pkg-def.scm" in the
;; current directory and return the packages it defines. ;; current directory and return the packages it defines.
(define (load-packages) (define (load-packages)
@ -455,25 +472,25 @@
(load-quietly package-definition-file)) (load-quietly package-definition-file))
(cell-ref (fluid *packages*))))) (cell-ref (fluid *packages*)))))
;; Like load-package but check additionally that none of the loaded ;; Check that the given package does not require a more recent version
;; packages require a more recent version of the installation library, ;; of the installation library, and fail if it is the case.
;; and fail if it is the case. (define (check-package pkg)
(and-let* ((req-lst (package-extension pkg 'install-lib-version))
(req (first req-lst))
((or (not (= (version-major req)
(version-major install-lib-version)))
(> (version-minor req)
(version-minor install-lib-version)))))
(display-error-and-exit
"package "(package-name pkg)" needs a newer "
"version of install-lib: "(version->string req)"\n"
"(installed: " (version->string install-lib-version) ")")))
;; Like load-package but additionally check loaded packages.
(define (load&check-packages) (define (load&check-packages)
(let ((pkgs (load-packages))) (and-let* ((pkgs (load-packages))
(for-each (lambda (pkg) ((for-each check-package pkgs)))
(and-let* pkgs))
((req-lst (package-extension pkg 'install-lib-version))
(req (first req-lst))
((or (not (= (version-major req)
(version-major install-lib-version)))
(> (version-minor req)
(version-minor install-lib-version)))))
(display-error-and-exit
"package "(package-name pkg)" needs a newer "
"version of install-lib: "(version->string req)"\n"
"(installed: " (version->string install-lib-version) ")")))
pkgs)
pkgs))
(define (load-package-in dir) (define (load-package-in dir)
(with-cwd dir (load-quietly package-definition-file))) (with-cwd dir (load-quietly package-definition-file)))
@ -784,7 +801,31 @@ advanced options:
END END
) )
(define program-usage #<<END
Usage: ~a [options]
options:
-h, --help display this help message, then exit
--prefix <dir> specify directory where files are installed
--layout <layout> specify layout of installation directory
(predefined: ~a)
--dry-run don't do anything, print what would have been done
--verbose print messages about what is being done
--force overwrite existing files during installation
--no-user-defaults don't read user default from ~~/.scsh-pkg-defaults.scm
advanced options:
--build <name> name of platform for which to build
--layout-from <file> load layout of installation directory from file
--layout-to <file> output layout to given file
--dest-dir <dir> specify prefix to used during installation
(to be used only during staged installations)
END
)
(define usage-descr-col 26) (define usage-descr-col 26)
(define program-usage-descr-col 26)
;; Complete the above USAGE string to include information about the ;; Complete the above USAGE string to include information about the
;; package options PKG-OPTS. ;; package options PKG-OPTS.
@ -806,9 +847,27 @@ END
pkg-opts) pkg-opts)
(set! usage (string-output-port-output usage-port)))) (set! usage (string-output-port-output usage-port))))
(define (complete-program-usage! pkg-opts)
(let ((usage-port (make-string-output-port)))
(write-string program-usage usage-port)
(write-string "\npackage-specific options:\n" usage-port)
(for-each
(lambda (pkg-opt)
(let ((option/arg (format #f "--~a ~a"
(pkg-opt-name pkg-opt)
(pkg-opt-arg-help pkg-opt))))
(format usage-port
" ~a~a~a [~a]\n"
option/arg
(spaces 2 (- program-usage-descr-col (string-length option/arg)))
(pkg-opt-help pkg-opt)
((pkg-opt-show pkg-opt) (pkg-opt-default pkg-opt)))))
pkg-opts)
(set! program-usage (string-output-port-output usage-port))))
;; Display the usage string, then all MSGS on the standard output ;; Display the usage string, then all MSGS on the standard output
;; port, then exit with an error code of 1. ;; port, then exit with an error code of 1.
(define (display-usage-and-exit . msgs) (define (display-usage-and-exit usage . msgs)
(format #t (format #t
usage usage
(car (command-line)) (car (command-line))
@ -897,7 +956,7 @@ END
alist))))) alist)))))
(list (list
(option '(#\h "help") #f #f (option '(#\h "help") #f #f
(lambda args (display-usage-and-exit))) (lambda args (display-usage-and-exit usage)))
(option '("prefix") #t #f (alist-arg-updater 'prefix)) (option '("prefix") #t #f (alist-arg-updater 'prefix))
(option '("dest-dir") #t #f (alist-arg-updater 'dest-dir)) (option '("dest-dir") #t #f (alist-arg-updater 'dest-dir))
(option '("layout") #t #f (alist-arg-updater 'layout)) (option '("layout") #t #f (alist-arg-updater 'layout))
@ -916,15 +975,42 @@ END
(option '("verbose") #f #t (alist-boolean-updater 'verbose)) (option '("verbose") #f #t (alist-boolean-updater 'verbose))
(option '("force") #f #t (alist-boolean-updater 'force))))) (option '("force") #f #t (alist-boolean-updater 'force)))))
(define program-options
(let ((alist-arg-updater (lambda (key)
(lambda (opt name arg alist)
(alist-replace key arg alist))))
(alist-boolean-updater (lambda (key)
(lambda (opt name arg alist)
(alist-replace key
(or (not arg)
(parse-boolean arg))
alist)))))
(list
(option '(#\h "help") #f #f
(lambda args (display-usage-and-exit program-usage)))
(option '("prefix") #t #f (alist-arg-updater 'prefix))
(option '("dest-dir") #t #f (alist-arg-updater 'dest-dir))
(option '("layout") #t #f (alist-arg-updater 'layout))
(option '("layout-from") #t #f
(lambda (opt name arg alist)
(alist-replace 'layout
(let ((layout (call-with-input-file arg read)))
(lambda args layout))
alist)))
(option '("layout-to") #t #f (alist-arg-updater 'layout-to))
(option '("dry-run") #f #t (alist-boolean-updater 'dry-run))
(option '("verbose") #f #t (alist-boolean-updater 'verbose))
(option '("force") #f #t (alist-boolean-updater 'force)))))
(define no-user-defaults-option "--no-user-defaults") (define no-user-defaults-option "--no-user-defaults")
(define (parse-options args options defaults) (define (parse-options usage args options defaults)
(args-fold args (args-fold args
options options
(lambda (option name . rest) (lambda (option name . rest)
(display-usage-and-exit "Unknown option "name)) (display-usage-and-exit usage "Unknown option "name))
(lambda (operand . rest) (lambda (operand . rest)
(display-usage-and-exit "Don't know what to do with " operand)) (display-usage-and-exit usage "Don't know what to do with " operand))
defaults)) defaults))
;; Return user-specific defaults. ;; Return user-specific defaults.
@ -955,6 +1041,19 @@ END
(force . #f) (force . #f)
(exclude . ,(lambda args #f)))) (exclude . ,(lambda args #f))))
(define program-options-defaults
`((prefix . "/usr/local")
(dest-dir . "/")
(layout . "fhs-program")
(layout-to . #f)
(build . ,(host))
(non-shared-only . #f)
(inactive . #t)
(dry-run . #f)
(verbose . #f)
(force . #f)
(exclude . ,(lambda args #f))))
(define (install-main cmd-line) (define (install-main cmd-line)
(let* ((packages (load&check-packages)) (let* ((packages (load&check-packages))
(all-pkg-opts (all-package-options packages))) (all-pkg-opts (all-package-options packages)))
@ -967,7 +1066,8 @@ END
(read-user-defaults)) (read-user-defaults))
options-defaults) options-defaults)
(map pkg-opt-key&default all-pkg-opts))) (map pkg-opt-key&default all-pkg-opts)))
(options-values (parse-options (delete no-user-defaults-option (options-values (parse-options usage
(delete no-user-defaults-option
(cdr cmd-line)) (cdr cmd-line))
all-opts all-opts
all-dfts)) all-dfts))
@ -990,3 +1090,34 @@ END
(display-error-and-exit "invalid layout "layout)) (display-error-and-exit "invalid layout "layout))
(install-packages packages options-values) (install-packages packages options-values)
(display-use-hint prefix resolved-layout packages))))) (display-use-hint prefix resolved-layout packages)))))
(define (install-program-main cmd-line)
(let* ((packages (cell-ref (fluid *packages*)))
(all-pkg-opts (all-package-options packages)))
(for-each check-package packages)
(if (not (null? all-pkg-opts))
(complete-program-usage! all-pkg-opts))
(let* ((all-opts (append program-options
(map pkg-opt->option all-pkg-opts)))
(all-dfts (append (alist-combine
(if (member no-user-defaults-option cmd-line)
'()
(read-user-defaults))
program-options-defaults)
(map pkg-opt-key&default all-pkg-opts)))
(options-values (parse-options program-usage
(delete no-user-defaults-option
(cdr cmd-line))
all-opts
all-dfts))
(prefix (alist-get 'prefix options-values))
(layout (alist-get 'layout options-values)))
(if (null? packages)
(display-error-and-exit
"no package to install"))
(if (not (file-name-absolute? prefix))
(display-error-and-exit "prefix must be an absolute path"))
(let ((resolved-layout (resolve-layout layout)))
(if (not resolved-layout)
(display-error-and-exit "invalid layout "layout))
(install-packages packages options-values)))))