Compare commits

..

No commits in common. "2715390f16a679526de7c0f38133020abe695c03" and "db033371c3f6ac86374480dff66912d78ef35892" have entirely different histories.

12 changed files with 60 additions and 204 deletions

View file

@ -3,7 +3,6 @@ enabled_backends = ["arch"]
hostname_groups_enabled = true
[hostname_groups]
violet = ["system","office","nvidia","music","mail","latex","emacs","dev","desktop-rofi","desktop-polybar","desktop-misc","desktop","console","browsers"]
weiss = ["system","office","music","mail","latex","emacs","dev","desktop-rofi","desktop-polybar","desktop-misc","desktop","console","browsers"]
archlinux = ["system","office","music","mail","latex","emacs","dev","desktop-rofi","desktop-polybar","desktop-misc","desktop","console","browsers"]

View file

@ -1,5 +1,4 @@
arch = [
"veracrypt",
"android-file-transfer",
"remmina",
"noto-fonts-emoji",

View file

@ -2,6 +2,7 @@ arch = [
"xf86-video-ati",
"xf86-video-amdgpu",
"vulkan-radeon",
"nvidia-utils",
"vulkan-intel",
"intel-media-driver",
"libva-intel-driver",

View file

@ -1,5 +1,5 @@
[Unit]
Description=Run notmuch sync script every 5 minutes
Description=Run notmuch new every 5 minutes
[Timer]
OnBootSec=1min

View file

@ -381,14 +381,14 @@ DIR is either 'left or 'right."
_t_: Terminal (Alacritty)
_b_: Browser (Firefox)
_s_: Rocket.Chat
_d_: DBeaver
_c_: Chromium
_e_: Element
_d_: Discord
"
("t" (lambda () (interactive) (my/run-in-background "alacritty")))
("b" (lambda () (interactive) (my/run-in-background "firefox")))
("s" (lambda () (interactive) (my/run-in-background "rocketchat-desktop")))
("d" (lambda () (interactive) (my/run-in-background "dbeaver")))
("c" (lambda () (interactive) (my/run-in-background "chromium"))))
("s" (lambda () (interactive) (my/run-in-background "flatpak run chat.rocket.RocketChat")))
("e" (lambda () (interactive) (my/run-in-background "flatpak run im.riot.Riot")))
("d" (lambda () (interactive) (my/run-in-background "flatpak run com.discordapp.Discord"))))
(defun my/exwm-lock ()
(interactive)
@ -594,10 +594,10 @@ _c_: Chromium
(my/exwm-set-wallpaper)
(my/exwm-run-shepherd)
(my/exwm-run-systemd)
(my/run-in-background "gpgconf --reload gpg-agent")
(my/exwm-run-polybar)
(setenv "DBUS_SESSION_BUS_ADDRESS" "unix:path=/run/user/1000/bus")
(my/exwm-run-systemd)
(when (my/is-arch)
(my/run-in-background "set_layout")))

View file

