Function: package-vc--unpack-1

package-vc--unpack-1 is a byte-compiled function defined in package-vc.el.gz.

Signature

(package-vc--unpack-1 PKG-DESC)

Documentation

Prepare PKG-DESC that is already checked-out.

When there's a relevant pkg-spec it is used for checkout directory. Otherwise dir slot of PKG-SPEC is used. This includes downloading missing dependencies, generating autoloads, generating a package description file (used to identify a package as a VC package later on), building documentation and marking the package as installed.

Source Code

;; Defined in /usr/src/emacs/lisp/emacs-lisp/package-vc.el.gz
(defun package-vc--unpack-1 (pkg-desc)
  "Prepare PKG-DESC that is already checked-out.
When there's a relevant pkg-spec it is used for checkout directory.
Otherwise `dir' slot of PKG-SPEC is used.  This includes downloading
missing dependencies, generating autoloads, generating a package
description file (used to identify a package as a VC package later on),
building documentation and marking the package as installed."
  (let* (;; Main package directory, under `package-user-dir'.  This is
         ;; the same `checkout-dir' when package has been installed with
         ;; `package-vc-install'.
         (pkg-dir (package-desc-dir pkg-desc))
         (pkg-spec (package-vc--desc->spec pkg-desc))
         ;; Directory where the package repository has been checked out.
         ;; This is the `dir' argument of
         ;; `package-vc-install-from-checkout'.
         (checkout-dir (package-vc--checkout-dir pkg-desc))
         ;; Directory where package's Lisp code resides.  It may be
         ;; equal to `checkout-dir' or be a subdirectory of it.
         (lisp-dir (package-vc--checkout-dir pkg-desc 'lisp-dir))
         missing)

    ;; In case the package was installed directly from source, the
    ;; dependency list wasn't know beforehand, and they might have
    ;; to be installed explicitly.
    (let ((ignored-files
           (if (plist-get pkg-spec :ignored-files)
               (mapconcat
                (lambda (ignore)
                  (wildcard-to-regexp
                   (if (string-match-p "\\`/" ignore)
                       (concat checkout-dir ignore)
                     (concat "*/" ignore))))
                (plist-get pkg-spec :ignored-files)
                "\\|")
             regexp-unmatchable))
          (deps '()))
      (dolist (file (directory-files lisp-dir t "\\.el\\'" t))
        (unless (string-match-p ignored-files file)
          (with-temp-buffer
            (insert-file-contents file)
            (when-let* ((require-lines (lm-header-multiline "package-requires")))
              (thread-last
                (mapconcat #'identity require-lines " ")
                package-read-from-string
                lm--prepare-package-dependencies
                (nconc deps)
                (setq deps))))))
      (dolist (dep deps)
        (cl-callf version-to-list (cadr dep)))
      (setf (package-desc-reqs pkg-desc) deps)
      (setf missing (package-vc-install-dependencies (delete-dups deps)))
      (setf missing (delq (assq (package-desc-name pkg-desc)
                                missing)
                          missing)))

    ;; Generate autoloads
    (let* ((name (package-desc-name pkg-desc))
           (auto-name (format "%s-autoloads.el" name)))
      (package-generate-autoloads name lisp-dir)
      ;; There are two cases when we wish to "indirect" the loading of
      ;; autoload files:
      ;;
      ;; 1. a package specification has a `:lisp-dir' entry listing
      ;; indicting that the actual Lisp code is located in a
      ;; subdirectory of the checkout,
      ;;
      ;; 2. the package has been installed using
      ;; `package-vc-install-from-checkout' and we want to load the
      ;; other directory instead -- which is outside of the checkout.
      ;; We can therefore take file inequality as a sign that we have to
      ;; set up an indirection.
      (unless (file-equal-p lisp-dir pkg-dir)
        (write-region
         (concat
          ";; Autoload indirection for package-vc -*- lexical-binding: t -*-\n\n"
          (prin1-to-string
           ;; The indirection is just a single load statement to the
           ;; actual file (we don't want to use symbolic links due to
           ;; portability reasons).  Detecting which of the two cases
           ;; mentioned above we are setting up can be done by checking
           ;; if the directory with the lisp code is a subdirectory of
           ;; the package directory.
           `(load ,(if (file-in-directory-p lisp-dir pkg-dir)
                       `(expand-file-name
                         ,(file-relative-name
                           (expand-file-name auto-name lisp-dir)
                           pkg-dir)
                         (or (and load-file-name
                                  (file-name-directory load-file-name))
                             (car load-path)))
                     (expand-file-name auto-name lisp-dir)))))
         nil (expand-file-name auto-name pkg-dir))))

    ;; Generate package file
    (let ((pkg-file (expand-file-name (package--description-file pkg-dir) pkg-dir)))
      (package-vc--generate-description-file pkg-desc pkg-file))

    ;; Process :make and :shell-command arguments before building documentation
    (when (or (eq package-vc-allow-build-commands t)
              (memq (package-desc-name pkg-desc)
                    package-vc-allow-build-commands))
      (package-vc--make pkg-spec pkg-desc))

    ;; Detect a manual
    (when (executable-find "install-info")
      (dolist (doc-file (ensure-list (plist-get pkg-spec :doc)))
        (package-vc--build-documentation pkg-desc doc-file)))

    ;; Remove any previous instance of PKG-DESC from `package-alist'
    (let ((pkgs (assq (package-desc-name pkg-desc) package-alist)))
      (when pkgs
        (setf (cdr pkgs) (seq-remove #'package-vc-p (cdr pkgs)))))

    ;; Remove all compiled files to allow for macros to be used from
    ;; source files, regardless of order of source files compilation and
    ;; load ordering.  As a side effect there are no compiled files for
    ;; source files that no longer exist.
    (dolist (elc-file (directory-files-recursively
                       lisp-dir
                       (rx string-start
                           (not ".") (zero-or-more anychar) ".elc"
                           string-end)
                       nil
                       (lambda (dir)
                         (and (file-accessible-directory-p dir)
                              (not (string-prefix-p "." dir))))))
        (delete-file elc-file))

    ;; Update package-alist.
    (let* ((new-desc (package-load-descriptor pkg-dir))
           (compile-desc (package-desc-create :name (package-desc-name new-desc)
                                              :dir lisp-dir)))
      ;; Activation has to be done before compilation, so that if we're
      ;; upgrading and macros have changed we load the new definitions
      ;; before compiling.
      (when (package-activate-1 new-desc :reload :deps)
        ;; `package-activate-1' will reload all necessary package files
        ;; as long as their stems are relative to of `pkg-dir'.  If
        ;; that's not the case (for example for packages with different
        ;; `checkout-dir' or with source files in a sub directory of
        ;; `pkg-dir'), we want to reload package files  from the
        ;; `lisp-dir' before compilation.
        (unless (file-equal-p lisp-dir pkg-dir)
          (package--reload-previously-loaded compile-desc))
        ;; `package-activate-1' will add info node as long as dir file
        ;; exists in `pkg-dir'.  We need to manually add it when
        ;; `checkout-dir' is in different location.
        (unless (file-equal-p checkout-dir pkg-dir)
          (package--add-info-node checkout-dir))
        ;; FIXME: Compilation should be done as a separate, optional, step.
        ;; E.g. for multi-package installs, we should first install all packages
        ;; and then compile them.
        (package--compile compile-desc)
        (when package-native-compile
          (package--native-compile-async compile-desc))
        ;; After compilation, load again any files loaded by
        ;; `package-activate-1', so that we use the byte-compiled
        ;; definitions.  This time we'll use `compile-desc' straight
        ;; away.
        (package--reload-previously-loaded compile-desc)))

    ;; Mark package as selected
    (let ((name (package-desc-name pkg-desc)))
      (unless (memq name package-selected-packages)
        (package--save-selected-packages
         (cons name package-selected-packages))))

    (package--quickstart-maybe-refresh)

    ;; Confirm that the installation was successful
    (let ((main-file (package-vc--main-file pkg-desc)))
      (message "VC package `%s' installed (Version %s, Revision %S).%s"
               (package-desc-name pkg-desc)
               (lm-with-file main-file
                 (package-strip-rcs-id
                  (or (lm-header "package-version")
                      (lm-header "version"))))
               (vc-working-revision main-file)
               (if missing
                   (format
                    " Failed to install the following dependencies: %s"
                    (mapconcat
                     (lambda (p)
                       (format "%s (%s)" (car p) (cadr p)))
                     missing ", "))
                 "")))
    t))