Skip to content

Commit f95fd8a

Browse files
committed
Rework module installation with interactive choice and defcustom
Replace ghostel-auto-download-module with ghostel-module-auto-install which supports four modes: - 'ask (default): prompt with [d]ownload / [c]ompile / [s]kip - 'download: silently download pre-built binary from GitHub releases - 'compile: build from source via ghostel-module-compile - nil: do nothing, user installs manually The interactive prompt shows the download URL and mentions Zig as a requirement for compilation. Compile mode runs build.sh synchronously and reports results in *ghostel-build* buffer.
1 parent 72b746f commit f95fd8a

1 file changed

Lines changed: 95 additions & 50 deletions

File tree

ghostel.el

Lines changed: 95 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,16 @@
8686
"https://github.com/dakra/ghostel/releases"
8787
"Base URL for ghostel GitHub releases.")
8888

89-
(defcustom ghostel-auto-download-module nil
90-
"Automatically download a pre-built native module if missing.
91-
When non-nil, ghostel will attempt to download a pre-built module
92-
from GitHub releases on first load. When nil (the default), the
93-
user must explicitly run \\[ghostel-download-module] or build from
94-
source with ./build.sh."
95-
:type 'boolean
89+
(defcustom ghostel-module-auto-install 'ask
90+
"What to do when the native module is missing at load time.
91+
\\=`ask' — prompt with a choice to download, compile, or skip (default).
92+
\\=`download' — download a pre-built binary from GitHub releases.
93+
\\=`compile' — build from source via `ghostel-module-compile'.
94+
nil — do nothing; the user must install the module manually."
95+
:type '(choice (const :tag "Ask interactively" ask)
96+
(const :tag "Download pre-built binary" download)
97+
(const :tag "Compile from source" compile)
98+
(const :tag "Do nothing" nil))
9699
:group 'ghostel)
97100

98101
(defun ghostel--module-platform-tag ()
@@ -112,34 +115,83 @@ Returns nil if the platform is not recognized."
112115
(when tag
113116
(format "ghostel-module-%s%s" tag module-file-suffix))))
114117

115-
(defun ghostel--maybe-download-module (dir)
116-
"Try to download a pre-built module into DIR if available.
117-
Downloads from the latest GitHub release matching the current platform.
118-
Does nothing if the platform is unsupported or the download fails."
118+
(defun ghostel--module-download-url ()
119+
"Return the download URL for the current platform's pre-built module."
120+
(let ((asset-name (ghostel--module-asset-name)))
121+
(when asset-name
122+
(let ((version (ghostel--package-version)))
123+
(if version
124+
(format "%s/download/v%s/%s"
125+
ghostel-github-release-url version asset-name)
126+
(format "%s/latest/download/%s"
127+
ghostel-github-release-url asset-name))))))
128+
129+
(defun ghostel--download-module (dir)
130+
"Download a pre-built module into DIR.
131+
Returns non-nil on success."
119132
(condition-case err
120-
(let ((asset-name (ghostel--module-asset-name)))
121-
(when asset-name
122-
(let* ((version (ghostel--package-version))
123-
(url (if version
124-
(format "%s/download/v%s/%s"
125-
ghostel-github-release-url
126-
version
127-
asset-name)
128-
(format "%s/latest/download/%s"
129-
ghostel-github-release-url
130-
asset-name)))
131-
(dest (expand-file-name
132-
(concat "ghostel-module" module-file-suffix) dir)))
133-
;; Enforce HTTPS for security
134-
(unless (string-prefix-p "https://" url)
135-
(error "Refusing non-HTTPS download URL: %s" url))
133+
(let ((url (ghostel--module-download-url)))
134+
(when url
135+
(unless (string-prefix-p "https://" url)
136+
(error "Refusing non-HTTPS download URL: %s" url))
137+
(let ((dest (expand-file-name
138+
(concat "ghostel-module" module-file-suffix) dir)))
136139
(message "ghostel: downloading native module from %s..." url)
137140
(when (ghostel--download-file url dest)
138-
(message "ghostel: native module downloaded to %s" dest)))))
141+
(message "ghostel: native module downloaded successfully")
142+
t))))
139143
(error
140-
(message "ghostel: auto-download failed: %s" (error-message-string err))
144+
(message "ghostel: download failed: %s" (error-message-string err))
141145
nil)))
142146

