;; -*- lexical-binding: t; -*- ;; A nice interface for running long-running local programs (use-package prodigy :commands (prodigy) :general ('normal prodigy-mode-map "SPC" leader-map) ('normal prodigy-view-mode-map "SPC" leader-map) :custom (prodigy-completion-system 'default) :config (evil-collection-prodigy-setup) ;; Add ability to associate a file with service logs instead of a buffer (defun prodigy-service-file (service) "Return SERVICE file. If SERVICE file exists, use that. If not, find the first SERVICE tag that has a file and return that." (let ((file (prodigy-service-or-first-tag-with service :file))) (if (functionp file) (prodigy-callback-with-plist file service) file))) (defun prodigy-display-process-file-or-buffer () (interactive) (when-let (service (prodigy-service-at-pos)) (if-let (file (prodigy-service-file service)) (progn (find-file-literally file) (prodigy-view-mode) (auto-revert-tail-mode) (general-define-key :states 'normal :keymaps 'local "Q" #'kill-this-buffer)) (prodigy-switch-to-process-buffer service)))) (general-def 'normal prodigy-mode-map "`" #'prodigy-display-process-file-or-buffer) ;; Add ability to inhibit all output processing (defun prodigy-start-service (service &optional callback) "Start process associated with SERVICE unless already started. When CALLBACK function is specified, that is called when the process has been started. When the process is started, a timer starts and checks every second for `prodigy-start-tryouts' times if the process is live. If the process is not live after `prodigy-start-tryouts' seconds, the process is put in failed status." (declare (indent 1)) (unless (prodigy-service-started-p service) (let* ((default-directory (-if-let (cwd (prodigy-service-cwd service)) (f-full cwd) default-directory)) (name (plist-get service :name)) (sudo (plist-get service :sudo)) (command (prodigy-service-command service)) (args (prodigy-service-args service)) (exec-path (append (prodigy-service-path service) exec-path)) (env (--map (s-join "=" it) (prodigy-service-env service))) (process-environment (append env process-environment)) (process nil) (create-process (lambda () (unless process (setq process (apply (if sudo 'prodigy-start-sudo-process 'start-process) (append (list name nil command) args))))))) (-when-let (init (prodigy-service-init service)) (funcall init)) (-when-let (init-async (prodigy-service-init-async service)) (let (callbacked) (funcall init-async (lambda () (setq callbacked t) (funcall create-process))) (with-timeout (prodigy-init-async-timeout (error "Did not callback async callback within %s seconds" prodigy-init-async-timeout)) (while (not callbacked) (accept-process-output nil 0.005))))) (funcall create-process) (let ((tryout 0)) (prodigy-every 1 (lambda (next) (setq tryout (1+ tryout)) (if (process-live-p process) (when callback (funcall callback)) (if (= tryout prodigy-start-tryouts) (prodigy-set-status service 'failed) (funcall next)))))) (plist-put service :process process) (when (not (plist-get service :inhibit-process-filter)) (set-process-filter process (lambda (_ output) (run-hook-with-args 'prodigy-process-on-output-hook service output)))) (set-process-query-on-exit-flag process nil)))) (add-hook 'prodigy-view-mode-hook (lambda () (toggle-truncate-lines 1))) ;; Actual service definitions begin here (defun call-with-venv (venv callback) (let ((venv-dir (cond ((file-exists-p venv) venv) ((file-exists-p (substitute-in-file-name (format "$WORKON_HOME/%s" venv))) (substitute-in-file-name (format "$WORKON_HOME/%s" venv))) (t (error "virtual environment %s does not exist" venv))))) (call-with-env-from-file (format "%s/bin/activate" venv-dir) callback))) (defun kill-log-buffers () (interactive) (kill-matching-buffers "\\.log$" nil t) (message "Killed log buffers")) (cl-defun python-service-setup (venv &optional env-file &key env-dir) (lambda (done) (call-with-venv venv (if env-file (lambda () (call-with-env-from-file env-file done :dir env-dir)) done)))) (defun call-with-lola-env (callback) (let ((process-environment (cons (format "LOLA_ENV=%s" (completing-read "Environment: " '("local" "development" "staging"))) process-environment))) (funcall callback))) (prodigy-define-tag :name 'lola) (prodigy-define-service :name "lola-server (gunicorn)" :tags '(lola backend) :command "bash" :args (lambda () (list "-c" "gunicorn -c server/web/gunicorn.conf.py \ -b 127.0.0.1:7200 bin.start_web:init_and_create_flask_app\\(\\) \ >> ~/lola/logs/lola-server.log 2>&1")) :file "~/lola/logs/lola-server.log" :inhibit-process-filter t :cwd "~/lola/core-services/lola_server" :stop-signal 'int :truncate-output t :init-async (python-service-setup "~/lola/core-services/.venv" "~/lola/core-services/lola_server/.env")) (prodigy-define-service :name "lola-server celery worker" :tags '(lola backend) :command "python" :args '("bin/start_celery_worker.py" "-P" "gevent" "-n" "lola-server") :cwd "~/lola/core-services/lola_server" :stop-signal 'int :truncate-output t :init-async (python-service-setup "~/lola/core-services/.venv" "~/lola/core-services/lola_server/.env")) (prodigy-define-service :name "travel-service" :tags '(lola backend) :command "bash" :args (lambda () (list "-c" "python bin/start_web.py >> ~/lola/logs/travel-svc.log 2>&1")) :cwd "~/lola/core-services/travel_service" :file "~/lola/logs/travel-svc.log" :inhibit-process-filter t :stop-signal 'int :truncate-output t :init-async (python-service-setup "~/lola/core-services/.venv" "~/lola/core-services/travel_service/.env")) (prodigy-define-service :name "travel-service celery worker" :tags '(lola backend) :command "bash" :args (lambda () (list "-c" (concat "python " "bin/start_celery_workers.py " "-n " "travel-service " ">> ~/lola/logs/travel-svc-celery.log 2>&1"))) :file "~/lola/logs/travel-svc-celery.log" :inhibit-process-filter t :cwd "~/lola/core-services/travel_service" :stop-signal 'int :truncate-output t :init-async (python-service-setup "~/lola/core-services/.venv" "~/lola/core-services/travel_service/.env")) (prodigy-define-service :name "secrets" :tags '(lola backend) :command "python" :args '("bin/cmdline.py" "www") :env '(("PORT" "7450")) :cwd "~/lola/secrets" :truncate-output t :stop-signal 'int :init-async (python-service-setup "~/.pyenv/versions/secrets" "~/lola/secrets/.env")) (prodigy-define-service :name "lola-desktop" :tags '(lola frontend) :command "npm" :args '("start") :cwd "~/lola/lola-desktop" :port 3001 :env '(("PORT" "3001")) :stop-signal 'int :init-async #'call-with-lola-env) (prodigy-define-service :name "wallet" :tags '(lola frontend) :command "npm" :args '("start") :cwd "~/lola/wallet" :stop-signal 'int :env '(("PORT" "3000")) :init-async #'call-with-lola-env) (prodigy-define-service :name "agent-console" :command "npm" :args '("start") :cwd "~/lola/agent-console" :stop-signal 'int :env '(("PORT" "3002")) :init-async (lambda (done) (call-with-lola-env (lambda () (nvm-use "v10.15.1" done))))) (prodigy-define-service :name "luigid" :command "luigid" :cwd "~/lola/data-pipeline" :port 8082 :stop-signal 'int :init-async (python-service-setup "data-pipeline" "~/lola/data-pipeline/.env")) (prodigy-define-service :name "prometheus" :command "prometheus" :args '("--config.file=prometheus.yml") :port 9090 :stop-signal 'int :cwd "~/prometheus") (prodigy-define-service :name "priceline-service" :tags '(lola backend) :command "~/lola/python_services/priceline/bin/start.sh" :args '("web-dev") :cwd "~/lola/python_services" :stop-signal 'int :init-async (python-service-setup "~/lola/python_services/.venv" "~/lola/python_services/priceline/.env" :env-dir "~/lola/python_services")) (prodigy-define-service :name "priceline-cars-service" :tags '(lola backend) :command "bash" :args '("-c" "priceline_cars/bin/start.sh web-dev >> ~/lola/logs/priceline-cars.log 2>&1") :cwd "~/lola/python_services" :inhibit-process-filter t :file "~/lola/logs/priceline-cars.log" :stop-signal 'int :init-async (python-service-setup "~/lola/python_services/.venv" "~/lola/python_services/priceline_cars/.env" :env-dir "~/lola/python_services")) (prodigy-define-service :name "threev-service" :tags '(lola backend) :command "~/lola/python_services/threev/bin/start.sh" :args '("web-dev") :cwd "~/lola/python_services" :stop-signal 'int :init-async (python-service-setup "~/lola/python_services/.venv" "~/lola/python_services/threev/.env" :env-dir "~/lola/python_services")) (prodigy-define-service :name "amd-flight-service" :tags '(lola backend) :command "~/lola/python_services/amd_flight/bin/start.sh" :args '("web-dev") :cwd "~/lola/python_services" :stop-signal 'int :init-async (python-service-setup "~/lola/python_services/.venv" "~/lola/python_services/amd_flight/.env" :env-dir "~/lola/python_services")) (prodigy-define-service :name "ean-hotels-service" :tags '(lola backend) :command "bash" :args '("-c" "ean_hotels/bin/start.sh web-dev >> ~/lola/logs/ean-hotels.log 2>&1") :cwd "~/lola/python_services" :inhibit-process-filter t :file "~/lola/logs/ean-hotels.log" :stop-signal 'kill :init-async (python-service-setup "~/lola/python_services/.venv" "~/lola/python_services/ean_hotels/.env" :env-dir "~/lola/python_services")) (prodigy-define-service :name "smp-hotels-service" :command "bash" :args '("-c" "smp_hotels/bin/start.sh web >> ~/lola/logs/smp-hotels.log 2>&1") :cwd "~/lola/python_services" :inhibit-process-filter t :file "~/lola/logs/smp-hotels.log" :stop-signal 'kill :init-async (python-service-setup "~/lola/python_services/.venv" "~/lola/python_services/smp_hotels/.env" :env-dir "~/lola/python_services")) (prodigy-define-service :name "email-template-service" :tags '(lola backend) :command "npm" :args '("start") :cwd "~/lola/email-template-service" :env '(("PORT" "7300")) :stop-signal 'int :init-async (lambda (done) (nvm-use "10.15.1" done))) (prodigy-define-service :name "mabl-link-agent" :command "link-agent" :args (lambda () (list "-a" (password-store-get "mabl-link-agent") "-n" "jdormit-macbook"))) (prodigy-define-service :name "xray-daemon" :command "xray_mac" :args '("-o" "-n" "us-east-1")) (prodigy-define-service :name "spend-service" :tags '(lola backend) :command "~/lola/python_services/spend/bin/start.sh" :args '("web-dev") :cwd "~/lola/python_services" :stop-signal 'int :init-async (python-service-setup "~/lola/python_services/.venv" "~/lola/python_services/spend/.env" :env-dir "~/lola/python_services"))) (provide 'init-prodigy)