My attempt to optimize my emacs load time <1 second
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

330 lines
11 KiB

  1. ;;; vlocitemacs.el --- Vlocity Build Tool :: Emacs integration
  2. ;;; Commentary:
  3. ;;
  4. ;; Essentially the following commands are abstracted into elisp and made dynamic:
  5. ;;
  6. ;; vlocity packDeploy -propertyfile build.properties -job job.yaml -key VlocityUITemplate/Test-test
  7. ;; vlocity packExport -propertyfile build.properties -job job.yaml -key VlocityUITemplate/Test-test
  8. ;;
  9. ;;
  10. ;;; Code:
  11. (require 'transient)
  12. (require 'json)
  13. (defvar vlo/project-file-name ".vemacs.txt"
  14. "The name of the VlocitEmacs configuration file.
  15. This file exists for the purpose of locating the project folder as there is no
  16. good way of knowing you are in the root vlocity project. It also contains the
  17. list of environments to be used for deployments/exports.")
  18. (defvar vlo/project-jobfile-template "projectPath: ."
  19. "Bare-bones template to use for =job.yaml=.")
  20. ;; DONE
  21. (defun vlo/generate-project-file ()
  22. "Create the project file and append it to .gitignore if file exists."
  23. (interactive)
  24. (let* ((dir (read-directory-name "Choose Project Root: "))
  25. (project-file (concat dir vlo/project-file-name))
  26. (job-file (concat dir "job.yaml"))
  27. (gitignore (concat dir ".gitignore")))
  28. ;; Create job.yaml if it doesn't exist
  29. (when (not (file-exists-p job-file))
  30. (with-temp-file job-file (insert vlo/project-jobfile-template)))
  31. ;; Create .vemacs.txt
  32. (with-temp-file project-file (insert ""))
  33. ;; Insert username into .vemacs.txt
  34. (let ((current-user (vlo/prompt-org-list)))
  35. (with-temp-file project-file (insert current-user))
  36. )
  37. ;; Add .vemacs.txt to .gitignore
  38. (when (file-exists-p gitignore)
  39. (append-to-file vlo/project-file-name nil gitignore))))
  40. ;; DONE
  41. (defun vlo/prompt-org-list ()
  42. "Get a list of authenticated orgs via SFDX cli and store the selected user in the project file."
  43. (interactive)
  44. (let* ((project-file (concat (vlo/project-path) vlo/project-file-name))
  45. (temp-json-file
  46. (make-temp-file "sfdx-org-list" nil ".json"
  47. (shell-command-to-string "sfdx force:org:list --json")))
  48. (json-object-type 'hash-table)
  49. (json-array-type 'list)
  50. (json-key-type 'string)
  51. (json (json-read-file temp-json-file))
  52. (result (gethash "result" json))
  53. (orgs (gethash "nonScratchOrgs" result))
  54. (usernames '())
  55. )
  56. (dolist (org orgs)
  57. (add-to-list 'usernames (gethash "username" org)))
  58. (let ((current-user (completing-read "SFDX user: " usernames)))
  59. (with-temp-file project-file current-user)
  60. current-user)))
  61. ;; DONE
  62. (defun vlo/in-vlocity-project ()
  63. "Check if you are currently inside a vlocity project."
  64. (if (vlo/project-path)
  65. t
  66. nil))
  67. ;; DONE
  68. (defun vlo/project-path ()
  69. "Return path to the project file, or nil.
  70. If project file exists in the current working directory, or a
  71. parent directory recursively, return its path. Otherwise, return
  72. nil."
  73. (locate-dominating-file default-directory vlo/project-file-name))
  74. ;; DONE
  75. (defun vlo/get-project-user ()
  76. "Return the user stored in the project file."
  77. (if (vlo/in-vlocity-project)
  78. (let ((project-dir (concat (vlo/project-path) vlo/project-file-name)))
  79. (with-temp-buffer (insert-file-contents project-dir) (buffer-string)))
  80. nil))
  81. ;; DONE
  82. (defun vlo/get-jobfile-name ()
  83. "The name of the job.yaml file."
  84. "job.yaml")
  85. ;; DONE
  86. (defun vlo/get-deployment-key ()
  87. "Return the Name of the component dynamically from the =_DataPpack.json= file."
  88. (let ((datapack-file (expand-file-name (concat (file-name-base) "_DataPack.json"))))
  89. (if (file-exists-p datapack-file)
  90. (let* ((json-object-type 'hash-table)
  91. (json-array-type 'list)
  92. (json-key-type 'string)
  93. (json (json-read-file datapack-file))
  94. (component-name (gethash "Name" json)))
  95. (concat "VlocityUITemplate/" component-name))
  96. nil)))
  97. ;; DONE
  98. (defun vlo/exec-process (cmd name &optional comint)
  99. "Execute a process running CMD and use NAME to generate a unique buffer name and optionally pass COMINT as t to put buffer in `comint-mode'."
  100. (let ((compilation-buffer-name-function
  101. (lambda (mode)
  102. (format "*%s*" name))))
  103. (message (concat "Running " cmd))
  104. (compile cmd comint)))
  105. ;; DONE
  106. (defun vlo/packExport (username job &optional key)
  107. "Run the packExport command with sfdx USERNAME or alias using the JOB file.
  108. Optionally specifying KEY to export. If KEY is nil, this command will run
  109. packExport using job.yaml provided (i.e. export all)."
  110. (if (and (vlo/in-vlocity-project)
  111. (file-exists-p (concat (vlo/project-path) job)))
  112. (let ((cmd
  113. (if key
  114. (format "cd %s; vlocity packExport -sfdx.username %s -job %s -key %s"
  115. (vlo/project-path)
  116. username
  117. job
  118. key)
  119. (format "cd %s; vlocity packExport -sfdx.username %s -job %s"
  120. (vlo/project-path)
  121. username
  122. job)
  123. )))
  124. (vlo/exec-process cmd "vlocity:retrieve" t))
  125. (message "ERROR Exporting:: project: %s, user: %s, job: %s, key: %s"
  126. (vlo/project-path)
  127. username
  128. job
  129. key)))
  130. ;; DONE
  131. (defun vlo/packDeploy (username job &optional key)
  132. "Run the packDeploy command with sfdx USERNAME or alias using the JOB file.
  133. Optionally specifying KEY to export. If KEY is nil, this command will run
  134. packDeploy using job.yaml provided (i.e. deploy all)."
  135. (if (and (vlo/in-vlocity-project)
  136. (file-exists-p (concat (vlo/project-path) job)))
  137. (let ((cmd
  138. (if key
  139. (format "cd %s; vlocity packDeploy -sfdx.username %s -job %s -key %s"
  140. (vlo/project-path)
  141. username
  142. job
  143. key)
  144. (format "cd %s; vlocity packDeploy -sfdx.username %s -job %s"
  145. (vlo/project-path)
  146. username
  147. job)
  148. )))
  149. (vlo/exec-process cmd "vlocity:retrieve" t))
  150. (message "ERROR Deploying:: project: %s, user: %s, job: %s, key: %s"
  151. (vlo/project-path)
  152. username
  153. job
  154. key)))
  155. (defun vlo/prompt-tabulated-list (&optional result)
  156. "A wrapper function to `vlocitemacs' from async call which passes a RESULT."
  157. (vlocitemacs))
  158. ;; FIXME :: This isn't triggering `vlocitemacs' as it should after building the list.
  159. (defun vlo/get-available-exports (username job)
  160. "Run the packGetAllAvailableExports command with USERNAME and JOB file.
  161. Returns a list into VlocityBuildLog.yaml. Upon completing the async process
  162. `vlocitemacs' is run."
  163. (if (and (vlo/in-vlocity-project)
  164. (file-exists-p (concat (vlo/project-path) job)))
  165. ;; this following 'if' is essentially a cache
  166. (if (not (string= (shell-command-to-string (format "cat %sVlocityBuildLog.yaml | grep 'manifest'" (vlo/project-path))) ""))
  167. (vlocitemacs)
  168. (progn
  169. (message "Generating list...")
  170. (async-start-process "vlocity:getlist" "sh" (lambda (res) (vlocitemacs)) "-c" (format "cd %s; vlocity packGetAllAvailableExports -sfdx.username %s -job %s -type VlocityUITemplate; exit" (vlo/project-path) username job))))
  171. (message "Cannot get available exports!")))
  172. (defun vlo/createDatapack ()
  173. "Description."
  174. (interactive)
  175. (message "TODO :: Creating..."))
  176. ;; DONE
  177. (defun vlo/search ()
  178. "Description."
  179. (interactive)
  180. (vlo/get-available-exports (vlo/get-project-user) (vlo/get-jobfile-name)))
  181. ;; DONE
  182. (defun vlo/exportThisAction ()
  183. "Destructively retrieve this component."
  184. (interactive)
  185. (let ((key (vlo/get-deployment-key)))
  186. (if (yes-or-no-p (format "Retrieve \"%s\"? (THIS WILL OVERWRITE LOCAL CHANGES!) " key))
  187. (progn
  188. (message "Retrieving \"%s\"..." key)
  189. (vlo/packExport (vlo/get-project-user) (vlo/get-jobfile-name) key))
  190. (message "Cancelled Retrieve"))))
  191. ;; DONE
  192. (defun vlo/exportAllAction ()
  193. "Description."
  194. (interactive)
  195. (if (yes-or-no-p "Retrieve ALL DataPacks in Manifest? (THIS WILL OVERWRITE LOCAL CHANGES!) ")
  196. (progn
  197. (message "Retrieving ALL DataPacks in Manifest file...")
  198. (vlo/packExport (vlo/get-project-user) (vlo/get-jobfile-name)))
  199. (message "Cancelled Retrieve")))
  200. ;; DONE
  201. (defun vlo/deployThisAction ()
  202. "Description."
  203. (interactive)
  204. (let ((key (vlo/get-deployment-key)))
  205. (if key
  206. (progn
  207. (vlo/packDeploy (vlo/get-project-user) (vlo/get-jobfile-name) key)
  208. (message "Deploying \"%s\"..." key))
  209. (message "No DataPack file found for this component!"))))
  210. ;; DONE
  211. (defun vlo/deployAllAction ()
  212. "Description."
  213. (interactive)
  214. (if (yes-or-no-p "Are you sure you wish to deploy everything? ")
  215. (vlo/packDeploy (vlo/get-project-user) (vlo/get-jobfile-name))
  216. (message "Cancelled")))
  217. ;; TODO : could check if file is installed locally and then either prompt to overwrite or goto item
  218. (defun vlo/get-item-at-point (&optional arg)
  219. "Get the DataPack under cursor ARG."
  220. (interactive "P")
  221. (let ((item (aref (tabulated-list-get-entry) 0)))
  222. (message "Item Selected: %s and arg %s" item arg)
  223. (vlo/packExport (vlo/get-project-user) (vlo/get-jobfile-name) (concat "VlocityUITemplate/" item))))
  224. ;; DONE
  225. (defvar vlocitemacs-mode-map
  226. (let ((map (make-sparse-keymap)))
  227. (define-key map (kbd "RET") 'vlo/get-item-at-point)
  228. map)
  229. "Keymap for `vlocitemacs-mode'.")
  230. ;; DONE
  231. (define-derived-mode vlocitemacs-mode tabulated-list-mode "VlocitEmacs"
  232. "A custom mode for interacting with the Vlocity Build Tool CLI."
  233. (let (
  234. (columns [("Choose DataPack" 100)])
  235. (rows (mapcar (lambda(x) `(nil [,x]))
  236. (split-string (shell-command-to-string (format "cat %sVlocityBuildLog.yaml | grep ' - ' | sed 's/ - VlocityUITemplate\\///'" (vlo/project-path)))))))
  237. (buffer-disable-undo)
  238. (kill-all-local-variables)
  239. (setq truncate-lines t)
  240. (setq mode-name "VlocitEmacs")
  241. (setq major-mode 'vlocitemacs-mode)
  242. (setq tabulated-list-format columns)
  243. (setq tabulated-list-entries rows)
  244. (use-local-map vlocitemacs-mode-map)
  245. (tabulated-list-init-header)
  246. (tabulated-list-print)
  247. (run-mode-hooks 'vlocitemacs-mode-hook)))
  248. ;; DONE
  249. (defun vlocitemacs ()
  250. "Invoke the VlocitEmacs buffer."
  251. (interactive)
  252. (switch-to-buffer "*vlocitemacs*")
  253. (vlocitemacs-mode))
  254. ;; DONE
  255. (defun vlo/transient-action ()
  256. "Dynamically choose which transient to show based on if currently in a project."
  257. (interactive)
  258. (if (vlo/in-vlocity-project)
  259. (vlo/transient-project-action)
  260. (vlo/transient-init-action)))
  261. (define-transient-command vlo/transient-init-action ()
  262. "Vlocity Build Tool CLI Actions"
  263. ["Vlocity Project file not created"
  264. ("i" "Initialize Vlocity Project" vlo/generate-project-file)])
  265. (define-transient-command vlo/transient-project-action ()
  266. "Vlocity Build Tool CLI Actions"
  267. ["Create"
  268. ("c" "Create a new datapack (dynamically)" vlo/createDatapack)]
  269. ["Retrieve"
  270. ("s" "Search for new datapack" vlo/search)
  271. ("r" "Refresh this datapack (destructive)" vlo/exportThisAction)
  272. ("R" "Refresh all local datapacks (destructive)" vlo/exportAllAction)
  273. ]
  274. ["Deploy"
  275. ("d" "Deploy this datapack" vlo/deployThisAction)
  276. ("D" "Deploy all local datapacks" vlo/deployAllAction)
  277. ])
  278. (provide 'vlocitemacs)
  279. ;;; vlocitemacs.el ends here