@ -82,8 +82,6 @@
;; I have everything I need in polybar
(emms-mode-line-mode -1)
(emms-playing-time-display-mode -1)
(delq 'emms-mark-mode evil-emacs-state-modes)
(delq 'emms-browser-mode evil-emacs-state-modes)
(defun emms-info-mpd-process (track info)
(dolist (data info)
(let ((name (car data))

View file

@ -375,11 +375,8 @@ REMOTE = '<rclone-remote>'
FOLDERS = json.loads('<rclone-folders-json>')
OPTIONS = json.loads('<rclone-options>')
for folder, i in zip(FOLDERS, range(len(FOLDERS))):
folder['id'] = i
def rclone_make_command(local_path, remote_path, remote, extra_args=[]):
def rclone_make_command(local_path, remote_path, remote):
return [
'rclone',
'bisync',
@ -393,8 +390,7 @@ def rclone_make_command(local_path, remote_path, remote, extra_args=[]):
'NEVER',
'--use-json-log',
'--stats',
'9999m',
*extra_args
'9999m'
]
@ -422,26 +418,15 @@ def process_output(output):
except Exception:
print(line)
def process_command_for_print(command):
res = []
for c in command:
if ' ' in c:
res.append(f'\\'{c}\\'')
else:
res.append(c)
return ' '.join(res)
def rclone_run(folder, extra_args=[]):
def rclone_run(folder):
command = rclone_make_command(
folder['local-path'], folder['remote-path'], folder['remote'], extra_args
folder['local-path'], folder['remote-path'], folder['remote']
)
try:
print(str(folder['id']) + '. ' + process_command_for_print(command))
result = subprocess.run(command, check=True, capture_output=True, text=True)
except subprocess.CalledProcessError as e:
print(f'=== Error syncing {folder['local-path']} ===')
print(f'Command: {process_command_for_print(command)}')
print(f'Command: {' '.join(command)}')
print(f'--- STDOUT ---')
process_output(e.stdout)
print(f'--- STDERR ---')
@ -449,6 +434,7 @@ def rclone_run(folder, extra_args=[]):
return {'success': False, 'stats': {}}
return {'success': True, 'stats': parse_rclone_stats(result.stderr)}
def notify(summary, body, level='normal', expire_time=5000):
subprocess.run(['notify-send', '-u', level, '-t', str(expire_time), summary, body])
@ -461,16 +447,17 @@ def sizeof_fmt(num, suffix='B'):
return f'{num:.1f}Yi{suffix}'
def rclone_run_all(folders, extra_args=[]):
def rclone_run_all(folders):
error_folders = []
total_bytes = 0
total_transfers = 0
total_deleted = 0
total_renamed = 0
for folder in folders:
res = rclone_run(folder, extra_args)
print(f'Running rclone for {folder}')
res = rclone_run(folder)
if not res['success']:
error_folders.append(folder)
error_folders.append(folder['local-path'])
else:
total_bytes += res.get('stats', {}).get('bytes', 0)
total_transfers += res.get('stats', {}).get('transfers', 0)
@ -482,44 +469,21 @@ def rclone_run_all(folders, extra_args=[]):
if total_transfers > 0:
msg += f'''Transferred {total_transfers} files ({sizeof_fmt(total_bytes)})\n'''
if total_deleted > 0:
msg += f'''Deleted {total_deleted} files\n'''
msg += f'''Deleted {total_transfers} files\n'''
if total_renamed > 0:
msg += f'''Renamed {total_renamed} files\n'''
if len(error_folders) > 0:
msg += '''\nSync errors for the following folders:'''
for folder in error_folders:
msg += '''\n- ''' + str(folder['id']) + '. ' + folder['local-path']
msg += '''\n- ''' + folder
level = 'critical'
if len(msg) > 0:
notify(f'rclone sync {REMOTE}', msg, level=level)
def parse_arguments():
if len(sys.argv) < 2:
return None, []
id_arg = sys.argv[1]
folder_ids = [int(x.strip()) for x in id_arg.split(',')]
extra_args = sys.argv[2:]
return folder_ids, extra_args
if __name__ == '__main__':
folder_ids, extra_args = parse_arguments()
if folder_ids is None:
selected_folders = FOLDERS
else:
selected_folders = [f for f in FOLDERS if f['id'] in folder_ids]
found_ids = {f['id'] for f in selected_folders}
missing_ids = set(folder_ids) - found_ids
if missing_ids:
print(f'Warning: folder IDs not found: {sorted(missing_ids)}')
rclone_run_all(selected_folders, extra_args)
rclone_run_all(FOLDERS)
"))
(setq script
(thread-last script
@ -598,23 +562,6 @@ The return value is a list of commands as defined by
commands))
(nreverse commands)))
(defun my/index-rclone-reset ()
"Delete all rclone test files."
(interactive)
(let* ((tree (my/index--tree-retrive))
(folders (my/index--rclone-get-folders tree))
files-to-delete)
(dolist (folder folders)
(let ((test-file-path
(concat
(alist-get :local-path folder)
(format ".rclone-test-%s" (alist-get :remote folder)))))
(when (file-exists-p test-file-path)
(push test-file-path files-to-delete))))
(when (y-or-n-p (format "Delete %d files" (seq-length files-to-delete)))
(dolist (file files-to-delete)
(delete-file file)))))
(defun my/index--git-commands (tree)
"Get commands to clone the yet uncloned git repos in TREE.

View file

@ -70,12 +70,6 @@ Host *
AddKeysToAgent yes
#+end_src
And run:
#+begin_src bash
systemctl enable --user --now ssh-agent
#+end_src
It looks like it is necessary to run at least once.
Then, clone the dotfiles repo with =yadm=:
#+begin_src bash
yadm clone git@github.com:SqrtMinusOne/dotfiles.git
@ -140,8 +134,6 @@ sudo systemctl disable --now systemd-networkd
#+end_src
And reboot. After the reboot, =NetworkManager= should run using =wpa_supplicant= as backend for Wi-Fi.
Don't forget to sync mail and enable the sync timer.
* Metapac configuration
[[https://github.com/ripytide/metapac][metapac]] is a declarative wrapper around different package managers, including [[https://wiki.archlinux.org/title/Pacman][pacman]] and [[https://github.com/Morganamilo/paru][paru]]. This means the required packages can be listed in configuration files and checked into version control.
@ -151,21 +143,20 @@ In =metapac=, packages are listed in "groups", each group being a TOML file stat
Below is the table enabling different groups on different hostnames:
#+NAME: metapac-groups
| Profile | archlinux | weiss | violet |
| browsers | + | + | + |
| console | + | + | + |
| desktop | + | + | + |
| desktop-misc | + | + | + |
| desktop-polybar | + | + | + |
| desktop-rofi | + | + | + |
| dev | + | + | + |
| emacs | + | + | + |
| latex | + | + | + |
| mail | + | + | + |
| music | + | + | + |
| nvidia | | | + |
| office | + | + | + |
| system | + | + | + |
| Profile | archlinux | weiss |
| browsers | + | + |
| console | + | + |
| desktop | + | + |
| desktop-misc | + | + |
| desktop-polybar | + | + |
| desktop-rofi | + | + |
| dev | + | + |
| emacs | + | + |
| latex | + | + |
| mail | + | + |
| music | + | + |
| office | + | + |
| system | + | + |
And the code to format it as TOML:
#+NAME: metapac-groups-format
@ -240,26 +231,16 @@ Various drivers, I'm not sure which I actually need, so...
| libva-intel-driver |
| intel-media-driver |
| vulkan-intel |
| nvidia-utils |
| vulkan-radeon |
| xf86-video-amdgpu |
| xf86-video-ati |
NVIDIA drivers for violet
| Category | Arch dependency |
|----------+-----------------|
| nvidia | cuda |
| nvidia | nvidia-utils |
| nvidia | nvidia |
#+NAME: packages
#+begin_src emacs-lisp :tangle no :var category=""
(my/format-arch-dependencies category)
#+end_src
#+begin_src scheme :tangle .config/metapac/groups/nvidia.toml :noweb yes
<<packages("nvidia")>>
#+end_src
#+begin_src scheme :tangle .config/metapac/groups/system.toml :noweb yes
<<packages()>>
#+end_src

View file

@ -965,14 +965,14 @@ A +transient+ hydra for shortcuts for the most frequent apps.
_t_: Terminal (Alacritty)
_b_: Browser (Firefox)
_s_: Rocket.Chat
_d_: DBeaver
_c_: Chromium
_e_: Element
_d_: Discord
"
("t" (lambda () (interactive) (my/run-in-background "alacritty")))
("b" (lambda () (interactive) (my/run-in-background "firefox")))
("s" (lambda () (interactive) (my/run-in-background "rocketchat-desktop")))
("d" (lambda () (interactive) (my/run-in-background "dbeaver")))
("c" (lambda () (interactive) (my/run-in-background "chromium"))))
("s" (lambda () (interactive) (my/run-in-background "flatpak run chat.rocket.RocketChat")))
("e" (lambda () (interactive) (my/run-in-background "flatpak run im.riot.Riot")))
("d" (lambda () (interactive) (my/run-in-background "flatpak run com.discordapp.Discord"))))
#+end_src
*** Locking up
Run i3lock.
@ -1219,10 +1219,10 @@ And the EXWM config itself.
(my/exwm-set-wallpaper)
(my/exwm-run-shepherd)
(my/exwm-run-systemd)
(my/run-in-background "gpgconf --reload gpg-agent")
(my/exwm-run-polybar)
(setenv "DBUS_SESSION_BUS_ADDRESS" "unix:path=/run/user/1000/bus")
(my/exwm-run-systemd)
(when (my/is-arch)
(my/run-in-background "set_layout")))
@ -4239,7 +4239,6 @@ This section generates manifests for various desktop software that I'm using.
| office | okular |
| office | obs-studio |
| office | rocketchat-desktop |
** LaTeX
| Category | Arch dependency | Disabled |
|----------+--------------------------+----------|
@ -4541,7 +4540,6 @@ Other desktop programs I use are listed below.
| desktop-misc | noto-fonts-emoji | |
| desktop-misc | remmina | |
| desktop-misc | android-file-transfer | |
| desktop-misc | veracrypt | |
#+NAME: packages
#+begin_src emacs-lisp :tangle no

View file

@ -10433,8 +10433,6 @@ References:
;; I have everything I need in polybar
(emms-mode-line-mode -1)
(emms-playing-time-display-mode -1)
(delq 'emms-mark-mode evil-emacs-state-modes)
(delq 'emms-browser-mode evil-emacs-state-modes)
<<emms-fixes>>)
#+end_src
**** MPD
@ -12872,11 +12870,8 @@ REMOTE = '<rclone-remote>'
FOLDERS = json.loads('<rclone-folders-json>')
OPTIONS = json.loads('<rclone-options>')
for folder, i in zip(FOLDERS, range(len(FOLDERS))):
folder['id'] = i
def rclone_make_command(local_path, remote_path, remote, extra_args=[]):
def rclone_make_command(local_path, remote_path, remote):
return [
'rclone',
'bisync',
@ -12890,8 +12885,7 @@ def rclone_make_command(local_path, remote_path, remote, extra_args=[]):
'NEVER',
'--use-json-log',
'--stats',
'9999m',
,*extra_args
'9999m'
]
@ -12919,26 +12913,15 @@ def process_output(output):
except Exception:
print(line)
def process_command_for_print(command):
res = []
for c in command:
if ' ' in c:
res.append(f'\\'{c}\\'')
else:
res.append(c)
return ' '.join(res)
def rclone_run(folder, extra_args=[]):
def rclone_run(folder):
command = rclone_make_command(
folder['local-path'], folder['remote-path'], folder['remote'], extra_args
folder['local-path'], folder['remote-path'], folder['remote']
)
try:
print(str(folder['id']) + '. ' + process_command_for_print(command))
result = subprocess.run(command, check=True, capture_output=True, text=True)
except subprocess.CalledProcessError as e:
print(f'=== Error syncing {folder['local-path']} ===')
print(f'Command: {process_command_for_print(command)}')
print(f'Command: {' '.join(command)}')
print(f'--- STDOUT ---')
process_output(e.stdout)
print(f'--- STDERR ---')
@ -12946,6 +12929,7 @@ def rclone_run(folder, extra_args=[]):
return {'success': False, 'stats': {}}
return {'success': True, 'stats': parse_rclone_stats(result.stderr)}
def notify(summary, body, level='normal', expire_time=5000):
subprocess.run(['notify-send', '-u', level, '-t', str(expire_time), summary, body])
@ -12958,16 +12942,17 @@ def sizeof_fmt(num, suffix='B'):
return f'{num:.1f}Yi{suffix}'
def rclone_run_all(folders, extra_args=[]):
def rclone_run_all(folders):
error_folders = []
total_bytes = 0
total_transfers = 0
total_deleted = 0
total_renamed = 0
for folder in folders:
res = rclone_run(folder, extra_args)
print(f'Running rclone for {folder}')
res = rclone_run(folder)
if not res['success']:
error_folders.append(folder)
error_folders.append(folder['local-path'])
else:
total_bytes += res.get('stats', {}).get('bytes', 0)
total_transfers += res.get('stats', {}).get('transfers', 0)
@ -12979,44 +12964,21 @@ def rclone_run_all(folders, extra_args=[]):
if total_transfers > 0:
msg += f'''Transferred {total_transfers} files ({sizeof_fmt(total_bytes)})\n'''
if total_deleted > 0:
msg += f'''Deleted {total_deleted} files\n'''
msg += f'''Deleted {total_transfers} files\n'''
if total_renamed > 0:
msg += f'''Renamed {total_renamed} files\n'''
if len(error_folders) > 0:
msg += '''\nSync errors for the following folders:'''
for folder in error_folders:
msg += '''\n- ''' + str(folder['id']) + '. ' + folder['local-path']
msg += '''\n- ''' + folder
level = 'critical'
if len(msg) > 0:
notify(f'rclone sync {REMOTE}', msg, level=level)
def parse_arguments():
if len(sys.argv) < 2:
return None, []
id_arg = sys.argv[1]
folder_ids = [int(x.strip()) for x in id_arg.split(',')]
extra_args = sys.argv[2:]
return folder_ids, extra_args
if __name__ == '__main__':
folder_ids, extra_args = parse_arguments()
if folder_ids is None:
selected_folders = FOLDERS
else:
selected_folders = [f for f in FOLDERS if f['id'] in folder_ids]
found_ids = {f['id'] for f in selected_folders}
missing_ids = set(folder_ids) - found_ids
if missing_ids:
print(f'Warning: folder IDs not found: {sorted(missing_ids)}')
rclone_run_all(selected_folders, extra_args)
rclone_run_all(FOLDERS)
#+end_src
A function that templates the script above:
@ -13111,26 +13073,6 @@ The return value is a list of commands as defined by
(nreverse commands)))
#+end_src
Also, a command to remove all =.rclone-test-*= files. This is necessary, e.g. after a change in the filter file.
#+begin_src emacs-lisp
(defun my/index-rclone-reset ()
"Delete all rclone test files."
(interactive)
(let* ((tree (my/index--tree-retrive))
(folders (my/index--rclone-get-folders tree))
files-to-delete)
(dolist (folder folders)
(let ((test-file-path
(concat
(alist-get :local-path folder)
(format ".rclone-test-%s" (alist-get :remote folder)))))
(when (file-exists-p test-file-path)
(push test-file-path files-to-delete))))
(when (y-or-n-p (format "Delete %d files" (seq-length files-to-delete)))
(dolist (file files-to-delete)
(delete-file file)))))
#+end_src
**** Git repos
To sync git, we just need to clone the required git repos. Removing the repos is handled by the folder sync commands.

View file

@ -9,7 +9,7 @@ I use the [[https://leanpub.com/lit-config/read][literate configuration]] strate
The files themselves are managed and deployed via [[https://yadm.io/][yadm]], although I use Org Mode for things like config templating.
My current GNU/Linux distribution is [[https://guix.gnu.org/][Arch Linux]], managed declaratively with [[https://github.com/ripytide/metapac][metapac]] (look for tables with "Arch dependency" in the header). I used to use Guix for the same purpose for 4.5 years; I keep the config now for archival purposes.
My current GNU/Linux distribution is [[https://guix.gnu.org/][GNU Guix]]. I like Guix because, among other things, it allows [[https://guix.gnu.org/cookbook/en/html_node/Advanced-package-management.html#Advanced-package-management][to declare the required software]] in configuration files, so I can have the same set of programs across multiple machines (look for tables with "Guix dependency" in the header).
The central program to all of that is, of course, [[https://www.gnu.org/software/emacs/][GNU Emacs]]. At the time of this writing, it takes ~50% of my screen time and has the largest share of configuration here.
@ -22,14 +22,15 @@ Table of contents and software:
- [[file:Console.org][Console.org]]
- /Active/: [[file:Console.org::*=.profile=][.profile]], [[file:Console.org::*Bash][Bash]], [[file:Console.org::*Fish][Fish]], [[file:Console.org::*Starship prompt][Starship]], [[file:Console.org::*Tmux][Tmux]], [[file:Console.org::*Alacritty][Alacritty]]
- /In Limbo/: [[file:Console.org::*Nushell][Nushell]]
- [[file:Arch.org][Arch.org]]
- [[file:Guix.org][Guix.org]]
- [[file:Mail.org][Mail.org]]
- /Active/: [[file:Mail.org::*Lieer][Lieer]], [[file:Mail.org::*DavMail][DavMail]], [[file:Mail.org::*OfflineIMAP][OfflineIMAP]], [[file:Mail.org::*Notmuch][Notmuch]]
- [[file:Guix.org][Guix.org]] (archive)
(/Apparently, links on the second level work only in Emacs 🙁/)
A few other repositories I may consider a part of my config:
- [[https://github.com/SqrtMinusOne/channel-q][channel-q]] is my Guix channel
- [[https://github.com/SqrtMinusOne/sqrt-data][sqrt-data]] is a home for my statistics gathering effort
- [[https://sqrtminusone.xyz/emacs-packages/][My Emacs Packages]], some of which originated in my Emacs config
See also [[https://sqrtminusone.xyz/posts/][my blog posts]].

View file

@ -2,21 +2,11 @@
{
"title": "OS/Distro",
"elements": [
{
"name": "Arch Linux",
"states": [
{
"startDate": "2025-11-23"
}
],
"color": "y"
},
{
"name": "GNU Guix",
"states": [
{
"startDate": "2021-06-11",
"endDate": "2025-11-23"
"startDate": "2021-06-11"
}
],
"color": "y"