|
47 | 47 | :initform nil |
48 | 48 | :accessor installer-resources |
49 | 49 | :documentation "List of paths of resource files such as icons.") |
50 | | - (root |
51 | | - :initarg :root |
| 50 | + (jupyter-path |
| 51 | + :initarg :jupyter-path |
52 | 52 | :initform nil |
53 | | - :accessor installer-root |
54 | | - :documentation "The root directory under which the Jupyter folder is found. If nil then it will be determined automatically.") |
| 53 | + :accessor installer-jupyter-path |
| 54 | + :documentation "The Jupyter directory. If nil then it will be determined automatically.") |
| 55 | + (program-path |
| 56 | + :initarg :program-path |
| 57 | + :initform nil |
| 58 | + :accessor installer-program-path |
| 59 | + :documentation "The program directory. If nil then it will be determined automatically.") |
55 | 60 | (systems |
56 | 61 | :initarg :systems |
57 | 62 | :initform nil |
|
75 | 80 | () |
76 | 81 | (:documentation "User image installer class.")) |
77 | 82 |
|
78 | | -(defgeneric installer-path-part (instance part) |
79 | | - (:documentation "Get a specific part of an installer path. part is a keyword symbol specifying which part.")) |
80 | | - |
81 | | -(defmethod installer-path-part (instance (part (eql :prefix))) |
82 | | - "Get the directory prefix if it exists." |
83 | | - (with-slots (prefix) instance |
84 | | - (if prefix |
85 | | - (merge-pathnames |
86 | | - (uiop:relativize-pathname-directory (installer-path-part instance :root)) |
87 | | - (truename prefix)) |
88 | | - (installer-path-part instance :root)))) |
89 | | - |
90 | | -(defmethod installer-path-part ((instance system-installer) (type (eql :root))) |
91 | | - "Get the root directory for a system installation." |
92 | | - (cond |
93 | | - ((installer-root instance) |
94 | | - (installer-root instance)) |
95 | | - ((uiop:os-windows-p) ; Use %PROGRAMDATA% on Windows |
96 | | - (uiop:getenv-absolute-directory "PROGRAMDATA")) |
97 | | - ((installer-local instance) ; /usr/local/share/ |
98 | | - (make-pathname :directory '(:absolute "usr" "local" "share"))) |
99 | | - (t ; /usr/share/ |
100 | | - (make-pathname :directory '(:absolute "usr" "share"))))) |
101 | | - |
102 | | -(defmethod installer-path-part ((instance user-installer) (type (eql :root))) |
103 | | - "Get the root directory for a user installation" |
104 | | - (cond |
105 | | - ((installer-root instance) |
106 | | - (installer-root instance)) |
107 | | - ((uiop:os-macosx-p) ; use $HOME/Library/ on Mac |
108 | | - (merge-pathnames (make-pathname :directory '(:relative "Library")) |
109 | | - (uiop:getenv-pathname "HOME" :ensure-directory t))) |
110 | | - ((uiop:os-windows-p) ; Use %APPDATA% on Windows |
111 | | - (uiop:get-folder-path :appdata)) |
112 | | - (t ; Use XDG_DATA_HOME on all other platforms |
113 | | - (uiop:xdg-data-home)))) |
114 | | - |
115 | | -(defmethod installer-path-part (instance (part (eql :kernel))) |
116 | | - "Get the kernel directory." |
117 | | - (make-pathname |
118 | | - :directory |
119 | | - (list |
120 | | - :relative |
121 | | - ; Just in case HFS+ is case-sensitive |
122 | | - (if (uiop:os-macosx-p) "Jupyter" "jupyter") |
123 | | - "kernels" |
124 | | - (installer-kernel-name instance)))) |
125 | | - |
126 | | -(defmethod installer-path-part (instance (part (eql :program))) |
127 | | - "Get the program directory." |
128 | | - (make-pathname |
129 | | - :directory |
130 | | - (list |
131 | | - :relative |
132 | | - (format nil "~A-jupyter" (installer-kernel-name instance))))) |
133 | | - |
134 | | -(defmethod installer-path-part (instance (part (eql :spec))) |
135 | | - "Get the kernel spec file name." |
136 | | - (make-pathname :name "kernel" :type "json")) |
137 | | - |
138 | | -(defmethod installer-path-part (instance (part (eql :image))) |
139 | | - "Get the image file name." |
140 | | - (make-pathname :name "image" :type (when (uiop:os-windows-p) "exe"))) |
141 | | - |
142 | | -(defmethod installer-path-part (instance (part (eql :bundle))) |
143 | | - "Get the Quicklisp bundle file name." |
144 | | - (make-pathname :name "bundle" :type "lisp")) |
145 | | - |
146 | | -(defmethod installer-path-part (instance (part (eql :local-projects))) |
147 | | - "Get the local-projects directory." |
148 | | - (make-pathname |
149 | | - :directory (list :relative "local-projects"))) |
150 | | - |
151 | | -(defmethod installer-path-part (instance (part string)) |
152 | | - "If the part is a string then just return it." |
153 | | - part) |
154 | | - |
155 | | -(defmethod installer-path-part (instance (part pathname)) |
156 | | - "If the part is already a pathname then just return it." |
157 | | - part) |
158 | | - |
159 | | -(defun installer-path (instance &rest parts) |
160 | | - "Resolve each of the path parts then combine all into a single path using merge-pathnames." |
161 | | - (reduce |
162 | | - (lambda (previous part) |
163 | | - (merge-pathnames |
164 | | - (installer-path-part instance part) |
165 | | - previous)) |
166 | | - parts |
167 | | - :initial-value (make-pathname))) |
| 83 | +(defgeneric installer-path (instance name)) |
| 84 | + |
| 85 | +(defmethod installer-path (instance (name (eql :spec))) |
| 86 | + (merge-pathnames (make-pathname :name "kernel" :type "json") |
| 87 | + (installer-path instance :kernel))) |
| 88 | + |
| 89 | +(defmethod installer-path (instance (name (eql :kernel))) |
| 90 | + (merge-pathnames (make-pathname :directory (list :relative |
| 91 | + "kernels" |
| 92 | + (installer-kernel-name instance))) |
| 93 | + (installer-path instance :jupyter))) |
| 94 | + |
| 95 | +(defun add-prefix (instance path) |
| 96 | + (if (installer-prefix instance) |
| 97 | + (merge-pathnames (uiop:relativize-pathname-directory path) |
| 98 | + (truename (installer-prefix instance))) |
| 99 | + path)) |
| 100 | + |
| 101 | +(defmethod installer-path ((instance system-installer) (name (eql :root))) |
| 102 | + #+windows |
| 103 | + (uiop:getenv-absolute-directory "PROGRAMDATA") |
| 104 | + #-windows |
| 105 | + (make-pathname :directory (if (installer-local instance) |
| 106 | + '(:absolute "usr" "local" "share") |
| 107 | + '(:absolute "usr" "share")))) |
| 108 | + |
| 109 | +(defmethod installer-path ((instance user-installer) (name (eql :root))) |
| 110 | + #+darwin |
| 111 | + (merge-pathnames (make-pathname :directory '(:relative "Library")) |
| 112 | + (uiop:getenv-pathname "HOME" :ensure-directory t)) |
| 113 | + #+windows |
| 114 | + (uiop:get-folder-path :appdata) |
| 115 | + #-(or darwin windows) |
| 116 | + (uiop:xdg-data-home)) |
| 117 | + |
| 118 | +(defmethod installer-path ((instance system-installer) (name (eql :jupyter))) |
| 119 | + (add-prefix instance |
| 120 | + (or (installer-jupyter-path instance) |
| 121 | + (merge-pathnames (make-pathname :directory '(:relative "jupyter")) |
| 122 | + (installer-path instance :root))))) |
| 123 | + |
| 124 | +(defmethod installer-path ((instance user-installer) (name (eql :jupyter))) |
| 125 | + (add-prefix instance |
| 126 | + (or (installer-jupyter-path instance) |
| 127 | + (merge-pathnames (make-pathname :directory '(:relative #+darwin "Jupyter" |
| 128 | + #-darwin "jupyter")) |
| 129 | + (installer-path instance :root))))) |
| 130 | + |
| 131 | +(defmethod installer-path (instance (name (eql :program))) |
| 132 | + (add-prefix instance |
| 133 | + (or (installer-program-path instance) |
| 134 | + (merge-pathnames (make-pathname :directory (list :relative |
| 135 | + (format nil "~A-jupyter" |
| 136 | + (installer-kernel-name instance)))) |
| 137 | + (installer-path instance :root))))) |
| 138 | + |
| 139 | +(defmethod installer-path (instance (name (eql :image))) |
| 140 | + (merge-pathnames (make-pathname :name "image" :type #+windows "exe" #-windows :unspecific) |
| 141 | + (installer-path instance :program))) |
| 142 | + |
| 143 | +(defmethod installer-path (instance (name (eql :bundle))) |
| 144 | + (merge-pathnames (make-pathname :name "bundle" :type "lisp") |
| 145 | + (installer-path instance :program))) |
| 146 | + |
| 147 | +(defmethod installer-path (instance (name (eql :local-projects))) |
| 148 | + (merge-pathnames (make-pathname :directory (list :relative "local-projects")) |
| 149 | + (installer-path instance :program))) |
| 150 | + |
| 151 | +(defmethod installer-path (instance (name pathname)) |
| 152 | + name) |
168 | 153 |
|
169 | 154 | (defgeneric command-line (instance) |
170 | 155 | (:documentation "Get the command line for an installer instance.")) |
171 | 156 |
|
172 | 157 | (defmethod command-line ((instance user-image-installer)) |
173 | 158 | "Get the command for a user image installer." |
174 | | - (list |
175 | | - (namestring (installer-path instance :root :program :image)) |
176 | | - "{connection_file}")) |
| 159 | + (list (namestring (installer-path instance :image)) |
| 160 | + "{connection_file}")) |
177 | 161 |
|
178 | 162 | (defgeneric copy-component (component dest) |
179 | 163 | (:documentation "Copy a specific ASDF component to the destination.")) |
|
206 | 190 |
|
207 | 191 | (defun install-local-systems (instance) |
208 | 192 | "Install the local systems into local-projects." |
209 | | - (let ((dest (installer-path instance :prefix :program :local-projects))) |
210 | | - (format t "Installing local systems to ~A~%" dest) |
211 | | - (dolist (system-sym (installer-local-systems instance)) |
212 | | - (alexandria:when-let ((system (asdf:find-system system-sym))) |
213 | | - (copy-component system dest))))) |
| 193 | + (when (installer-local-systems instance) |
| 194 | + (let ((dest (installer-path instance :local-projects))) |
| 195 | + (format t "Installing local systems to ~A~%" dest) |
| 196 | + (ensure-directories-exist dest) |
| 197 | + (dolist (system-sym (installer-local-systems instance)) |
| 198 | + (alexandria:when-let ((system (asdf:find-system system-sym))) |
| 199 | + (copy-component system dest)))))) |
214 | 200 |
|
215 | 201 | (defun install-bundle (instance) |
216 | 202 | "Install the Quicklisp bundle." |
217 | | - (let ((dest (installer-path instance :prefix :program))) |
| 203 | + (let ((dest (installer-path instance :program))) |
218 | 204 | (format t "Installing Quicklisp bundle to ~A~%" dest) |
| 205 | + (ensure-directories-exist dest) |
219 | 206 | (funcall (fdefinition (find-symbol "BUNDLE-SYSTEMS" 'ql)) |
220 | 207 | (installer-systems instance) :to dest))) |
221 | 208 |
|
222 | 209 | (defun install-directories (instance) |
223 | 210 | "Create all needed directories." |
224 | 211 | (format t "Creating directories.~%") |
225 | | - (alexandria:when-let ((prefix (installer-prefix instance))) |
226 | | - (ensure-directories-exist prefix)) |
227 | | - (ensure-directories-exist (installer-path instance :prefix :kernel)) |
228 | | - (ensure-directories-exist (installer-path instance :prefix :program))) |
| 212 | + (alexandria:when-let ((installer-prefix (installer-prefix instance))) |
| 213 | + (ensure-directories-exist installer-prefix)) |
| 214 | + (ensure-directories-exist (installer-path instance :kernel))) |
229 | 215 |
|
230 | 216 | (defun install-spec (instance) |
231 | 217 | "Install the kernel spec file." |
232 | 218 | (with-slots (display-name language) instance |
233 | | - (let ((spec-path (installer-path instance :prefix :kernel :spec))) |
| 219 | + (let ((spec-path (installer-path instance :spec))) |
234 | 220 | (format t "Installing kernel spec file ~A~%" spec-path) |
235 | 221 | (with-open-file (stream spec-path :direction :output :if-exists :supersede) |
236 | 222 | (shasht:write-json |
|
244 | 230 | :empty-object)) |
245 | 231 | stream))))) |
246 | 232 |
|
247 | | -(defun install-resources (instance) |
| 233 | +(defun install-resources (instance &aux (kernel-path (installer-path instance :kernel))) |
248 | 234 | "Install all kernel resources." |
249 | | - (format t "Installing kernel resources to ~A.~%" (installer-path instance :prefix :kernel)) |
| 235 | + (format t "Installing kernel resources to ~A.~%" kernel-path) |
250 | 236 | (dolist (src (installer-resources instance)) |
251 | | - (alexandria:copy-file src (installer-path instance :prefix :kernel (file-namestring src))))) |
| 237 | + (alexandria:copy-file src (merge-pathnames (file-namestring src) |
| 238 | + kernel-path)))) |
252 | 239 |
|
253 | 240 | (defgeneric install (instance) |
254 | 241 | (:documentation "Install a kernel based on an installer instance.")) |
|
261 | 248 |
|
262 | 249 | (defmethod install ((instance user-image-installer)) |
263 | 250 | "Create an image for the user image based kernels." |
264 | | - (let ((prefixed-image-path (installer-path instance :prefix :program :image)) |
| 251 | + (let ((prefixed-image-path (installer-path instance :image)) |
265 | 252 | (class (installer-class instance))) |
266 | 253 | (setq uiop:*image-entry-point* |
267 | 254 | `(lambda () |
|
0 commit comments