From 08dbe763f60633dc80a89e6bfd94b28f00c3a2a8 Mon Sep 17 00:00:00 2001 From: Jen-Chieh Shen Date: Tue, 22 Aug 2023 21:52:10 -0700 Subject: [PATCH] feat(init): Add option to init from Keg-file (#182) * feat(init): Add option to init from Keg-file * Add help * Remove msg * complete --- cmds/core/init.js | 5 ++ lisp/_prepare.el | 3 +- lisp/help/init/keg | 6 ++ lisp/init/keg.el | 159 +++++++++++++++++++++++++++++++++++++ test/development/compat.el | 3 +- 5 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 lisp/help/init/keg create mode 100644 lisp/init/keg.el diff --git a/cmds/core/init.js b/cmds/core/init.js index 1e907600..56f34292 100644 --- a/cmds/core/init.js +++ b/cmds/core/init.js @@ -48,6 +48,11 @@ exports.handler = async (argv) => { , UTIL.def_flag(argv.from, '--from', argv.from) , argv.files); break; + case 'keg': + await UTIL.e_call(argv, 'init/keg' + , UTIL.def_flag(argv.from, '--from', argv.from) + , argv.files); + break; default: console.log(`Invalid argument, from: ${argv.from}`); break; diff --git a/lisp/_prepare.el b/lisp/_prepare.el index bfec8b96..213895bd 100644 --- a/lisp/_prepare.el +++ b/lisp/_prepare.el @@ -90,7 +90,8 @@ will return `lint/checkdoc' with a dash between two subcommands." (defun eask-special-p () "Return t if the command that can be run without Eask-file existence." - (member (eask-command) '("init/cask" "cat" "keywords" + (member (eask-command) '("init/cask" "init/keg" + "cat" "keywords" "generate/ignore" "generate/license"))) (defun eask-checker-p () diff --git a/lisp/help/init/keg b/lisp/help/init/keg new file mode 100644 index 00000000..032957f7 --- /dev/null +++ b/lisp/help/init/keg @@ -0,0 +1,6 @@ + +💡 Make sure you have a valid Keg-file in your directory + +💡 Or specify Keg-file explicitly, like: + + $ eask init --from=keg /path/to/Keg diff --git a/lisp/init/keg.el b/lisp/init/keg.el new file mode 100644 index 00000000..22cb8fa3 --- /dev/null +++ b/lisp/init/keg.el @@ -0,0 +1,159 @@ +;;; init/keg.el --- Initialize Eask from Keg -*- lexical-binding: t; -*- + +;;; Commentary: +;; +;; Commmand use to convert Keg-file to Eask-file +;; +;; $ eask init --from keg +;; + +;;; Code: + +(let ((dir (file-name-directory (nth 1 (member "-scriptload" command-line-args))))) + (load (expand-file-name "_prepare.el" + (locate-dominating-file dir "_prepare.el")) + nil t)) + +;; Copied from `keg.el' +(defun eask--keg-file-read (path) + "Return sexp from Keg file search from `deafult-directory'. +If no found the Keg file, returns nil." + (let (sources devs packages lint-disables scripts) + (when path + (dolist (elm (read (with-temp-buffer + (insert-file-contents path) + (format "(%s)" (buffer-string))))) + (let ((op (car elm)) + (args (cdr elm))) + (cond + ((eq 'source op) + (dolist (elm args) (push elm sources))) + ((eq 'dev-dependency op) + (dolist (elm args) (push elm devs))) + ((eq 'package op) + (dolist (elm args) (push elm packages))) + ((eq 'disable-lint op) + (dolist (elm args) (push elm lint-disables))) + ((eq 'script op) + (dolist (elm args) (push elm scripts)))))) + `((sources . ,(nreverse (delete-dups sources))) + (devs . ,(nreverse (delete-dups devs))) + (packages . ,(nreverse (delete-dups packages))) + (disables . ,(nreverse (delete-dups lint-disables))) + (scripts . ,(nreverse (delete-dups scripts))))))) + +(defun eask--convert-keg (filename) + "Convert Keg FILENAME to Eask." + (let* ((filename (expand-file-name filename)) + (file (file-name-nondirectory (eask-root-del filename))) + (new-file (eask-s-replace "Keg" "Eask" file)) + (new-filename (expand-file-name new-file)) + (contents (eask--keg-file-read filename)) ; Read it! + (converted)) + (eask-with-progress + (format "Converting file `%s` to `%s`... " file new-file) + (eask-with-verbosity 'debug + (cond ((not (string-prefix-p "Keg" file)) + (eask-debug "✗ Invalid Keg filename, the file should start with `Keg`")) + ((file-exists-p new-filename) + (eask-debug "✗ The file `%s` already presented" new-file)) + (t + (with-current-buffer (find-file new-filename) + (goto-char (point-min)) + + (let* ((project-name (file-name-nondirectory (directory-file-name default-directory))) + (package-name (read-string (format "\npackage name: (%s) " project-name) nil nil project-name)) + (version (read-string "version: (1.0.0) " nil nil "1.0.0")) + (description (read-string "description: ")) + (guess-entry-point (format "%s.el" project-name)) + (entry-point (read-string (format "entry point: (%s) " guess-entry-point) + nil nil guess-entry-point)) + (emacs-version (read-string "emacs version: (26.1) " nil nil "26.1")) + (website (read-string "website: ")) + (keywords (read-string "keywords: ")) + (keywords (split-string keywords "[, ]")) + (keywords (string-join keywords "\" \"")) + (content (format + "(package \"%s\" + \"%s\" + \"%s\") + +(website-url \"%s\") +(keywords \"%s\") + +(package-file \"%s\") + +(script \"test\" \"echo \\\"Error: no test specified\\\" && exit 1\") +" + package-name version description website keywords + entry-point))) + (insert content) + + (when-let ((scripts (alist-get 'scripts contents))) + (dolist (script scripts) + (let* ((cmds (cadr script)) + (_ (pop cmds)) + (cmds (mapconcat #'identity cmds " "))) + (insert "(script \"" (eask-2str (car script)) + "\" " (prin1-to-string cmds) ")\n")))) + + (insert "\n") + + (dolist (source (alist-get 'sources contents)) + (insert "(source '" (eask-2str source) ")\n")) + + (insert "\n") + + (insert (format "(depends-on \"emacs\" \"%s\")\n" emacs-version))) + + (when-let ((pkgs (alist-get 'packages contents))) + (dolist (pkg pkgs) + (insert "(depends-on \"" (eask-2str (car pkg)) "\")\n"))) + + (insert "\n") + + (when-let ((devs (alist-get 'devs contents))) + (insert "(development\n") + (dolist (dev devs) + (insert " (depends-on \"" (eask-2str dev) "\")\n")) + (insert " )\n")) + + (save-buffer)) + (setq converted t)))) + (if converted "done ✓" "skipped ✗")) + converted)) + +(eask-start + ;; Preparation + (eask-with-archives "melpa" + (eask-package-install 'keg)) + + ;; Start Converting + (require 'keg) + (let* ((patterns (eask-args)) + (files (if patterns + (eask-expand-file-specs patterns) + (directory-files default-directory t "Keg"))) + (files (cl-remove-if-not (lambda (file) + (string= "Keg" (file-name-nondirectory file))) + files)) + (converted 0)) + (cond + ;; Files found, do the action! + (files + (dolist (file files) + (when (eask--convert-keg file) + (cl-incf converted))) + (eask-msg "") + (eask-info "(Total of %s Keg-file%s converted)" converted + (eask--sinr converted "" "s"))) + ;; Pattern defined, but no file found! + (patterns + (eask-info "(No files match wildcard: %s)" + (mapconcat #'identity patterns " "))) + ;; Default, print help! + (t + (eask-info "(No Keg-files have been converted to Eask)") + (eask-help "init/keg"))))) + +;;; init/keg.el ends here diff --git a/test/development/compat.el b/test/development/compat.el index a3c720d9..307fe3b1 100644 --- a/test/development/compat.el +++ b/test/development/compat.el @@ -27,7 +27,8 @@ package-generate-description-file locate-dominating-file directory-empty-p - url-file-exists-p) + url-file-exists-p + prin1-to-string) "List of function to check Emacs compatibility.") (message "Starting compatibility test for functions...")