summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaciej Barć <xgqt@gentoo.org>2022-07-07 20:52:56 +0200
committerMaciej Barć <xgqt@gentoo.org>2022-07-07 20:52:56 +0200
commite2761fd718d470e4a4565628e10ec3ac726e89b4 (patch)
tree47b1a9a83e6d104e6fa06b3ef20ec00aa5c962f8
downloademacs-openrc-e2761fd718d470e4a4565628e10ec3ac726e89b4.tar.gz
emacs-openrc-e2761fd718d470e4a4565628e10ec3ac726e89b4.tar.bz2
emacs-openrc-e2761fd718d470e4a4565628e10ec3ac726e89b4.zip
*: port0.0.0
Signed-off-by: Maciej Barć <xgqt@gentoo.org>
-rw-r--r--.editorconfig15
-rw-r--r--.gitignore8
-rw-r--r--Makefile19
-rw-r--r--openrc.el305
4 files changed, 347 insertions, 0 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..baa071b
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,15 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+indent_style = space
+insert_final_newline = true
+tab_width = 4
+trim_trailing_whitespace = true
+
+[.gitmodules]
+indent_style = tab
+
+[Makefile]
+indent_style = tab
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7944263
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+*.elc
+*.~undo-tree
+*~
+flycheck_*
+
+.cask/
+.eldev/
+dist/
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..513142e
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,19 @@
+EMACS := emacs
+FIND := find
+
+EMACFLAGS := --batch -q --no-site-file
+EMACSCMD = $(EMACS) $(EMACFLAGS)
+
+
+.PHONY: all
+all: clean compile
+
+.PHONY: clean
+clean:
+ $(FIND) $(PWD) -iname "*.elc" -delete
+
+%.elc:
+ $(EMACSCMD) --eval "(byte-compile-file \"$(*).el\" 0)"
+
+.PHONY: compile
+compile: openrc.elc
diff --git a/openrc.el b/openrc.el
new file mode 100644
index 0000000..a1bc135
--- /dev/null
+++ b/openrc.el
@@ -0,0 +1,305 @@
+;;; openrc.el --- OpenRC integration -*- lexical-binding: t -*-
+
+
+;; Copyright 2022 Gentoo Authors
+
+
+;; This file is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 2 of the License, or
+;; (at your option) any later version.
+
+;; This file is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+
+;; Author: Maciej Barć <xgqt@riseup.net>
+;; Homepage: https://gitweb.gentoo.org/proj/emacs-openrc.git
+;; Keywords: processes
+;; Maintainer: <emacs@gentoo.org>
+;; Package-Requires: ((emacs "24.3"))
+;; Version: 0.0.0
+
+
+
+;;; Commentary:
+
+
+;; OpenRC integration.
+
+
+;; This library was originally written as part of "emacs-gentoo"
+;; by Maciej Barć.
+;; It was later relicensed by the author under the GPL-2-or-later license
+;; and republished under the Gentoo GNU Emacs project.
+
+;; Original repository: https://gitlab.com/xgqt/emacs-gentoo
+
+
+
+;;; Code:
+
+
+;; Commands to consider:
+;; - rc-service -l -- all of services
+;; - rc-status -f "ini" boot
+;; - rc-update show -v
+
+
+(defconst openrc-version "0.0.0"
+ "Emacs-Openrc version.")
+
+(defgroup openrc nil
+ "OpenRC integration."
+ :group 'external)
+
+
+;; Executables
+
+(defcustom openrc-rc-command "/sbin/rc"
+ "Path to the \"rc\" binary."
+ :safe 'stringp
+ :type 'file
+ :group 'openrc)
+
+(defcustom openrc-rc-update-command (concat openrc-rc-command "-update")
+ "Path to the \"rc-update\" binary."
+ :safe 'stringp
+ :type 'file
+ :group 'openrc)
+
+(defcustom openrc-rc-service-command (concat openrc-rc-command "-service")
+ "Path to the \"rc-service\" binary."
+ :safe 'stringp
+ :type 'file
+ :group 'openrc)
+
+(defcustom openrc-sudo-command "sudo"
+ "Path to the \"sudo\" binary.
+Used to gain privilege for some commands."
+ :safe 'stringp
+ :type 'file
+ :group 'openrc)
+
+
+;; Directories
+
+(defcustom openrc-run-dir "/run/openrc"
+ "Path to OpenRC run directory (defaults to \"/run/openrc\")."
+ :safe 'stringp
+ :type 'file
+ :group 'openrc)
+
+(defcustom openrc-started-dir (expand-file-name "started" openrc-run-dir)
+ "Path to OpenRC directory containing started services."
+ :safe 'stringp
+ :type 'file
+ :group 'openrc)
+
+
+;; Other
+
+(defcustom openrc-use-sudo
+ (or (executable-find openrc-sudo-command)
+ (file-executable-p openrc-sudo-command))
+ "Whether to use \"sudo\" or \"su\" for commands that need root privileges.
+The invoked \"sudo\" executable location is controlled by the
+‘openrc-sudo-command’ variable."
+ :type 'boolean
+ :group 'openrc)
+
+
+
+;; Helpers
+
+(defun openrc--service-started? (service)
+ "Check if SERVICE is started."
+ (file-exists-p (expand-file-name service openrc-started-dir)))
+
+(defun openrc--get-services ()
+ "Get all OpenRC services."
+ (mapcar
+ (lambda (s)
+ (let* ((lst (split-string s "|" t " *"))
+ (service (car lst))
+ (runlevel (cdr lst)))
+ (vector service
+ (if (openrc--service-started? service) "YES" "NO")
+ (if (equal runlevel nil) "none" (car runlevel)))))
+ (split-string (shell-command-to-string
+ (concat openrc-rc-update-command " show -v")) "\n" t)))
+
+(defun openrc--tabulated-list (vectors list-length tabulated-list)
+ "Create a TABULATED-LIST from list of VECTORS of length LIST-LENGTH."
+ (cond
+ ((equal vectors nil) tabulated-list)
+ (t (openrc--tabulated-list
+ (cdr vectors)
+ list-length
+ (append tabulated-list
+ (list (list (- list-length (length vectors))
+ (car vectors))))))))
+
+(defun openrc-refresh-services ()
+ "Refresh the list of OpenRC services."
+ (interactive)
+ (message "Refreshing OpenRC services list...")
+ (let ((services (openrc--get-services)))
+ (setq tabulated-list-entries
+ (openrc--tabulated-list services (length services) '())))
+ (tabulated-list-init-header)
+ (tabulated-list-print t)
+ (message "...OpenRC services list refresh done!"))
+
+(defun openrc--async-shell-command (privileged &rest args)
+ "Run `async-shell-command' with ARGS.
+If PRIVILEGED is true, then use the \"sudo\" or \"su\" to run the command."
+ (let ((buffer-name "*OpenRC Command*")
+ (error-buffer-name "*OpenRC Command ERRORS*")
+ (command (apply 'concat (mapcar (lambda (s) (concat " " s)) args))))
+ (let ((buffer (get-buffer-create buffer-name)))
+ (with-current-buffer buffer
+ (if privileged
+ (if openrc-use-sudo
+ (async-shell-command (concat "sudo " command)
+ buffer-name
+ error-buffer-name)
+ (async-shell-command (concat "su -c \"" command "\"")
+ buffer-name
+ error-buffer-name))
+ (async-shell-command command buffer-name error-buffer-name))
+ (view-mode)))))
+
+
+;; Describing services
+
+(defun openrc--describe (service)
+ "Describe a SERVICE."
+ (openrc--async-shell-command
+ nil openrc-rc-service-command service "describe" "--verbose"))
+
+(defun openrc-describe-entry ()
+ "Describe a service under the tabulated list entry."
+ (interactive)
+ (openrc--describe (aref (tabulated-list-get-entry) 0)))
+
+
+;; Stopping and starting services
+
+(defun openrc--toggle (service started?)
+ "Start or stop a SERVICE depending on STARTED? state."
+ (openrc--async-shell-command
+ 'privileged
+ openrc-rc-service-command
+ service
+ (if started? "stop" "start") "--verbose"))
+
+(defun openrc-toggle-entry ()
+ "Start or stop a service under the tabulated list entry depending on state."
+ (interactive)
+ (let ((service (aref (tabulated-list-get-entry) 0)))
+ (openrc--toggle service (openrc--service-started? service))))
+
+(defun openrc--restart (service)
+ "Restart a SERVICE."
+ (openrc--async-shell-command
+ 'privileged openrc-rc-service-command service "restart" "--verbose"))
+
+(defun openrc-restart-entry ()
+ "Restart a service under the tabulated list entry."
+ (interactive)
+ (openrc--restart (aref (tabulated-list-get-entry) 0)))
+
+
+;; Adding and removing services from runlevels
+
+(defconst openrc--runlevels
+ '("boot" "default" "nonetwork" "shutdown" "sysinit")
+ "List of available runlevels.")
+
+(defun openrc--read-runlevel ()
+ "Read a runlevel selected by the user."
+ (completing-read "Runlevel:" openrc--runlevels))
+
+(defun openrc--add (service runlevel)
+ "Add a SERVICE to a RUNLEVEL."
+ (openrc--async-shell-command
+ 'privileged openrc-rc-update-command "add" service runlevel "--verbose" ))
+
+(defun openrc-add-entry ()
+ "Add a service under the tabulated list entry to a runlevel."
+ (interactive)
+ (openrc--add
+ (aref (tabulated-list-get-entry) 0) (openrc--read-runlevel)))
+
+(defun openrc--del (service runlevel)
+ "Remove a SERVICE from a RUNLEVEL."
+ (openrc--async-shell-command
+ 'privileged openrc-rc-update-command "del" service runlevel "--verbose"))
+
+(defun openrc-del-entry ()
+ "Remove a service under the tabulated list entry from a runlevel."
+ (interactive)
+ (openrc--del
+ (aref (tabulated-list-get-entry) 0) (openrc--read-runlevel)))
+
+
+;; Mode
+
+(defvar openrc-services-menu-mode-hook nil
+ "Hook for `openrc-services-menu' major mode.")
+
+(defvar openrc-services-menu-mode-map
+ (let ((openrc-services-menu-mode-map (make-keymap)))
+ (define-key
+ openrc-services-menu-mode-map (kbd "/") #'isearch-forward)
+ (define-key openrc-services-menu-mode-map (kbd "e")
+ #'openrc-describe-entry)
+ (define-key openrc-services-menu-mode-map (kbd "a")
+ #'openrc-add-entry)
+ (define-key openrc-services-menu-mode-map (kbd "d")
+ #'openrc-del-entry)
+ (define-key openrc-services-menu-mode-map (kbd "g")
+ #'openrc-refresh-services)
+ (define-key openrc-services-menu-mode-map (kbd "r")
+ #'openrc-restart-entry)
+ (define-key openrc-services-menu-mode-map (kbd "t")
+ #'openrc-toggle-entry)
+ openrc-services-menu-mode-map)
+ "Key map for `openrc-services-menu' major mode.")
+
+(define-derived-mode openrc-services-menu-mode tabulated-list-mode
+ "OpenRC Services Menu"
+ "Major mode for listing the OpenRC services."
+ (setq tabulated-list-format
+ [("Service" 30 t)
+ ("Started" 10 t)
+ ("Runlevel" 20 t)])
+ (setq tabulated-list-sort-key (cons "Runlevel" nil))
+ (run-hooks 'openrc-services-menu-mode-hook)
+ (use-local-map openrc-services-menu-mode-map))
+
+
+;; Main provided features
+
+;;;###autoload
+(defun openrc-list-services ()
+ "Display a list of OpenRC services."
+ (interactive)
+ (let ((buffer (get-buffer-create "*OpenRC Services*")))
+ (with-current-buffer buffer
+ (openrc-services-menu-mode)
+ (openrc-refresh-services))
+ (display-buffer buffer)))
+
+
+(provide 'openrc)
+
+
+
+;;; openrc.el ends here