forked from radian-software/straight.el
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinstall.el
234 lines (226 loc) · 11.5 KB
/
install.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
;;; install.el --- Install straight.el from scratch -*- lexical-binding: t -*-
;; Caution: this file contains copious amounts of magic. You have been
;; warned.
;; For the sake of sanity, here is the issue. We want to install
;; straight.el, but to do that we need to figure out what repository
;; to install it from. That requires parsing the recipe that the user
;; has provided, if any. But not only is that logic a part of
;; straight.el itself, but the logic changes depending on the version
;; of straight.el. It would seem to be impossible to get straight.el
;; to correctly install any version of itself, without hardcoding the
;; repository. Not so!
;;
;; We start out by making sure that a recipe version identifier is
;; saved in the version lockfiles whenever they are saved. We put the
;; version identifier in the lockfiles because if the lockfiles are
;; absent, then we are just installing the latest version of
;; straight.el anyway, so there is no need for the version identifier
;; in that case.
;;
;; Then we look for lockfiles, and determine the version identifier.
;; This is automatically translated into a branch name for
;; straight.el. The idea is that while there are lots of revisions of
;; straight.el, only a few actually change the interpretation of
;; recipe fetch keywords. And so we can actually use a rather
;; coarse-grained selection of revisions to get all the versions of
;; straight.el that we need in order to parse any given recipe format.
;;
;; After we get the appropriate branch name, we directly download that
;; branch's revision of straight.el (the file) from the official
;; GitHub repository, raxod502/straight.el. Now, one of the goals of
;; this implementation is that forking straight.el does not require
;; any changes to this file as long as you do not make divergent
;; changes to the interpretation of recipe fetch keywords. The fact
;; that we download from the source rather than whatever fork is
;; specified does not actually violate this goal, if you think about
;; it. If the fork *does* make divergent changes to recipe
;; interpretation, then all it needs to do is update the version
;; identifier in `straight-freeze-versions', tag a new branch with a
;; unique version identifier, and override the hardcoded
;; raxod502/straight.el to the fork (this last part being necessary
;; because otherwise the new branch could not be found; all previous
;; branches would still be available, though).
;;
;; After we get a copy of straight.el, it's just a matter of using it
;; to parse the recipe for straight.el itself, taking into account all
;; user-set variables. But of course evaluating straight.el will mess
;; up the environment, so we have to do this in a child Emacs
;; instance.
;;
;; Previous versions of straight.el expected a symlink for
;; bootstrap.el, in order for the bootstrap snippet to be able to
;; identify the name of the local repository for straight.el. I
;; decided later that this was more trouble than it was worth, and
;; that users wishing to rename the repository can reasonably be
;; expected to update their bootstrap snippet. We still create the
;; symlink, though, for backwards compatibility (this script should
;; work for all versions of straight.el, present and past).
;; We have to wrap everything in a single form so that this file can
;; be evaluated with `eval-print-last-sexp', rather than
;; `eval-buffer', since the latter forcibly swallows all errors(!) and
;; turns them into warnings.
(progn
(message "Bootstrapping straight.el...")
;; Any errors in this Emacs go directly to the user's init-file and
;; abort init. Errors in the child Emacs spawned below create a
;; non-zero exit code, and are re-thrown.
(let ((min-version "24.4"))
(when (version< emacs-version min-version)
(error (concat "straight.el requires at least Emacs %s, "
"but you are running Emacs %s")
min-version emacs-version)))
;; Load some libraries.
(require 'cl-lib)
(require 'url-http)
;; Because `url-http' is weird, it doesn't properly define its
;; variables. So we have to do this.
(defvar url-http-end-of-headers)
(defvar url-http-response-status)
(let (;; This needs to have a default value, just in case the user
;; doesn't have any lockfiles.
(version :jupiter)
(straight-profiles (if (boundp 'straight-profiles)
straight-profiles
'((nil . "default")))))
;; The only permissible error here is for a lockfile to be absent
;; entirely. Anything else triggers an abort so that we don't
;; accidentally do something the user doesn't expect (like if they
;; forked straight.el and made incompatible divergent changes to
;; the recipe specification, and forgot to update which repository
;; their init-file downloaded install.el from).
(dolist (lockfile-name (mapcar #'cdr straight-profiles))
(let ((lockfile-path (concat user-emacs-directory
"straight/versions/"
lockfile-name)))
(when (file-exists-p lockfile-path)
(condition-case nil
(with-temp-buffer
(insert-file-contents-literally lockfile-path)
(read (current-buffer))
(let ((alleged-version (read (current-buffer))))
(cond
(version
(unless (eq alleged-version version)
(error (concat "Incompatible recipe versions specified "
"in version lockfiles: %S and %S")
version alleged-version)))
((keywordp alleged-version)
(setq version alleged-version))
(t (error
(concat "Invalid recipe version specified "
"in version lockfile: %S")
alleged-version)))))
;; Prevent end-of-file errors from being swallowed (they
;; are ignored by default by the debugger).
(end-of-file
(error "Malformed version lockfile: %S" lockfile-name))))))
(with-current-buffer
(url-retrieve-synchronously
(format
(concat "https://raw.githubusercontent.com/"
"raxod502/straight.el/install/%s/straight.el")
(substring (symbol-name version) 1))
'silent 'inhibit-cookies)
;; In case of 404, that means the version identifier is unknown.
;; This will happen when I screw up, or if the user forks
;; straight.el and changes the version identifier, but forgets
;; to push a corresponding branch and override the repository
;; here.
(unless (equal url-http-response-status 200)
(error "Unknown recipe version: %S" version))
;; Delete the evil HTTP headers.
(delete-region (point-min) url-http-end-of-headers)
;; All of the following code is actually executed by the child
;; Emacs.
(goto-char (point-min))
(print
`(progn
;; Pass relevant variables into the child Emacs, if they
;; have been set.
,@(cl-mapcan (lambda (variable)
(when (boundp variable)
`((setq ,variable ',(symbol-value variable)))))
'(bootstrap-version
straight-arrow
straight-current-profile
straight-default-vc
straight-profiles
straight-recipe-overrides
straight-recipe-repositories
straight-recipes-gnu-elpa-url
straight-repository-branch
straight-vc-git-default-branch
straight-vc-git-default-protocol
straight-vc-git-force-protocol
straight-vc-git-primary-remote
straight-vc-git-upstream-remote
user-emacs-directory)))
(current-buffer))
(goto-char (point-max))
(print
`(progn
;; Don't worry, this recipe will be overridden by
;; `straight-recipe-overrides' if that variable has been
;; set. We're just mirroring bootstrap.el. (But note that
;; `:files' doesn't have to be specified, since we're
;; skipping the build phase.)
(straight-use-package-no-build
`(straight :type git :host github
:repo "raxod502/straight.el"
:branch ,straight-repository-branch))
(unless (and (boundp 'bootstrap-version)
(integerp bootstrap-version)
(>= bootstrap-version 3))
;; Make a bootstrap.el symlink, for backwards compatibility
;; (bootstrap snippets versioned 2 and lower expect this
;; symlink to exist).
(let* ((recipe (gethash "straight" straight--recipe-cache))
(local-repo (plist-get recipe :local-repo))
;; This is a relative symlink. It won't break if you
;; (for some silly reason) move your
;; `user-emacs-directory'.
(target (concat "repos/" local-repo "/bootstrap.el"))
(linkname (concat user-emacs-directory
"straight/bootstrap.el")))
(ignore-errors
;; If it's a directory, the linking will fail. Just let
;; the user deal with it in that case, since they are
;; doing something awfully weird.
(delete-file linkname))
;; Unfortunately, there appears to be no way to get
;; `make-symbolic-link' to overwrite an existing file,
;; like 'ln -sf'. Providing the OK-IF-ALREADY-EXISTS
;; argument just makes it fail silently in the case of an
;; existing file. That's why we have to `delete-file'
;; above.
(if straight-use-symlinks
(make-symbolic-link target linkname)
(with-temp-file linkname
(print
`(load (expand-file-name
,target (file-name-directory load-file-name))
nil 'nomessage)
(current-buffer)))))))
(current-buffer))
(let ((temp-file (make-temp-file "straight.el~")))
(write-region nil nil temp-file nil 'silent)
(with-temp-buffer
(unless (= 0
(call-process
;; Taken with love from package `restart-emacs'.
(let ((emacs-binary-path
(expand-file-name
invocation-name invocation-directory))
(runemacs-binary-path
(when (memq system-type '(windows-nt ms-dos))
(expand-file-name
"runemacs.exe" invocation-directory))))
(if (and runemacs-binary-path
(file-exists-p runemacs-binary-path))
runemacs-binary-path
emacs-binary-path))
nil '(t t) nil
"--batch" "--no-window-system" "--quick"
"--load" temp-file))
(error "straight.el bootstrap failed: %s" (buffer-string)))))))
(message "Bootstrapping straight.el...done"))