147+
(defun ghostel--compile-module (dir)
148+
"Compile the native module from source in DIR.
149+
Runs synchronously and returns non-nil on success."
150+
(let ((default-directory dir)
151+
(script (expand-file-name "build.sh" dir)))
152+
(if (file-executable-p script)
153+
(progn
154+
(message "ghostel: compiling native module (this may take a moment)...")
155+
(let ((ret (call-process script nil "*ghostel-build*" nil)))
156+
(if (eq ret 0)
157+
(progn (message "ghostel: native module compiled successfully") t)
158+
(display-warning 'ghostel
159+
"Module compilation failed. See *ghostel-build* buffer for details.")
160+
nil)))
161+
(display-warning 'ghostel
162+
(format "build.sh not found in %s.\nClone with submodules and run ./build.sh manually." dir))
163+
nil)))
164+
165+
(defun ghostel--ensure-module (dir)
166+
"Ensure the native module exists in DIR.
167+
Behavior is controlled by `ghostel-module-auto-install'."
168+
(let ((action ghostel-module-auto-install))
169+
(when (eq action 'ask)
170+
(setq action (ghostel--ask-install-action dir)))
171+
(pcase action
172+
('download (ghostel--download-module dir))
173+
('compile (ghostel--compile-module dir))
174+
(_ nil))))
175+
176+
(defun ghostel--ask-install-action (dir)
177+
"Prompt the user to choose how to install the missing native module.
178+
DIR is the target directory. Returns \\='download, \\='compile, or nil."
179+
(let* ((url (or (ghostel--module-download-url) "GitHub releases"))
180+
(choice (read-char-choice
181+
(format "Ghostel native module not found.
182+
183+
[d] Download pre-built binary from:
184+
%s
185+
[c] Compile from source (requires Zig)
186+
[s] Skip — install manually later
187+
188+
Choice: " url)
189+
'(?d ?c ?s))))
190+
(pcase choice
191+
(?d 'download)
192+
(?c 'compile)
193+
(?s nil))))
194+
143195
(defun ghostel--package-version ()
144196
"Return ghostel package version string, or nil.
145197
Returns nil without error when `package.el' is unavailable."
@@ -166,7 +218,6 @@ Returns nil without error when `package.el' is unavailable."
166218
(start (point)))
167219
(when (< start (point-max))
168220
(write-region start (point-max) dest nil 'silent)
169-
;; Make executable on Unix
170221
(set-file-modes dest #o755)
171222
t)))))
172223
(when (buffer-live-p buf)
@@ -181,39 +232,33 @@ Returns nil without error when `package.el' is unavailable."
181232
buffer-file-name)))
182233
(mod (expand-file-name
183234
(concat "ghostel-module" module-file-suffix) dir)))
184-
(if (file-exists-p mod)
185-
(if (yes-or-no-p "Module already exists. Re-download? ")
186-
(progn
187-
(ghostel--maybe-download-module dir)
188-
(when (file-exists-p mod)
189-
(module-load mod)
190-
(message "ghostel: module loaded successfully")))
191-
(message "Cancelled."))
192-
(ghostel--maybe-download-module dir)
193-
(if (file-exists-p mod)
194-
(progn
195-
(module-load mod)
196-
(message "ghostel: module loaded successfully"))
197-
(user-error "Download failed. Run ./build.sh to build from source")))))
235+
(when (and (file-exists-p mod)
236+
(not (yes-or-no-p "Module already exists. Re-download? ")))
237+
(user-error "Cancelled"))
238+
(if (ghostel--download-module dir)
239+
(progn
240+
(module-load mod)
241+
(message "ghostel: module loaded successfully"))
242+
(user-error "Download failed. Try M-x ghostel-module-compile to build from source"))))
198243

199244
;; Load the native module
200245
(unless (featurep 'ghostel-module)
201246
(let* ((dir (file-name-directory (or load-file-name buffer-file-name)))
202247
(mod (expand-file-name
203248
(concat "ghostel-module" module-file-suffix) dir)))
204249
(unless (file-exists-p mod)
205-
(when ghostel-auto-download-module
206-
(ghostel--maybe-download-module dir)))
250+
(ghostel--ensure-module dir))
207251
(if (file-exists-p mod)
208252
(condition-case err
209253
(module-load mod)
210254
(error
211255
(display-warning 'ghostel
212-
(format "Failed to load native module: %s\nRun ./build.sh to rebuild"
256+
(format "Failed to load native module: %s\nTry M-x ghostel-module-compile to rebuild"
213257
(error-message-string err)))))
214-
(display-warning 'ghostel
215-
(concat "Native module not found: " mod
216-
"\nRun ./build.sh or M-x ghostel-download-module")))))
258+
(unless ghostel-module-auto-install
259+
(display-warning 'ghostel
260+
(concat "Native module not found: " mod
261+
"\nRun M-x ghostel-download-module or M-x ghostel-module-compile"))))))
217262

218263
;; Declare native module functions for the byte compiler
219264
(declare-function ghostel--new "ghostel-module")

0 commit comments

Comments
 (0)