 (require 'package-build)
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;;; Low-level API
+;;;; Utility functions
 
 (defun straight--dir (&rest segments)
   (apply 'concat user-emacs-directory

(defun straight--file (&rest segments)
  (substring (apply 'straight--dir segments) 0 -1))

(defvar straight--cache nil)

;;;###autoload
(defun straight-load-cache ()
  (setq straight--cache
        (or (with-temp-buffer
              (insert-file-contents-literally
               (straight--file "cache.el"))

;;;###autoload
(defun straight-save-cache ()
  (with-temp-file (straight--file "cache.el")
    (pp straight--build-cache (current-buffer))))

(defmacro straight--with-build-recipe (build-recipe &rest body)
  (declare (indent 1))
  `(let* ((package (plist-get build-recipe :package))
          (repo (or (plist-get build-recipe :repo)
                    package))
          (files (plist-get build-recipe :files)))
     (unless package
       (error "build recipe %S is missing :package" build-recipe))
     ,@body))

;;;###autoload
(defun straight-package-might-be-modified-p (build-recipe)
  (straight--with-build-recipe build-recipe
    (let ((mtime (gethash package straight--build-cache)))
      (or (not mtime)
          (with-temp-buffer
            (let ((default-directory (straight--dir "repos" repo)))
              (call-process
               "find" nil '(t t) nil
               "." "-name" ".git" "-o" "-newermt" mtime "-print")
              (> (buffer-size) 0)))))))

(defun straight--symlink-package (package repo files)
  (ignore-errors
    (delete-directory
     (straight--dir "build" package)
     'recursive))
  (make-directory (straight--dir "build" package) 'parents)
  (dolist (spec (package-build-expand-file-specs
                 (straight--dir "repos" repo)
                 (package-build--config-file-list `(:files ,files))))
    (let ((repo-file (straight--file "repos" repo (car spec)))
          (build-file (straight--file "build" package (cdr spec))))
      (unless (file-exists-p repo-file)
        (error "file %S does not exist" repo-file))
      (make-directory (file-name-directory build-file) 'parents)
      (make-symbolic-link repo-file build-file))))

(defun straight--autoload-file-name (package)
  (format "%s-autoloads.el" package))

(defun straight--generate-package-autoloads (package)
  (let ((generated-autoload-file
         (straight--file
          "build" package
          (straight--autoload-file-name package)))
        ;; Silence `autoload-generate-file-autoloads'.
        (noninteractive t))
    (ignore-errors
      (delete-file generated-autoload-file))
    (update-directory-autoloads
     (straight--dir "build" package))))

(defun straight--byte-compile-package (package)
  ;; Prevent Emacs from asking the user to save all their files before
  ;; compiling.
  (cl-letf (((symbol-function #'save-some-buffers) #'ignore))
    (byte-recompile-directory
     (straight--dir "build" package)
     0 'force)))

(defun straight--update-build-mtime (package)
  (let ((mtime (format-time-string "%FT%T%z")))
    (puthash package mtime straight--build-cache)))

;;;###autoload
(defun straight-build-package (build-recipe)
  (straight--with-build-recipe build-recipe
    (straight--symlink-package package repo files)
    (straight--generate-package-autoloads package)
    (straight--byte-compile-package package)
    (straight--update-build-mtime package)))

;;;###autoload
(defun straight-add-package-to-load-path (package)
  (add-to-list 'load-path (straight--dir "build" package)))

;;;###autoload
(defun straight-install-package-autoloads (package)
  (load (straight--file "build" package (straight--autoload-file-name package))
        nil 'nomessage))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; Temporary placeholder for high-level API

;;;###autoload
(defun straight-load-package (build-recipe)
  (straight--with-build-recipe build-recipe
    (when (straight-package-might-be-modified-p build-recipe)
      (straight-build-package build-recipe))
    (straight-add-package-to-load-path package)
    (straight-install-package-autoloads package)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; Closing remarks
