We have made an emacs conf with profiles. And refactored lab tool to use deploy-rs
This commit is contained in:
parent
24b01ae4f0
commit
bff56e4ffc
22 changed files with 1448 additions and 176 deletions
123
documentation/SSH_DEPLOYMENT_STRATEGY.md
Normal file
123
documentation/SSH_DEPLOYMENT_STRATEGY.md
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
# SSH Deployment Strategy - Unified sma User Approach
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This document outlines the updated SSH deployment strategy for the home lab, standardizing on the `sma` user for all administrative operations and deployments.
|
||||||
|
|
||||||
|
## User Strategy
|
||||||
|
|
||||||
|
### sma User (System Administrator)
|
||||||
|
- **Purpose**: System administration, deployment, maintenance
|
||||||
|
- **SSH Key**: `id_ed25519_admin`
|
||||||
|
- **Privileges**: sudo NOPASSWD, wheel group
|
||||||
|
- **Usage**: All lab tool deployments, system maintenance
|
||||||
|
|
||||||
|
### geir User (Developer)
|
||||||
|
- **Purpose**: Development work, daily usage, git operations
|
||||||
|
- **SSH Key**: `id_ed25519_dev`
|
||||||
|
- **Privileges**: Standard user with development tools
|
||||||
|
- **Usage**: Development workflows, git operations
|
||||||
|
|
||||||
|
## Deployment Workflow
|
||||||
|
|
||||||
|
### From Any Machine (Workstation or Laptop)
|
||||||
|
|
||||||
|
1. **Both machines have sma user configured** with admin SSH key
|
||||||
|
2. **Lab tool uses sma user consistently** for all remote operations
|
||||||
|
3. **Deploy-rs uses sma user** for automated deployments with rollback
|
||||||
|
|
||||||
|
### SSH Configuration
|
||||||
|
|
||||||
|
The SSH configuration supports both direct access patterns:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Direct Tailscale access with sma user
|
||||||
|
ssh sma@sleeper-service.tail807ea.ts.net
|
||||||
|
ssh sma@grey-area.tail807ea.ts.net
|
||||||
|
ssh sma@reverse-proxy.tail807ea.ts.net
|
||||||
|
ssh sma@little-rascal.tail807ea.ts.net
|
||||||
|
|
||||||
|
# Local sma user (for deployment from laptop to workstation)
|
||||||
|
ssh sma@localhost
|
||||||
|
```
|
||||||
|
|
||||||
|
## Lab Tool Commands
|
||||||
|
|
||||||
|
All lab commands now work consistently from both machines:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Status checking
|
||||||
|
lab status # Works from both workstation and laptop
|
||||||
|
|
||||||
|
# Deployment (using sma user automatically)
|
||||||
|
lab deploy sleeper-service # Works from both machines
|
||||||
|
lab deploy grey-area # Works from both machines
|
||||||
|
lab deploy little-rascal # Deploy TO laptop FROM workstation
|
||||||
|
lab deploy congenital-optimist # Deploy TO workstation FROM laptop
|
||||||
|
|
||||||
|
# Deploy-rs (with automatic rollback)
|
||||||
|
lab deploy-rs sleeper-service
|
||||||
|
lab hybrid-update all
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Benefits
|
||||||
|
|
||||||
|
1. **Principle of Least Privilege**: sma user only for admin tasks
|
||||||
|
2. **Key Separation**: Admin and development keys are separate
|
||||||
|
3. **Consistent Access**: Same user across all machines for deployment
|
||||||
|
4. **Audit Trail**: Clear separation between admin and development activities
|
||||||
|
|
||||||
|
## Machine-Specific Notes
|
||||||
|
|
||||||
|
### congenital-optimist (Workstation)
|
||||||
|
- **Type**: Local deployment
|
||||||
|
- **SSH**: Uses localhost with sma user for consistency
|
||||||
|
- **Primary Use**: Development and deployment hub
|
||||||
|
|
||||||
|
### little-rascal (Laptop)
|
||||||
|
- **Type**: Remote deployment
|
||||||
|
- **SSH**: Tailscale hostname with sma user
|
||||||
|
- **Primary Use**: Mobile development and deployment
|
||||||
|
|
||||||
|
### Remote Servers (sleeper-service, grey-area, reverse-proxy)
|
||||||
|
- **Type**: Remote deployment
|
||||||
|
- **SSH**: Tailscale hostnames with sma user
|
||||||
|
- **Access**: Both workstation and laptop can deploy
|
||||||
|
|
||||||
|
## Migration Benefits
|
||||||
|
|
||||||
|
1. **Simplified Workflow**: Same commands work from both machines
|
||||||
|
2. **Better Security**: Dedicated admin user for all system operations
|
||||||
|
3. **Consistency**: All deployments use the same SSH user pattern
|
||||||
|
4. **Flexibility**: Can deploy from either workstation or laptop seamlessly
|
||||||
|
|
||||||
|
## Testing the Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test SSH connectivity with sma user
|
||||||
|
ssh sma@sleeper-service.tail807ea.ts.net echo "Connection OK"
|
||||||
|
ssh sma@grey-area.tail807ea.ts.net echo "Connection OK"
|
||||||
|
ssh sma@little-rascal.tail807ea.ts.net echo "Connection OK"
|
||||||
|
|
||||||
|
# Test lab tool
|
||||||
|
lab status # Should show all machines
|
||||||
|
lab deploy sleeper-service # Should work with sma user
|
||||||
|
|
||||||
|
# Test deploy-rs
|
||||||
|
lab deploy-rs sleeper-service --dry-run
|
||||||
|
```
|
||||||
|
|
||||||
|
## Implementation Status
|
||||||
|
|
||||||
|
- ✅ SSH keys configured for sma user on all machines
|
||||||
|
- ✅ Lab tool updated to use sma user for all operations
|
||||||
|
- ✅ Deploy-rs configuration updated to use sma user
|
||||||
|
- ✅ SSH client configuration updated with proper host patterns
|
||||||
|
- 📋 Ready for testing and validation
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
1. Test SSH connectivity from both machines to all targets
|
||||||
|
2. Validate lab tool deployment commands
|
||||||
|
3. Test deploy-rs functionality with sma user
|
||||||
|
4. Update any remaining scripts that might use old SSH patterns
|
201
dotfiles/geir/emacs-config/init-nix.el
Normal file
201
dotfiles/geir/emacs-config/init-nix.el
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
;;; init.el --- Nix-integrated modular Emacs configuration -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
;; A Nix-integrated, modular Emacs configuration that leverages Nix-provided tools
|
||||||
|
;; and packages where possible, falling back to Emacs package manager only when needed.
|
||||||
|
;; Core setup: UI, Nix integration, modular loading
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
;; Performance optimizations
|
||||||
|
(setq gc-cons-threshold (* 50 1000 1000))
|
||||||
|
(add-hook 'emacs-startup-hook
|
||||||
|
(lambda ()
|
||||||
|
(setq gc-cons-threshold (* 2 1000 1000))
|
||||||
|
(let ((profile (getenv "EMACS_PROFILE")))
|
||||||
|
(message "Emacs loaded in %s with %d garbage collections (Profile: %s)."
|
||||||
|
(format "%.2f seconds"
|
||||||
|
(float-time
|
||||||
|
(time-subtract after-init-time before-init-time)))
|
||||||
|
gcs-done
|
||||||
|
(or profile "unknown")))))
|
||||||
|
|
||||||
|
;; Basic UI setup - minimal but pleasant
|
||||||
|
(setq inhibit-startup-screen t)
|
||||||
|
(menu-bar-mode -1)
|
||||||
|
(when (fboundp 'tool-bar-mode) (tool-bar-mode -1))
|
||||||
|
(when (fboundp 'scroll-bar-mode) (scroll-bar-mode -1))
|
||||||
|
(set-face-attribute 'default nil :height 140)
|
||||||
|
(setq-default cursor-type 'bar)
|
||||||
|
|
||||||
|
;; Nix Integration Setup
|
||||||
|
;; Configure Emacs to use Nix-provided tools when available
|
||||||
|
(defun nix-tool-path (tool-name)
|
||||||
|
"Get the path to TOOL-NAME from Nix environment variables."
|
||||||
|
(let ((env-var (concat (upcase tool-name) "_PATH")))
|
||||||
|
(getenv env-var)))
|
||||||
|
|
||||||
|
;; Configure external tools to use Nix-provided binaries
|
||||||
|
(when-let ((rg-path (nix-tool-path "rg")))
|
||||||
|
(setq consult-ripgrep-command rg-path))
|
||||||
|
|
||||||
|
(when-let ((ag-path (nix-tool-path "ag")))
|
||||||
|
(setq ag-executable ag-path))
|
||||||
|
|
||||||
|
(when-let ((fd-path (nix-tool-path "fd")))
|
||||||
|
(setq find-program fd-path))
|
||||||
|
|
||||||
|
(when-let ((sqlite-path (nix-tool-path "sqlite")))
|
||||||
|
(setq org-roam-database-connector 'sqlite3)
|
||||||
|
(setq org-roam-db-executable sqlite-path))
|
||||||
|
|
||||||
|
;; Language Server Configuration (for Nix-provided LSP servers)
|
||||||
|
(defun configure-nix-lsp-servers ()
|
||||||
|
"Configure LSP to use Nix-provided language servers."
|
||||||
|
(when (featurep 'lsp-mode)
|
||||||
|
;; Nix LSP server
|
||||||
|
(when-let ((nil-path (nix-tool-path "nil_lsp")))
|
||||||
|
(setq lsp-nix-nil-server-path nil-path))
|
||||||
|
|
||||||
|
;; Bash LSP server
|
||||||
|
(when-let ((bash-lsp-path (nix-tool-path "bash_lsp")))
|
||||||
|
(setq lsp-bash-language-server-path bash-lsp-path))
|
||||||
|
|
||||||
|
;; YAML LSP server
|
||||||
|
(when-let ((yaml-lsp-path (nix-tool-path "yaml_lsp")))
|
||||||
|
(setq lsp-yaml-language-server-path yaml-lsp-path))))
|
||||||
|
|
||||||
|
;; Configure format-all to use Nix-provided formatters
|
||||||
|
(defun configure-nix-formatters ()
|
||||||
|
"Configure format-all to use Nix-provided formatters."
|
||||||
|
(when (featurep 'format-all)
|
||||||
|
;; Shellcheck for shell scripts
|
||||||
|
(when-let ((shellcheck-path (nix-tool-path "shellcheck")))
|
||||||
|
(setq format-all-formatters
|
||||||
|
(cons `(sh (shellcheck ,shellcheck-path))
|
||||||
|
format-all-formatters)))))
|
||||||
|
|
||||||
|
;; Package management setup
|
||||||
|
;; Note: With Nix integration, we rely less on package.el
|
||||||
|
;; Most packages come pre-installed via the flake
|
||||||
|
(require 'package)
|
||||||
|
(setq package-archives
|
||||||
|
'(("melpa" . "https://melpa.org/packages/")
|
||||||
|
("gnu" . "https://elpa.gnu.org/packages/")))
|
||||||
|
|
||||||
|
;; Only initialize package.el if we're not in a Nix environment
|
||||||
|
;; In Nix environments, packages are pre-installed
|
||||||
|
(unless (getenv "EMACS_PROFILE")
|
||||||
|
(package-initialize)
|
||||||
|
|
||||||
|
;; Install use-package for non-Nix environments
|
||||||
|
(unless (package-installed-p 'use-package)
|
||||||
|
(package-refresh-contents)
|
||||||
|
(package-install 'use-package)))
|
||||||
|
|
||||||
|
;; Configure use-package for Nix integration
|
||||||
|
(require 'use-package)
|
||||||
|
;; Don't auto-install packages in Nix environment - they're pre-provided
|
||||||
|
(setq use-package-always-ensure (not (getenv "EMACS_PROFILE")))
|
||||||
|
|
||||||
|
;; Essential packages that should be available in all profiles
|
||||||
|
(use-package exec-path-from-shell
|
||||||
|
:if (memq window-system '(mac ns x))
|
||||||
|
:config
|
||||||
|
(exec-path-from-shell-initialize)
|
||||||
|
;; Ensure Nix environment is properly inherited
|
||||||
|
(exec-path-from-shell-copy-envs '("NIX_PATH" "NIX_EMACS_PROFILE")))
|
||||||
|
|
||||||
|
(use-package diminish)
|
||||||
|
(use-package bind-key)
|
||||||
|
|
||||||
|
;; Basic editing improvements
|
||||||
|
(use-package which-key
|
||||||
|
:config
|
||||||
|
(which-key-mode 1))
|
||||||
|
|
||||||
|
;; Load profile-specific configuration based on Nix profile
|
||||||
|
(defun load-profile-config ()
|
||||||
|
"Load configuration specific to the current Nix profile."
|
||||||
|
(let ((profile (getenv "EMACS_PROFILE")))
|
||||||
|
(pcase profile
|
||||||
|
("server"
|
||||||
|
(message "Loading minimal server configuration...")
|
||||||
|
;; Minimal config - only essential features
|
||||||
|
(setq gc-cons-threshold (* 2 1000 1000))) ; Lower memory usage
|
||||||
|
|
||||||
|
("laptop"
|
||||||
|
(message "Loading laptop development configuration...")
|
||||||
|
;; Laptop config - balanced features
|
||||||
|
(setq auto-save-timeout 30) ; More frequent saves
|
||||||
|
(setq lsp-idle-delay 0.3)) ; Moderate LSP responsiveness
|
||||||
|
|
||||||
|
("workstation"
|
||||||
|
(message "Loading workstation configuration...")
|
||||||
|
;; Workstation config - maximum performance
|
||||||
|
(setq gc-cons-threshold (* 50 1000 1000)) ; Higher performance
|
||||||
|
(setq lsp-idle-delay 0.1)) ; Fastest LSP response
|
||||||
|
|
||||||
|
(_
|
||||||
|
(message "Loading default configuration...")))))
|
||||||
|
|
||||||
|
;; Apply profile-specific settings
|
||||||
|
(load-profile-config)
|
||||||
|
|
||||||
|
;; Configure Nix integration after packages are loaded
|
||||||
|
(add-hook 'after-init-hook #'configure-nix-lsp-servers)
|
||||||
|
(add-hook 'after-init-hook #'configure-nix-formatters)
|
||||||
|
|
||||||
|
;; Org mode basic setup (always included)
|
||||||
|
(use-package org
|
||||||
|
:config
|
||||||
|
(setq org-startup-indented t)
|
||||||
|
(setq org-hide-emphasis-markers t))
|
||||||
|
|
||||||
|
;; Module loading system
|
||||||
|
;; Load modules based on availability and profile
|
||||||
|
(defvar my-modules-dir
|
||||||
|
(expand-file-name "modules/" user-emacs-directory)
|
||||||
|
"Directory containing modular configuration files.")
|
||||||
|
|
||||||
|
(defun load-module (module-name)
|
||||||
|
"Load MODULE-NAME from the modules directory."
|
||||||
|
(let ((module-file (expand-file-name (concat module-name ".el") my-modules-dir)))
|
||||||
|
(when (file-exists-p module-file)
|
||||||
|
(load-file module-file)
|
||||||
|
(message "Loaded module: %s" module-name))))
|
||||||
|
|
||||||
|
;; Load modules based on profile
|
||||||
|
(let ((profile (getenv "EMACS_PROFILE")))
|
||||||
|
(pcase profile
|
||||||
|
("server"
|
||||||
|
;; Minimal modules for server
|
||||||
|
(load-module "ui"))
|
||||||
|
|
||||||
|
((or "laptop" "workstation")
|
||||||
|
;; Full module set for development machines
|
||||||
|
(load-module "ui")
|
||||||
|
(load-module "completion")
|
||||||
|
(load-module "navigation")
|
||||||
|
(load-module "development")
|
||||||
|
(load-module "elisp-development")
|
||||||
|
(when (string= profile "workstation")
|
||||||
|
(load-module "claude-code")))
|
||||||
|
|
||||||
|
(_
|
||||||
|
;; Default module loading (non-Nix environment)
|
||||||
|
(load-module "ui")
|
||||||
|
(load-module "completion")
|
||||||
|
(load-module "navigation"))))
|
||||||
|
|
||||||
|
;; Display startup information
|
||||||
|
(add-hook 'emacs-startup-hook
|
||||||
|
(lambda ()
|
||||||
|
(let ((profile (getenv "EMACS_PROFILE")))
|
||||||
|
(message "=== Emacs Ready ===")
|
||||||
|
(message "Profile: %s" (or profile "default"))
|
||||||
|
(message "Nix Integration: %s" (if profile "enabled" "disabled"))
|
||||||
|
(message "Modules loaded based on profile")
|
||||||
|
(message "==================="))))
|
||||||
|
|
||||||
|
;;; init.el ends here
|
126
dotfiles/geir/emacs-config/modules/claude-code.el
Normal file
126
dotfiles/geir/emacs-config/modules/claude-code.el
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
;;; claude-code.el --- Claude Code CLI integration module -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
;; Integration with Claude Code CLI for AI-assisted coding directly in Emacs
|
||||||
|
;; Provides terminal interface and commands for interacting with Claude AI
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
;; Install claude-code via quelpa if not already installed
|
||||||
|
(unless (package-installed-p 'claude-code)
|
||||||
|
(quelpa '(claude-code :fetcher github :repo "stevemolitor/claude-code.el")))
|
||||||
|
|
||||||
|
;; Claude Code - AI assistant integration
|
||||||
|
(use-package claude-code
|
||||||
|
:ensure nil ; Already installed via quelpa
|
||||||
|
:bind-keymap ("C-c C-c" . claude-code-command-map)
|
||||||
|
:bind (("C-c C-c c" . claude-code)
|
||||||
|
("C-c C-c s" . claude-code-send-command)
|
||||||
|
("C-c C-c r" . claude-code-send-region)
|
||||||
|
("C-c C-c b" . claude-code-send-buffer)
|
||||||
|
("C-c C-c e" . claude-code-fix-error-at-point)
|
||||||
|
("C-c C-c t" . claude-code-toggle)
|
||||||
|
("C-c C-c k" . claude-code-kill)
|
||||||
|
("C-c C-c n" . claude-code-new))
|
||||||
|
:custom
|
||||||
|
;; Terminal backend preference (eat is now installed via quelpa)
|
||||||
|
(claude-code-terminal-type 'eat)
|
||||||
|
|
||||||
|
;; Enable desktop notifications
|
||||||
|
(claude-code-notifications t)
|
||||||
|
|
||||||
|
;; Startup delay to ensure proper initialization
|
||||||
|
(claude-code-startup-delay 1.0)
|
||||||
|
|
||||||
|
;; Confirm before killing Claude sessions
|
||||||
|
(claude-code-confirm-kill t)
|
||||||
|
|
||||||
|
;; Use modern keybinding style
|
||||||
|
(claude-code-newline-and-send-style 'modern)
|
||||||
|
|
||||||
|
:config
|
||||||
|
;; Smart terminal detection - eat should be available via quelpa
|
||||||
|
(defun claude-code-detect-best-terminal ()
|
||||||
|
"Detect the best available terminal for Claude Code."
|
||||||
|
(cond
|
||||||
|
((package-installed-p 'eat) 'eat)
|
||||||
|
((and (package-installed-p 'vterm)
|
||||||
|
(or (executable-find "cmake")
|
||||||
|
(file-exists-p "/usr/bin/cmake")
|
||||||
|
(file-exists-p "/nix/store/*/bin/cmake")))
|
||||||
|
'vterm)
|
||||||
|
(t 'eat))) ; fallback to eat, should be installed
|
||||||
|
|
||||||
|
;; Set terminal type based on detection
|
||||||
|
(setq claude-code-terminal-type (claude-code-detect-best-terminal))
|
||||||
|
|
||||||
|
;; Auto-start Claude in project root when opening coding files
|
||||||
|
(defun claude-code-auto-start-maybe ()
|
||||||
|
"Auto-start Claude Code if in a project and not already running."
|
||||||
|
(when (and (derived-mode-p 'prog-mode)
|
||||||
|
(project-current)
|
||||||
|
(not (claude-code-running-p)))
|
||||||
|
(claude-code)))
|
||||||
|
|
||||||
|
;; Optional: Auto-start when opening programming files
|
||||||
|
;; Uncomment the next line if you want this behavior
|
||||||
|
;; (add-hook 'prog-mode-hook #'claude-code-auto-start-maybe)
|
||||||
|
|
||||||
|
;; Add helpful message about Claude Code setup
|
||||||
|
(message "Claude Code module loaded. Use C-c C-c c to start Claude, C-c C-c h for help"))
|
||||||
|
|
||||||
|
;; Terminal emulator for Claude Code (eat installed via quelpa in init.el)
|
||||||
|
(use-package eat
|
||||||
|
:ensure nil ; Already installed via quelpa
|
||||||
|
:custom
|
||||||
|
(eat-term-name "xterm-256color")
|
||||||
|
(eat-kill-buffer-on-exit t))
|
||||||
|
|
||||||
|
;; Alternative terminal emulator (if eat fails or user prefers vterm)
|
||||||
|
(use-package vterm
|
||||||
|
:if (and (not (package-installed-p 'eat))
|
||||||
|
(executable-find "cmake"))
|
||||||
|
:custom
|
||||||
|
(vterm-always-compile-module t)
|
||||||
|
(vterm-kill-buffer-on-exit t)
|
||||||
|
(vterm-max-scrollback 10000))
|
||||||
|
|
||||||
|
;; Transient dependency for command menus
|
||||||
|
(use-package transient
|
||||||
|
:ensure t)
|
||||||
|
|
||||||
|
;; Enhanced error handling for Claude Code integration
|
||||||
|
(defun claude-code-send-error-context ()
|
||||||
|
"Send error at point with surrounding context to Claude."
|
||||||
|
(interactive)
|
||||||
|
(if (claude-code-running-p)
|
||||||
|
(let* ((error-line (line-number-at-pos))
|
||||||
|
(start (max 1 (- error-line 5)))
|
||||||
|
(end (min (line-number-at-pos (point-max)) (+ error-line 5)))
|
||||||
|
(context (buffer-substring-no-properties
|
||||||
|
(line-beginning-position (- start error-line))
|
||||||
|
(line-end-position (- end error-line)))))
|
||||||
|
(claude-code-send-command
|
||||||
|
(format "I'm getting an error around line %d. Here's the context:\n\n```%s\n%s\n```\n\nCan you help me fix this?"
|
||||||
|
error-line
|
||||||
|
(or (file-name-extension (buffer-file-name)) "")
|
||||||
|
context)))
|
||||||
|
(message "Claude Code is not running. Start it with C-c C-c c")))
|
||||||
|
|
||||||
|
;; Keybinding for enhanced error context
|
||||||
|
(global-set-key (kbd "C-c C-c x") #'claude-code-send-error-context)
|
||||||
|
|
||||||
|
;; Project-aware Claude instances
|
||||||
|
(defun claude-code-project-instance ()
|
||||||
|
"Start or switch to Claude instance for current project."
|
||||||
|
(interactive)
|
||||||
|
(if-let ((project (project-current)))
|
||||||
|
(let ((default-directory (project-root project)))
|
||||||
|
(claude-code))
|
||||||
|
(claude-code)))
|
||||||
|
|
||||||
|
;; Keybinding for project-specific Claude
|
||||||
|
(global-set-key (kbd "C-c C-c p") #'claude-code-project-instance)
|
||||||
|
|
||||||
|
(provide 'claude-code)
|
||||||
|
;;; claude-code.el ends here
|
55
dotfiles/geir/emacs-config/modules/completion.el
Normal file
55
dotfiles/geir/emacs-config/modules/completion.el
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
;;; completion.el --- Completion framework configuration -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
;; Modern completion with Vertico, Consult, and Corfu
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
;; Vertico - vertical completion UI
|
||||||
|
(use-package vertico
|
||||||
|
:init
|
||||||
|
(vertico-mode)
|
||||||
|
:custom
|
||||||
|
(vertico-cycle t))
|
||||||
|
|
||||||
|
;; Marginalia - rich annotations in minibuffer
|
||||||
|
(use-package marginalia
|
||||||
|
:init
|
||||||
|
(marginalia-mode))
|
||||||
|
|
||||||
|
;; Consult - enhanced search and navigation commands
|
||||||
|
(use-package consult
|
||||||
|
:bind (("C-s" . consult-line)
|
||||||
|
("C-x b" . consult-buffer)
|
||||||
|
("C-x 4 b" . consult-buffer-other-window)
|
||||||
|
("C-x 5 b" . consult-buffer-other-frame)
|
||||||
|
("M-y" . consult-yank-pop)
|
||||||
|
("M-g g" . consult-goto-line)
|
||||||
|
("M-g M-g" . consult-goto-line)
|
||||||
|
("C-x r b" . consult-bookmark)))
|
||||||
|
|
||||||
|
;; Orderless - flexible completion style
|
||||||
|
(use-package orderless
|
||||||
|
:custom
|
||||||
|
(completion-styles '(orderless basic))
|
||||||
|
(completion-category-defaults nil)
|
||||||
|
(completion-category-overrides '((file (styles partial-completion)))))
|
||||||
|
|
||||||
|
;; Corfu - in-buffer completion popup
|
||||||
|
(use-package corfu
|
||||||
|
:custom
|
||||||
|
(corfu-cycle t)
|
||||||
|
(corfu-auto t)
|
||||||
|
(corfu-auto-delay 0.2)
|
||||||
|
(corfu-auto-prefix 2)
|
||||||
|
:init
|
||||||
|
(global-corfu-mode))
|
||||||
|
|
||||||
|
;; Cape - completion at point extensions
|
||||||
|
(use-package cape
|
||||||
|
:init
|
||||||
|
(add-to-list 'completion-at-point-functions #'cape-dabbrev)
|
||||||
|
(add-to-list 'completion-at-point-functions #'cape-file))
|
||||||
|
|
||||||
|
(provide 'completion)
|
||||||
|
;;; completion.el ends here
|
40
dotfiles/geir/emacs-config/modules/development.el
Normal file
40
dotfiles/geir/emacs-config/modules/development.el
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
;;; development.el --- Development tools configuration -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
;; LSP, Copilot, and other development tools
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
;; LSP Mode
|
||||||
|
(use-package lsp-mode
|
||||||
|
:hook ((prog-mode . lsp-deferred))
|
||||||
|
:commands (lsp lsp-deferred)
|
||||||
|
:custom
|
||||||
|
(lsp-keymap-prefix "C-c l")
|
||||||
|
(lsp-idle-delay 0.5)
|
||||||
|
(lsp-log-io nil)
|
||||||
|
(lsp-completion-provider :none) ; Use corfu instead
|
||||||
|
:config
|
||||||
|
(lsp-enable-which-key-integration t))
|
||||||
|
|
||||||
|
;; LSP UI
|
||||||
|
(use-package lsp-ui
|
||||||
|
:after lsp-mode
|
||||||
|
:custom
|
||||||
|
(lsp-ui-doc-enable t)
|
||||||
|
(lsp-ui-doc-position 'bottom)
|
||||||
|
(lsp-ui-sideline-enable t)
|
||||||
|
(lsp-ui-sideline-show-hover nil))
|
||||||
|
|
||||||
|
;; Which Key - helpful for discovering keybindings
|
||||||
|
(use-package which-key
|
||||||
|
:config
|
||||||
|
(which-key-mode 1)
|
||||||
|
(setq which-key-idle-delay 0.3))
|
||||||
|
|
||||||
|
;; Magit - Git interface
|
||||||
|
(use-package magit
|
||||||
|
:bind ("C-x g" . magit-status))
|
||||||
|
|
||||||
|
(provide 'development)
|
||||||
|
;;; development.el ends here
|
164
dotfiles/geir/emacs-config/modules/elisp-development.el
Normal file
164
dotfiles/geir/emacs-config/modules/elisp-development.el
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
;;; elisp-development.el --- Enhanced Emacs Lisp development setup -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
;; Specialized configuration for Emacs Lisp development
|
||||||
|
;; This module provides enhanced development tools specifically for .el files
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
;; Enhanced Emacs Lisp mode with better defaults
|
||||||
|
(use-package elisp-mode
|
||||||
|
:ensure nil ; Built-in package
|
||||||
|
:mode "\\.el\\'"
|
||||||
|
:hook ((emacs-lisp-mode . eldoc-mode)
|
||||||
|
(emacs-lisp-mode . show-paren-mode)
|
||||||
|
(emacs-lisp-mode . electric-pair-mode))
|
||||||
|
:bind (:map emacs-lisp-mode-map
|
||||||
|
("C-c C-e" . eval-last-sexp)
|
||||||
|
("C-c C-b" . eval-buffer)
|
||||||
|
("C-c C-r" . eval-region)
|
||||||
|
("C-c C-d" . describe-function-at-point))
|
||||||
|
:config
|
||||||
|
;; Better indentation
|
||||||
|
(setq lisp-indent-function 'lisp-indent-function)
|
||||||
|
|
||||||
|
;; Show function signatures in minibuffer
|
||||||
|
(eldoc-mode 1))
|
||||||
|
|
||||||
|
;; Enhanced Elisp navigation
|
||||||
|
(use-package elisp-slime-nav
|
||||||
|
:hook (emacs-lisp-mode . elisp-slime-nav-mode)
|
||||||
|
:bind (:map elisp-slime-nav-mode-map
|
||||||
|
("M-." . elisp-slime-nav-find-elisp-thing-at-point)
|
||||||
|
("M-," . pop-tag-mark)))
|
||||||
|
|
||||||
|
;; Better parentheses handling
|
||||||
|
(use-package smartparens
|
||||||
|
:hook (emacs-lisp-mode . smartparens-strict-mode)
|
||||||
|
:config
|
||||||
|
(require 'smartparens-config)
|
||||||
|
(sp-local-pair 'emacs-lisp-mode "'" nil :actions nil)
|
||||||
|
(sp-local-pair 'emacs-lisp-mode "`" nil :actions nil))
|
||||||
|
|
||||||
|
;; Rainbow delimiters for better paren visibility
|
||||||
|
(use-package rainbow-delimiters
|
||||||
|
:hook (emacs-lisp-mode . rainbow-delimiters-mode))
|
||||||
|
|
||||||
|
;; Aggressive indentation
|
||||||
|
(use-package aggressive-indent
|
||||||
|
:hook (emacs-lisp-mode . aggressive-indent-mode))
|
||||||
|
|
||||||
|
;; Enhanced help and documentation
|
||||||
|
(use-package helpful
|
||||||
|
:bind (("C-h f" . helpful-callable)
|
||||||
|
("C-h v" . helpful-variable)
|
||||||
|
("C-h k" . helpful-key)
|
||||||
|
("C-h x" . helpful-command)
|
||||||
|
("C-h ." . helpful-at-point)))
|
||||||
|
|
||||||
|
;; Live examples for Elisp functions
|
||||||
|
(use-package elisp-demos
|
||||||
|
:after helpful
|
||||||
|
:config
|
||||||
|
(advice-add 'helpful-update :after #'elisp-demos-advice-helpful-update))
|
||||||
|
|
||||||
|
;; Package linting
|
||||||
|
(use-package package-lint
|
||||||
|
:commands package-lint-current-buffer)
|
||||||
|
|
||||||
|
;; Flycheck for syntax checking
|
||||||
|
(use-package flycheck
|
||||||
|
:hook (emacs-lisp-mode . flycheck-mode)
|
||||||
|
:config
|
||||||
|
;; Enhanced Emacs Lisp checking
|
||||||
|
(setq flycheck-emacs-lisp-load-path 'inherit))
|
||||||
|
|
||||||
|
;; Checkdoc for documentation linting
|
||||||
|
(use-package checkdoc
|
||||||
|
:ensure nil ; Built-in
|
||||||
|
:commands checkdoc)
|
||||||
|
|
||||||
|
;; Enhanced debugging
|
||||||
|
(use-package edebug
|
||||||
|
:ensure nil ; Built-in
|
||||||
|
:bind (:map emacs-lisp-mode-map
|
||||||
|
("C-c C-x C-d" . edebug-defun)
|
||||||
|
("C-c C-x C-b" . edebug-set-breakpoint)))
|
||||||
|
|
||||||
|
;; Package development helpers
|
||||||
|
(use-package auto-compile
|
||||||
|
:config
|
||||||
|
(auto-compile-on-load-mode)
|
||||||
|
(auto-compile-on-save-mode))
|
||||||
|
|
||||||
|
;; Enhanced REPL interaction
|
||||||
|
(use-package ielm
|
||||||
|
:ensure nil ; Built-in
|
||||||
|
:bind ("C-c C-z" . ielm)
|
||||||
|
:config
|
||||||
|
(add-hook 'ielm-mode-hook 'eldoc-mode))
|
||||||
|
|
||||||
|
;; Highlight defined functions and variables
|
||||||
|
(use-package highlight-defined
|
||||||
|
:hook (emacs-lisp-mode . highlight-defined-mode))
|
||||||
|
|
||||||
|
;; Better search and replace for symbols
|
||||||
|
(use-package expand-region
|
||||||
|
:bind ("C-=" . er/expand-region))
|
||||||
|
|
||||||
|
;; Multiple cursors for batch editing
|
||||||
|
(use-package multiple-cursors
|
||||||
|
:bind (("C-S-c C-S-c" . mc/edit-lines)
|
||||||
|
("C->" . mc/mark-next-like-this)
|
||||||
|
("C-<" . mc/mark-previous-like-this)))
|
||||||
|
|
||||||
|
;; Custom functions for Elisp development
|
||||||
|
(defun elisp-eval-and-replace ()
|
||||||
|
"Evaluate the sexp at point and replace it with its value."
|
||||||
|
(interactive)
|
||||||
|
(backward-kill-sexp)
|
||||||
|
(condition-case nil
|
||||||
|
(prin1 (eval (read (current-kill 0)))
|
||||||
|
(current-buffer))
|
||||||
|
(error (message "Invalid expression")
|
||||||
|
(insert (current-kill 0)))))
|
||||||
|
|
||||||
|
(defun elisp-describe-thing-at-point ()
|
||||||
|
"Show the documentation for the thing at point."
|
||||||
|
(interactive)
|
||||||
|
(let ((thing (symbol-at-point)))
|
||||||
|
(cond
|
||||||
|
((fboundp thing) (describe-function thing))
|
||||||
|
((boundp thing) (describe-variable thing))
|
||||||
|
(t (message "No documentation found for %s" thing)))))
|
||||||
|
|
||||||
|
;; Key bindings for custom functions
|
||||||
|
(define-key emacs-lisp-mode-map (kbd "C-c C-x C-e") 'elisp-eval-and-replace)
|
||||||
|
(define-key emacs-lisp-mode-map (kbd "C-c C-d") 'elisp-describe-thing-at-point)
|
||||||
|
|
||||||
|
;; Project-specific configurations
|
||||||
|
(defun setup-elisp-project ()
|
||||||
|
"Set up development environment for Elisp projects."
|
||||||
|
(interactive)
|
||||||
|
(when (and buffer-file-name
|
||||||
|
(string-match "\\.el\\'" buffer-file-name))
|
||||||
|
;; Add current directory to load-path for local requires
|
||||||
|
(add-to-list 'load-path (file-name-directory buffer-file-name))
|
||||||
|
|
||||||
|
;; Set up package development if this looks like a package
|
||||||
|
(when (or (file-exists-p "Cask")
|
||||||
|
(file-exists-p "Eask")
|
||||||
|
(string-match "-pkg\\.el\\'" buffer-file-name))
|
||||||
|
(message "Elisp package development mode enabled"))))
|
||||||
|
|
||||||
|
(add-hook 'emacs-lisp-mode-hook 'setup-elisp-project)
|
||||||
|
|
||||||
|
;; Better compilation output
|
||||||
|
(add-hook 'emacs-lisp-mode-hook
|
||||||
|
(lambda ()
|
||||||
|
(setq-local compile-command
|
||||||
|
(format "emacs -batch -f batch-byte-compile %s"
|
||||||
|
(shell-quote-argument buffer-file-name)))))
|
||||||
|
|
||||||
|
(provide 'elisp-development)
|
||||||
|
;;; elisp-development.el ends here
|
51
dotfiles/geir/emacs-config/modules/navigation.el
Normal file
51
dotfiles/geir/emacs-config/modules/navigation.el
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
;;; navigation.el --- Navigation and file management -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
;; File navigation, project management, and window management
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
;; Dired improvements
|
||||||
|
(use-package dired
|
||||||
|
:ensure nil
|
||||||
|
:custom
|
||||||
|
(dired-listing-switches "-alhF")
|
||||||
|
(dired-dwim-target t)
|
||||||
|
:config
|
||||||
|
(put 'dired-find-alternate-file 'disabled nil))
|
||||||
|
|
||||||
|
;; Project management
|
||||||
|
(use-package projectile
|
||||||
|
:config
|
||||||
|
(projectile-mode +1)
|
||||||
|
:bind-keymap
|
||||||
|
("C-c p" . projectile-command-map)
|
||||||
|
:custom
|
||||||
|
(projectile-completion-system 'default))
|
||||||
|
|
||||||
|
;; Treemacs - file tree
|
||||||
|
(use-package treemacs
|
||||||
|
:bind (("M-0" . treemacs-select-window)
|
||||||
|
("C-x t 1" . treemacs-delete-other-windows)
|
||||||
|
("C-x t t" . treemacs)
|
||||||
|
("C-x t d" . treemacs-select-directory)
|
||||||
|
("C-x t B" . treemacs-bookmark)
|
||||||
|
("C-x t C-t" . treemacs-find-file)
|
||||||
|
("C-x t M-t" . treemacs-find-tag))
|
||||||
|
:custom
|
||||||
|
(treemacs-width 30))
|
||||||
|
|
||||||
|
;; Ace Window - quick window switching
|
||||||
|
(use-package ace-window
|
||||||
|
:bind ("M-o" . ace-window)
|
||||||
|
:custom
|
||||||
|
(aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)))
|
||||||
|
|
||||||
|
;; Winner mode - window configuration undo/redo
|
||||||
|
(use-package winner
|
||||||
|
:ensure nil
|
||||||
|
:config
|
||||||
|
(winner-mode 1))
|
||||||
|
|
||||||
|
(provide 'navigation)
|
||||||
|
;;; navigation.el ends here
|
32
dotfiles/geir/emacs-config/modules/ui.el
Normal file
32
dotfiles/geir/emacs-config/modules/ui.el
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
;;; ui.el --- UI configuration module -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
;; Enhanced UI configuration - themes, modeline, icons
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
;; Doom themes
|
||||||
|
(use-package doom-themes
|
||||||
|
:config
|
||||||
|
(load-theme 'doom-monokai-pro t)
|
||||||
|
(doom-themes-visual-bell-config)
|
||||||
|
(doom-themes-org-config))
|
||||||
|
|
||||||
|
;; Doom modeline
|
||||||
|
(use-package doom-modeline
|
||||||
|
:init (doom-modeline-mode 1)
|
||||||
|
:custom
|
||||||
|
(doom-modeline-height 15)
|
||||||
|
(doom-modeline-icon t)
|
||||||
|
(doom-modeline-buffer-file-name-style 'truncate-with-project))
|
||||||
|
|
||||||
|
;; All the icons
|
||||||
|
(use-package all-the-icons
|
||||||
|
:if (display-graphic-p)
|
||||||
|
:config
|
||||||
|
;; Install fonts if not already done
|
||||||
|
(unless (find-font (font-spec :name "all-the-icons"))
|
||||||
|
(all-the-icons-install-fonts t)))
|
||||||
|
|
||||||
|
(provide 'ui)
|
||||||
|
;;; ui.el ends here
|
6
flake.lock
generated
6
flake.lock
generated
|
@ -54,11 +54,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs-unstable": {
|
"nixpkgs-unstable": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1751011381,
|
"lastModified": 1751271578,
|
||||||
"narHash": "sha256-krGXKxvkBhnrSC/kGBmg5MyupUUT5R6IBCLEzx9jhMM=",
|
"narHash": "sha256-P/SQmKDu06x8yv7i0s8bvnnuJYkxVGBWLWHaU+tt4YY=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "30e2e2857ba47844aa71991daa6ed1fc678bcbb7",
|
"rev": "3016b4b15d13f3089db8a41ef937b13a9e33a8df",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
@ -261,7 +261,7 @@
|
||||||
profiles.system = {
|
profiles.system = {
|
||||||
user = "root";
|
user = "root";
|
||||||
path = deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.little-rascal;
|
path = deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.little-rascal;
|
||||||
sshUser = "geir";
|
sshUser = "sma";
|
||||||
sudo = "sudo -u";
|
sudo = "sudo -u";
|
||||||
autoRollback = true;
|
autoRollback = true;
|
||||||
magicRollback = true;
|
magicRollback = true;
|
||||||
|
|
|
@ -33,6 +33,10 @@
|
||||||
|
|
||||||
# Development tools
|
# Development tools
|
||||||
../../modules/development/tools.nix
|
../../modules/development/tools.nix
|
||||||
|
../../modules/development/emacs.nix
|
||||||
|
|
||||||
|
# Emacs with workstation profile
|
||||||
|
../../modules/development/emacs.nix
|
||||||
|
|
||||||
# AI tools
|
# AI tools
|
||||||
../../modules/ai/claude-code.nix
|
../../modules/ai/claude-code.nix
|
||||||
|
@ -61,6 +65,14 @@
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Emacs workstation configuration
|
||||||
|
services.emacs-profiles = {
|
||||||
|
enable = true;
|
||||||
|
profile = "workstation";
|
||||||
|
enableDaemon = true;
|
||||||
|
user = "geir";
|
||||||
|
};
|
||||||
|
|
||||||
# Enable clean seatd/greetd login
|
# Enable clean seatd/greetd login
|
||||||
services.seatd-clean.enable = true;
|
services.seatd-clean.enable = true;
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
../../modules/virtualization/incus.nix
|
../../modules/virtualization/incus.nix
|
||||||
../../modules/users/sma.nix
|
../../modules/users/sma.nix
|
||||||
|
|
||||||
|
# Development (minimal for services host)
|
||||||
|
../../modules/development/emacs.nix
|
||||||
|
|
||||||
# NFS client with ID mapping
|
# NFS client with ID mapping
|
||||||
../../modules/services/nfs-client.nix
|
../../modules/services/nfs-client.nix
|
||||||
|
|
||||||
|
@ -43,6 +46,14 @@
|
||||||
# Disks and Updates
|
# Disks and Updates
|
||||||
services.fstrim.enable = true;
|
services.fstrim.enable = true;
|
||||||
|
|
||||||
|
# Emacs server configuration (minimal for services host)
|
||||||
|
services.emacs-profiles = {
|
||||||
|
enable = true;
|
||||||
|
profile = "server";
|
||||||
|
enableDaemon = false;
|
||||||
|
user = "sma";
|
||||||
|
};
|
||||||
|
|
||||||
# Mount remote filesystem
|
# Mount remote filesystem
|
||||||
fileSystems."/mnt/remote/media" = {
|
fileSystems."/mnt/remote/media" = {
|
||||||
device = "sleeper-service:/mnt/storage/media";
|
device = "sleeper-service:/mnt/storage/media";
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
../../modules/common/base.nix
|
../../modules/common/base.nix
|
||||||
../../modules/common/nix.nix
|
../../modules/common/nix.nix
|
||||||
../../modules/common/tty.nix
|
../../modules/common/tty.nix
|
||||||
../../modules/common/emacs.nix
|
|
||||||
|
|
||||||
# Desktop
|
# Desktop
|
||||||
../../modules/desktop/niri.nix
|
../../modules/desktop/niri.nix
|
||||||
|
@ -25,6 +24,7 @@
|
||||||
|
|
||||||
# Development
|
# Development
|
||||||
../../modules/development/tools.nix
|
../../modules/development/tools.nix
|
||||||
|
../../modules/development/emacs.nix
|
||||||
../../modules/ai/claude-code.nix
|
../../modules/ai/claude-code.nix
|
||||||
|
|
||||||
# Users
|
# Users
|
||||||
|
@ -79,6 +79,14 @@
|
||||||
kernel.sysctl."vm.swappiness" = 180;
|
kernel.sysctl."vm.swappiness" = 180;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Emacs laptop configuration
|
||||||
|
services.emacs-profiles = {
|
||||||
|
enable = true;
|
||||||
|
profile = "laptop";
|
||||||
|
enableDaemon = true;
|
||||||
|
user = "geir";
|
||||||
|
};
|
||||||
|
|
||||||
# zram configuration
|
# zram configuration
|
||||||
zramSwap = {
|
zramSwap = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
../../modules/network/extraHosts.nix
|
../../modules/network/extraHosts.nix
|
||||||
../../modules/users/sma.nix
|
../../modules/users/sma.nix
|
||||||
../../modules/security/ssh-keys.nix
|
../../modules/security/ssh-keys.nix
|
||||||
|
|
||||||
|
# Development (minimal for edge server)
|
||||||
|
../../modules/development/emacs.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
|
@ -43,6 +46,14 @@
|
||||||
# Tailscale for secure management access
|
# Tailscale for secure management access
|
||||||
services.tailscale.enable = true;
|
services.tailscale.enable = true;
|
||||||
|
|
||||||
|
# Emacs server configuration (minimal for edge server)
|
||||||
|
services.emacs-profiles = {
|
||||||
|
enable = true;
|
||||||
|
profile = "server";
|
||||||
|
enableDaemon = false;
|
||||||
|
user = "sma";
|
||||||
|
};
|
||||||
|
|
||||||
# SSH configuration - temporarily simplified for testing
|
# SSH configuration - temporarily simplified for testing
|
||||||
services.openssh = {
|
services.openssh = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
{ config, lib, pkgs, inputs, unstable, ... }: {
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
inputs,
|
||||||
|
unstable,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
imports = [
|
imports = [
|
||||||
./hardware-configuration.nix
|
./hardware-configuration.nix
|
||||||
# Security modules
|
# Security modules
|
||||||
|
@ -10,6 +17,9 @@
|
||||||
./nfs.nix
|
./nfs.nix
|
||||||
./services/transmission.nix
|
./services/transmission.nix
|
||||||
|
|
||||||
|
# Development (minimal for server)
|
||||||
|
../../modules/development/emacs.nix
|
||||||
|
|
||||||
# User modules - server only needs sma user
|
# User modules - server only needs sma user
|
||||||
../../modules/users/sma.nix
|
../../modules/users/sma.nix
|
||||||
];
|
];
|
||||||
|
@ -20,25 +30,37 @@
|
||||||
zfsSupport = true;
|
zfsSupport = true;
|
||||||
efiSupport = true;
|
efiSupport = true;
|
||||||
efiInstallAsRemovable = true;
|
efiInstallAsRemovable = true;
|
||||||
mirroredBoots = [
|
mirroredBoots = [
|
||||||
{ devices = [ "nodev" ]; path = "/boot"; } ];
|
{
|
||||||
|
devices = ["nodev"];
|
||||||
|
path = "/boot";
|
||||||
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
boot.supportedFilesystems = [ "zfs" ];
|
boot.supportedFilesystems = ["zfs"];
|
||||||
boot.loader.grub.memtest86.enable = true;
|
boot.loader.grub.memtest86.enable = true;
|
||||||
|
|
||||||
# Add nomodeset for graphics compatibility
|
# Add nomodeset for graphics compatibility
|
||||||
boot.kernelParams = [ "nomodeset" ];
|
boot.kernelParams = ["nomodeset"];
|
||||||
|
|
||||||
# ZFS services for file server
|
# ZFS services for file server
|
||||||
services.zfs = {
|
services.zfs = {
|
||||||
autoScrub.enable = true;
|
autoScrub.enable = true;
|
||||||
trim.enable = true;
|
trim.enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Emacs server configuration (minimal)
|
||||||
|
services.emacs-profiles = {
|
||||||
|
enable = true;
|
||||||
|
profile = "server";
|
||||||
|
enableDaemon = false; # Don't run daemon on server
|
||||||
|
user = "sma";
|
||||||
|
};
|
||||||
|
|
||||||
# Enable ZFS auto-mounting since we're using ZFS native mountpoints
|
# Enable ZFS auto-mounting since we're using ZFS native mountpoints
|
||||||
# systemd.services.zfs-mount.enable = lib.mkForce false;
|
# systemd.services.zfs-mount.enable = lib.mkForce false;
|
||||||
|
|
||||||
# Disable graphics for server use - comment out NVIDIA config for now
|
# Disable graphics for server use - comment out NVIDIA config for now
|
||||||
# hardware.graphics = {
|
# hardware.graphics = {
|
||||||
# enable = true;
|
# enable = true;
|
||||||
|
@ -48,15 +70,15 @@
|
||||||
# open = false;
|
# open = false;
|
||||||
# package = config.boot.kernelPackages.nvidiaPackages.legacy_470;
|
# package = config.boot.kernelPackages.nvidiaPackages.legacy_470;
|
||||||
# };
|
# };
|
||||||
|
|
||||||
# Comment out NVIDIA kernel modules for now
|
# Comment out NVIDIA kernel modules for now
|
||||||
# boot.kernelModules = [ "nvidia" "nvidia_modeset" "nvidia_uvm" "nvidia_drm" ];
|
# boot.kernelModules = [ "nvidia" "nvidia_modeset" "nvidia_uvm" "nvidia_drm" ];
|
||||||
|
|
||||||
# Comment out NVIDIA utilities for now
|
# Comment out NVIDIA utilities for now
|
||||||
# environment.systemPackages = with pkgs; [
|
# environment.systemPackages = with pkgs; [
|
||||||
# config.boot.kernelPackages.nvidiaPackages.legacy_470
|
# config.boot.kernelPackages.nvidiaPackages.legacy_470
|
||||||
# ];
|
# ];
|
||||||
|
|
||||||
# Create mount directories early in boot process
|
# Create mount directories early in boot process
|
||||||
# systemd.tmpfiles.rules = [
|
# systemd.tmpfiles.rules = [
|
||||||
# "d /mnt/storage 0755 root root -"
|
# "d /mnt/storage 0755 root root -"
|
||||||
|
@ -93,4 +115,4 @@
|
||||||
|
|
||||||
# DO NOT CHANGE - maintains data compatibility
|
# DO NOT CHANGE - maintains data compatibility
|
||||||
system.stateVersion = "23.11";
|
system.stateVersion = "23.11";
|
||||||
}
|
}
|
||||||
|
|
285
modules/development/emacs.nix
Normal file
285
modules/development/emacs.nix
Normal file
|
@ -0,0 +1,285 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
with lib; let
|
||||||
|
cfg = config.services.emacs-profiles;
|
||||||
|
|
||||||
|
# Emacs package configurations for different profiles
|
||||||
|
packageSets = {
|
||||||
|
# Essential packages for all profiles
|
||||||
|
essential = epkgs:
|
||||||
|
with epkgs; [
|
||||||
|
use-package
|
||||||
|
diminish
|
||||||
|
bind-key
|
||||||
|
which-key
|
||||||
|
exec-path-from-shell # Critical for integrating with Nix environment
|
||||||
|
];
|
||||||
|
|
||||||
|
# Minimal packages for server profile
|
||||||
|
minimal = epkgs:
|
||||||
|
with epkgs; [
|
||||||
|
# Basic editing
|
||||||
|
smartparens
|
||||||
|
expand-region
|
||||||
|
|
||||||
|
# Essential navigation (pure Emacs, no external deps)
|
||||||
|
vertico
|
||||||
|
consult
|
||||||
|
marginalia
|
||||||
|
orderless
|
||||||
|
|
||||||
|
# Basic modes for config files
|
||||||
|
nix-mode # Essential for Nix ecosystem
|
||||||
|
yaml-mode
|
||||||
|
markdown-mode
|
||||||
|
|
||||||
|
# Org mode essentials
|
||||||
|
org
|
||||||
|
org-roam
|
||||||
|
];
|
||||||
|
|
||||||
|
# Development packages for laptop/workstation
|
||||||
|
development = epkgs:
|
||||||
|
with epkgs; [
|
||||||
|
# Advanced navigation and completion
|
||||||
|
vertico
|
||||||
|
consult
|
||||||
|
marginalia
|
||||||
|
orderless
|
||||||
|
embark
|
||||||
|
embark-consult
|
||||||
|
corfu
|
||||||
|
cape
|
||||||
|
|
||||||
|
# Project management
|
||||||
|
projectile
|
||||||
|
magit
|
||||||
|
forge
|
||||||
|
|
||||||
|
# Development tools
|
||||||
|
lsp-mode
|
||||||
|
lsp-ui
|
||||||
|
company
|
||||||
|
flycheck
|
||||||
|
yasnippet
|
||||||
|
|
||||||
|
# Language support
|
||||||
|
nix-mode
|
||||||
|
rust-mode
|
||||||
|
python-mode
|
||||||
|
typescript-mode
|
||||||
|
json-mode
|
||||||
|
yaml-mode
|
||||||
|
markdown-mode
|
||||||
|
|
||||||
|
# Org mode and knowledge management
|
||||||
|
org
|
||||||
|
org-roam
|
||||||
|
org-roam-ui
|
||||||
|
org-agenda
|
||||||
|
|
||||||
|
# UI enhancements
|
||||||
|
doom-themes
|
||||||
|
doom-modeline
|
||||||
|
all-the-icons
|
||||||
|
rainbow-delimiters
|
||||||
|
highlight-indent-guides
|
||||||
|
|
||||||
|
# Editing enhancements
|
||||||
|
smartparens
|
||||||
|
expand-region
|
||||||
|
multiple-cursors
|
||||||
|
avy
|
||||||
|
ace-window
|
||||||
|
|
||||||
|
# Terminal integration
|
||||||
|
vterm
|
||||||
|
eshell-git-prompt
|
||||||
|
];
|
||||||
|
|
||||||
|
# Full workstation packages
|
||||||
|
workstation = epkgs:
|
||||||
|
with epkgs; [
|
||||||
|
# All development packages plus extras
|
||||||
|
claude-code # AI assistance (when available)
|
||||||
|
pdf-tools
|
||||||
|
nov # EPUB reader
|
||||||
|
elfeed # RSS reader
|
||||||
|
mu4e # Email (if configured)
|
||||||
|
dired-sidebar
|
||||||
|
treemacs
|
||||||
|
treemacs-projectile
|
||||||
|
treemacs-magit
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Generate Emacs configuration based on profile
|
||||||
|
# Uses emacs-gtk to track upstream with GTK3 support for desktop profiles
|
||||||
|
# Uses emacs-nox for server profiles (no X11/GUI dependencies)
|
||||||
|
emacsWithProfile = profile: let
|
||||||
|
# Choose Emacs package based on profile
|
||||||
|
emacsPackage =
|
||||||
|
if profile == "server"
|
||||||
|
then pkgs.emacs-nox # No GUI for servers
|
||||||
|
else pkgs.emacs-gtk; # GTK3 for desktops
|
||||||
|
|
||||||
|
# Combine package sets based on profile
|
||||||
|
selectedPackages = epkgs:
|
||||||
|
(packageSets.essential epkgs)
|
||||||
|
++ (
|
||||||
|
if profile == "server"
|
||||||
|
then packageSets.minimal epkgs
|
||||||
|
else if profile == "laptop"
|
||||||
|
then packageSets.development epkgs
|
||||||
|
else if profile == "workstation"
|
||||||
|
then (packageSets.development epkgs) ++ (packageSets.workstation epkgs)
|
||||||
|
else packageSets.minimal epkgs
|
||||||
|
);
|
||||||
|
in
|
||||||
|
pkgs.emacsWithPackagesFromUsePackage {
|
||||||
|
config = builtins.readFile ../../dotfiles/geir/emacs-config/init-nix.el;
|
||||||
|
package = emacsPackage;
|
||||||
|
extraEmacsPackages = selectedPackages;
|
||||||
|
|
||||||
|
# Provide external tools that Emacs will use
|
||||||
|
# These will be available via environment variables
|
||||||
|
override = epkgs:
|
||||||
|
epkgs
|
||||||
|
// {
|
||||||
|
# External tools for Emacs integration
|
||||||
|
external-tools =
|
||||||
|
[
|
||||||
|
pkgs.ripgrep # for fast searching
|
||||||
|
pkgs.fd # for file finding
|
||||||
|
pkgs.sqlite # for org-roam database
|
||||||
|
pkgs.ag # the silver searcher
|
||||||
|
pkgs.git # version control
|
||||||
|
pkgs.direnv # environment management
|
||||||
|
|
||||||
|
# Language servers (when available)
|
||||||
|
pkgs.nixd # Nix language server
|
||||||
|
pkgs.nodePackages.bash-language-server
|
||||||
|
pkgs.nodePackages.yaml-language-server
|
||||||
|
pkgs.marksman # Markdown language server
|
||||||
|
|
||||||
|
# Formatters
|
||||||
|
pkgs.alejandra # Nix formatter
|
||||||
|
pkgs.shellcheck # Shell script analysis
|
||||||
|
pkgs.shfmt # Shell script formatter
|
||||||
|
]
|
||||||
|
++ lib.optionals (profile != "server") [
|
||||||
|
# Additional tools for development profiles
|
||||||
|
pkgs.nodejs # for various language servers
|
||||||
|
pkgs.python3 # for Python development
|
||||||
|
pkgs.rustup # Rust toolchain
|
||||||
|
pkgs.go # Go language
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
options.services.emacs-profiles = {
|
||||||
|
enable = mkEnableOption "Emacs with machine-specific profiles";
|
||||||
|
|
||||||
|
profile = mkOption {
|
||||||
|
type = types.enum ["server" "laptop" "workstation"];
|
||||||
|
default = "laptop";
|
||||||
|
description = "Emacs profile to use based on machine type";
|
||||||
|
};
|
||||||
|
|
||||||
|
enableDaemon = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Enable Emacs daemon service";
|
||||||
|
};
|
||||||
|
|
||||||
|
user = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "geir";
|
||||||
|
description = "User to run Emacs daemon for";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
# Install Emacs with the selected profile
|
||||||
|
environment.systemPackages = [
|
||||||
|
(emacsWithProfile cfg.profile)
|
||||||
|
];
|
||||||
|
|
||||||
|
# System-wide Emacs daemon (optional)
|
||||||
|
services.emacs = mkIf cfg.enableDaemon {
|
||||||
|
enable = true;
|
||||||
|
package = emacsWithProfile cfg.profile;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Create the Emacs configuration directory structure
|
||||||
|
environment.etc = {
|
||||||
|
"emacs/init.el" = {
|
||||||
|
source = ../../dotfiles/geir/emacs-config/init-nix.el;
|
||||||
|
mode = "0644";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Module files
|
||||||
|
"emacs/modules/ui.el" = {
|
||||||
|
source = ../../dotfiles/geir/emacs-config/modules/ui.el;
|
||||||
|
mode = "0644";
|
||||||
|
};
|
||||||
|
|
||||||
|
"emacs/modules/completion.el" = {
|
||||||
|
source = ../../dotfiles/geir/emacs-config/modules/completion.el;
|
||||||
|
mode = "0644";
|
||||||
|
};
|
||||||
|
|
||||||
|
"emacs/modules/navigation.el" = {
|
||||||
|
source = ../../dotfiles/geir/emacs-config/modules/navigation.el;
|
||||||
|
mode = "0644";
|
||||||
|
};
|
||||||
|
|
||||||
|
"emacs/modules/development.el" = {
|
||||||
|
source = ../../dotfiles/geir/emacs-config/modules/development.el;
|
||||||
|
mode = "0644";
|
||||||
|
};
|
||||||
|
|
||||||
|
"emacs/modules/elisp-development.el" = {
|
||||||
|
source = ../../dotfiles/geir/emacs-config/modules/elisp-development.el;
|
||||||
|
mode = "0644";
|
||||||
|
};
|
||||||
|
|
||||||
|
"emacs/modules/claude-code.el" = mkIf (cfg.profile == "workstation") {
|
||||||
|
source = ../../dotfiles/geir/emacs-config/modules/claude-code.el;
|
||||||
|
mode = "0644";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Environment variables for Nix integration
|
||||||
|
environment.variables = {
|
||||||
|
EMACS_PROFILE = cfg.profile;
|
||||||
|
|
||||||
|
# Tool paths for Emacs integration
|
||||||
|
RG_PATH = "${pkgs.ripgrep}/bin/rg";
|
||||||
|
FD_PATH = "${pkgs.fd}/bin/fd";
|
||||||
|
SQLITE_PATH = "${pkgs.sqlite}/bin/sqlite3";
|
||||||
|
AG_PATH = "${pkgs.ag}/bin/ag";
|
||||||
|
|
||||||
|
# Language servers
|
||||||
|
NIL_LSP_PATH = "${pkgs.nixd}/bin/nixd";
|
||||||
|
BASH_LSP_PATH = "${pkgs.nodePackages.bash-language-server}/bin/bash-language-server";
|
||||||
|
YAML_LSP_PATH = "${pkgs.nodePackages.yaml-language-server}/bin/yaml-language-server";
|
||||||
|
|
||||||
|
# Formatters
|
||||||
|
SHELLCHECK_PATH = "${pkgs.shellcheck}/bin/shellcheck";
|
||||||
|
ALEJANDRA_PATH = "${pkgs.alejandra}/bin/alejandra";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Ensure the user can access the Emacs daemon
|
||||||
|
systemd.user.services.emacs = mkIf cfg.enableDaemon {
|
||||||
|
environment = {
|
||||||
|
EMACS_PROFILE = cfg.profile;
|
||||||
|
NIX_PATH = config.environment.variables.NIX_PATH or "";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -8,9 +8,7 @@
|
||||||
# Editors
|
# Editors
|
||||||
zed-editor
|
zed-editor
|
||||||
neovim
|
neovim
|
||||||
emacs
|
|
||||||
vscode
|
vscode
|
||||||
vscodium-fhs
|
|
||||||
|
|
||||||
# Language servers
|
# Language servers
|
||||||
nixd
|
nixd
|
||||||
|
@ -35,12 +33,13 @@
|
||||||
direnv
|
direnv
|
||||||
gh
|
gh
|
||||||
github-copilot-cli
|
github-copilot-cli
|
||||||
|
deploy-rs
|
||||||
# ai
|
# ai
|
||||||
claude-code
|
claude-code
|
||||||
];
|
];
|
||||||
|
|
||||||
# System-wide Emacs daemon
|
# Note: Emacs is now configured via modules/development/emacs.nix
|
||||||
services.emacs.enable = true;
|
# with machine-specific profiles
|
||||||
|
|
||||||
# Enable ZSH system-wide for development
|
# Enable ZSH system-wide for development
|
||||||
programs.zsh.enable = true;
|
programs.zsh.enable = true;
|
||||||
|
|
|
@ -78,6 +78,33 @@
|
||||||
User sma
|
User sma
|
||||||
IdentityFile ~/.ssh/id_ed25519_admin
|
IdentityFile ~/.ssh/id_ed25519_admin
|
||||||
|
|
||||||
|
# Direct sma user access via Tailscale for deployments
|
||||||
|
Host sma@sleeper-service.tail807ea.ts.net
|
||||||
|
Hostname sleeper-service.tail807ea.ts.net
|
||||||
|
User sma
|
||||||
|
IdentityFile ~/.ssh/id_ed25519_admin
|
||||||
|
|
||||||
|
Host sma@grey-area.tail807ea.ts.net
|
||||||
|
Hostname grey-area.tail807ea.ts.net
|
||||||
|
User sma
|
||||||
|
IdentityFile ~/.ssh/id_ed25519_admin
|
||||||
|
|
||||||
|
Host sma@reverse-proxy.tail807ea.ts.net
|
||||||
|
Hostname reverse-proxy.tail807ea.ts.net
|
||||||
|
User sma
|
||||||
|
IdentityFile ~/.ssh/id_ed25519_admin
|
||||||
|
|
||||||
|
Host sma@little-rascal.tail807ea.ts.net
|
||||||
|
Hostname little-rascal.tail807ea.ts.net
|
||||||
|
User sma
|
||||||
|
IdentityFile ~/.ssh/id_ed25519_admin
|
||||||
|
|
||||||
|
# Localhost sma user for local deployment from laptop
|
||||||
|
Host sma@localhost
|
||||||
|
Hostname localhost
|
||||||
|
User sma
|
||||||
|
IdentityFile ~/.ssh/id_ed25519_admin
|
||||||
|
|
||||||
# Tailscale network
|
# Tailscale network
|
||||||
Host 100.* *.tail*
|
Host 100.* *.tail*
|
||||||
User geir
|
User geir
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
;; lab/deployment.scm - Deployment operations (impure)
|
;; lab/deployment.scm - Deploy-rs based deployment operations
|
||||||
|
|
||||||
(define-module (lab deployment)
|
(define-module (lab deployment)
|
||||||
#:use-module (ice-9 format)
|
#:use-module (ice-9 format)
|
||||||
|
@ -7,10 +7,10 @@
|
||||||
#:use-module (srfi srfi-1)
|
#:use-module (srfi srfi-1)
|
||||||
#:use-module (utils logging)
|
#:use-module (utils logging)
|
||||||
#:use-module (utils config)
|
#:use-module (utils config)
|
||||||
#:use-module (utils ssh)
|
|
||||||
#:export (deploy-machine
|
#:export (deploy-machine
|
||||||
update-flake
|
update-flake
|
||||||
execute-nixos-rebuild
|
deploy-all-machines
|
||||||
|
deploy-with-rollback
|
||||||
option-ref))
|
option-ref))
|
||||||
|
|
||||||
;; Helper function for option handling
|
;; Helper function for option handling
|
||||||
|
@ -19,26 +19,128 @@
|
||||||
(let ((value (assoc-ref options key)))
|
(let ((value (assoc-ref options key)))
|
||||||
(if value value default)))
|
(if value value default)))
|
||||||
|
|
||||||
;; Impure function: Deploy machine configuration
|
;; Main deployment function using deploy-rs
|
||||||
(define (deploy-machine machine-name . args)
|
(define (deploy-machine machine-name . args)
|
||||||
"Deploy configuration to machine (impure - has side effects)"
|
"Deploy configuration to machine using deploy-rs (impure - has side effects)"
|
||||||
(let* ((mode (if (null? args) "boot" (car args)))
|
(let* ((mode (if (null? args) "default" (car args)))
|
||||||
(options (if (< (length args) 2) '() (cadr args)))
|
(options (if (< (length args) 2) '() (cadr args)))
|
||||||
(valid-modes '("boot" "test" "switch"))
|
(dry-run (option-ref options 'dry-run #f))
|
||||||
(dry-run (option-ref options 'dry-run #f)))
|
(skip-checks (option-ref options 'skip-checks #f)))
|
||||||
|
|
||||||
(if (not (validate-machine-name machine-name))
|
(if (not (validate-machine-name machine-name))
|
||||||
#f
|
#f
|
||||||
(if (not (member mode valid-modes))
|
(begin
|
||||||
(begin
|
(log-info "Starting deploy-rs deployment: ~a" machine-name)
|
||||||
(log-error "Invalid deployment mode: ~a" mode)
|
(execute-deploy-rs machine-name mode options)))))
|
||||||
(log-error "Valid modes: ~a" (string-join valid-modes ", "))
|
|
||||||
#f)
|
|
||||||
(begin
|
|
||||||
(log-info "Starting deployment: ~a (mode: ~a)" machine-name mode)
|
|
||||||
(execute-nixos-rebuild machine-name mode options))))))
|
|
||||||
|
|
||||||
;; Impure function: Update flake inputs
|
;; Execute deploy-rs deployment
|
||||||
|
(define (execute-deploy-rs machine-name mode options)
|
||||||
|
"Execute deployment using deploy-rs with automatic rollback"
|
||||||
|
(let* ((homelab-root (get-homelab-root))
|
||||||
|
(dry-run (option-ref options 'dry-run #f))
|
||||||
|
(skip-checks (option-ref options 'skip-checks #f))
|
||||||
|
(auto-rollback (option-ref options 'auto-rollback #t))
|
||||||
|
(magic-rollback (option-ref options 'magic-rollback #t)))
|
||||||
|
|
||||||
|
(log-info "Deploying ~a using deploy-rs..." machine-name)
|
||||||
|
|
||||||
|
(if dry-run
|
||||||
|
(begin
|
||||||
|
(log-info "DRY RUN: Would execute deploy-rs for ~a" machine-name)
|
||||||
|
(log-info "Command would be: deploy '.#~a'" machine-name)
|
||||||
|
#t)
|
||||||
|
(let* ((deploy-cmd (build-deploy-command machine-name skip-checks auto-rollback magic-rollback))
|
||||||
|
(start-time (current-time)))
|
||||||
|
|
||||||
|
(log-debug "Deploy command: ~a" deploy-cmd)
|
||||||
|
(log-info "Executing deployment with automatic rollback protection...")
|
||||||
|
|
||||||
|
(let* ((port (open-pipe* OPEN_READ "/bin/sh" "-c" deploy-cmd))
|
||||||
|
(output (get-string-all port))
|
||||||
|
(status (close-pipe port))
|
||||||
|
(elapsed (- (current-time) start-time)))
|
||||||
|
|
||||||
|
(if (zero? status)
|
||||||
|
(begin
|
||||||
|
(log-success "Deploy-rs deployment completed successfully in ~as" elapsed)
|
||||||
|
(log-info "Deployment output:")
|
||||||
|
(log-info "~a" output)
|
||||||
|
#t)
|
||||||
|
(begin
|
||||||
|
(log-error "Deploy-rs deployment failed (exit: ~a)" status)
|
||||||
|
(log-error "Error output:")
|
||||||
|
(log-error "~a" output)
|
||||||
|
(log-info "Deploy-rs automatic rollback should have been triggered")
|
||||||
|
#f)))))))
|
||||||
|
|
||||||
|
;; Build deploy-rs command with options
|
||||||
|
(define (build-deploy-command machine-name skip-checks auto-rollback magic-rollback)
|
||||||
|
"Build the deploy-rs command with appropriate flags"
|
||||||
|
(let ((base-cmd (format #f "cd ~a && deploy '.#~a'" (get-homelab-root) machine-name))
|
||||||
|
(flags '()))
|
||||||
|
|
||||||
|
;; Add flags based on options
|
||||||
|
(when skip-checks
|
||||||
|
(set! flags (cons "--skip-checks" flags)))
|
||||||
|
|
||||||
|
(when auto-rollback
|
||||||
|
(set! flags (cons "--auto-rollback" flags)))
|
||||||
|
|
||||||
|
(when magic-rollback
|
||||||
|
(set! flags (cons "--magic-rollback" flags)))
|
||||||
|
|
||||||
|
;; Combine command with flags
|
||||||
|
(if (null? flags)
|
||||||
|
base-cmd
|
||||||
|
(format #f "~a ~a" base-cmd (string-join flags " ")))))
|
||||||
|
|
||||||
|
;; Deploy to all machines
|
||||||
|
(define (deploy-all-machines . args)
|
||||||
|
"Deploy to all machines using deploy-rs"
|
||||||
|
(let* ((options (if (null? args) '() (car args)))
|
||||||
|
(dry-run (option-ref options 'dry-run #f))
|
||||||
|
(machines (get-all-machines)))
|
||||||
|
|
||||||
|
(log-info "Starting deployment to all machines (~a total)" (length machines))
|
||||||
|
|
||||||
|
(let ((results
|
||||||
|
(map (lambda (machine)
|
||||||
|
(log-info "Deploying to ~a..." machine)
|
||||||
|
(let ((result (deploy-machine machine "default" options)))
|
||||||
|
(if result
|
||||||
|
(log-success "✓ ~a deployed successfully" machine)
|
||||||
|
(log-error "✗ ~a deployment failed" machine))
|
||||||
|
(cons machine result)))
|
||||||
|
machines)))
|
||||||
|
|
||||||
|
;; Summary
|
||||||
|
(let ((successful (filter cdr results))
|
||||||
|
(failed (filter (lambda (r) (not (cdr r))) results)))
|
||||||
|
(log-info "Deployment summary:")
|
||||||
|
(log-info " Successful: ~a/~a machines" (length successful) (length machines))
|
||||||
|
(when (not (null? failed))
|
||||||
|
(log-error " Failed: ~a" (string-join (map car failed) ", ")))
|
||||||
|
|
||||||
|
;; Return true if all succeeded
|
||||||
|
(= (length successful) (length machines))))))
|
||||||
|
|
||||||
|
;; Deploy with explicit rollback testing
|
||||||
|
(define (deploy-with-rollback machine-name . args)
|
||||||
|
"Deploy with explicit rollback capability testing"
|
||||||
|
(let* ((options (if (null? args) '() (car args)))
|
||||||
|
(test-rollback (option-ref options 'test-rollback #f)))
|
||||||
|
|
||||||
|
(log-info "Deploying ~a with rollback testing..." machine-name)
|
||||||
|
|
||||||
|
(if test-rollback
|
||||||
|
(begin
|
||||||
|
(log-info "Testing rollback mechanism (deploy will be reverted)")
|
||||||
|
;; Deploy with magic rollback disabled to test manual rollback
|
||||||
|
(let ((modified-options (cons '(magic-rollback . #f) options)))
|
||||||
|
(execute-deploy-rs machine-name "default" modified-options)))
|
||||||
|
(execute-deploy-rs machine-name "default" options))))
|
||||||
|
|
||||||
|
;; Update flake inputs (moved from old deployment module)
|
||||||
(define (update-flake . args)
|
(define (update-flake . args)
|
||||||
"Update flake inputs (impure - has side effects)"
|
"Update flake inputs (impure - has side effects)"
|
||||||
(let* ((options (if (null? args) '() (car args)))
|
(let* ((options (if (null? args) '() (car args)))
|
||||||
|
@ -64,76 +166,3 @@
|
||||||
(log-error "Flake update failed (exit: ~a)" status)
|
(log-error "Flake update failed (exit: ~a)" status)
|
||||||
(log-error "Error output: ~a" output)
|
(log-error "Error output: ~a" output)
|
||||||
#f))))))
|
#f))))))
|
||||||
|
|
||||||
;; Impure function: Execute nixos-rebuild
|
|
||||||
(define (execute-nixos-rebuild machine-name mode options)
|
|
||||||
"Execute nixos-rebuild command (impure - has side effects)"
|
|
||||||
(let* ((dry-run (option-ref options 'dry-run #f))
|
|
||||||
(ssh-config (get-ssh-config machine-name))
|
|
||||||
(is-local (and ssh-config (assoc-ref ssh-config 'is-local)))
|
|
||||||
(homelab-root (get-homelab-root)))
|
|
||||||
|
|
||||||
(if is-local
|
|
||||||
;; Local deployment
|
|
||||||
(let ((rebuild-cmd (format #f "sudo nixos-rebuild ~a --flake ~a#~a"
|
|
||||||
mode homelab-root machine-name)))
|
|
||||||
(log-debug "Local rebuild command: ~a" rebuild-cmd)
|
|
||||||
|
|
||||||
(if dry-run
|
|
||||||
(begin
|
|
||||||
(log-info "DRY RUN: Would execute: ~a" rebuild-cmd)
|
|
||||||
#t)
|
|
||||||
(let* ((port (open-pipe* OPEN_READ "/bin/sh" "-c" rebuild-cmd))
|
|
||||||
(output (get-string-all port))
|
|
||||||
(status (close-pipe port)))
|
|
||||||
|
|
||||||
(if (zero? status)
|
|
||||||
(begin
|
|
||||||
(log-success "Local nixos-rebuild completed")
|
|
||||||
#t)
|
|
||||||
(begin
|
|
||||||
(log-error "Local nixos-rebuild failed (exit: ~a)" status)
|
|
||||||
#f)))))
|
|
||||||
|
|
||||||
;; Remote deployment
|
|
||||||
(let* ((hostname (assoc-ref ssh-config 'hostname))
|
|
||||||
(ssh-alias (or (assoc-ref ssh-config 'ssh-alias) hostname))
|
|
||||||
(temp-dir "/tmp/homelab-deploy")
|
|
||||||
(sync-cmd (format #f "rsync -av --delete ~a/ ~a:~a/"
|
|
||||||
homelab-root ssh-alias temp-dir))
|
|
||||||
(rebuild-cmd (format #f "ssh ~a 'cd ~a && sudo nixos-rebuild ~a --flake .#~a'"
|
|
||||||
ssh-alias temp-dir mode machine-name)))
|
|
||||||
|
|
||||||
(log-debug "Remote sync command: ~a" sync-cmd)
|
|
||||||
(log-debug "Remote rebuild command: ~a" rebuild-cmd)
|
|
||||||
|
|
||||||
(if dry-run
|
|
||||||
(begin
|
|
||||||
(log-info "DRY RUN: Would sync and rebuild remotely")
|
|
||||||
#t)
|
|
||||||
(begin
|
|
||||||
;; Sync configuration
|
|
||||||
(log-info "Syncing configuration to ~a..." machine-name)
|
|
||||||
(let* ((sync-port (open-pipe* OPEN_READ "/bin/sh" "-c" sync-cmd))
|
|
||||||
(sync-output (get-string-all sync-port))
|
|
||||||
(sync-status (close-pipe sync-port)))
|
|
||||||
|
|
||||||
(if (zero? sync-status)
|
|
||||||
(begin
|
|
||||||
(log-success "Configuration synced")
|
|
||||||
;; Execute rebuild
|
|
||||||
(log-info "Executing nixos-rebuild on ~a..." machine-name)
|
|
||||||
(let* ((rebuild-port (open-pipe* OPEN_READ "/bin/sh" "-c" rebuild-cmd))
|
|
||||||
(rebuild-output (get-string-all rebuild-port))
|
|
||||||
(rebuild-status (close-pipe rebuild-port)))
|
|
||||||
|
|
||||||
(if (zero? rebuild-status)
|
|
||||||
(begin
|
|
||||||
(log-success "Remote nixos-rebuild completed")
|
|
||||||
#t)
|
|
||||||
(begin
|
|
||||||
(log-error "Remote nixos-rebuild failed (exit: ~a)" rebuild-status)
|
|
||||||
#f))))
|
|
||||||
(begin
|
|
||||||
(log-error "Configuration sync failed (exit: ~a)" sync-status)
|
|
||||||
#f)))))))))
|
|
||||||
|
|
|
@ -22,44 +22,48 @@
|
||||||
;; Pure function: Command help text
|
;; Pure function: Command help text
|
||||||
(define (get-help-text)
|
(define (get-help-text)
|
||||||
"Pure function returning help text"
|
"Pure function returning help text"
|
||||||
"Home Lab Tool - K.I.S.S Refactored Edition
|
"Home Lab Tool - Deploy-rs Edition
|
||||||
|
|
||||||
USAGE: lab <command> [args...]
|
USAGE: lab <command> [args...]
|
||||||
|
|
||||||
COMMANDS:
|
COMMANDS:
|
||||||
status Show infrastructure status
|
status Show infrastructure status
|
||||||
machines List all machines
|
machines List all machines
|
||||||
deploy <machine> [mode] Deploy configuration to machine
|
deploy <machine> [options] Deploy configuration to machine using deploy-rs
|
||||||
Available modes: boot (default), test, switch
|
Options: --dry-run, --skip-checks
|
||||||
deploy-all Deploy to all machines
|
deploy-all [options] Deploy to all machines using deploy-rs
|
||||||
update Update flake inputs
|
update Update flake inputs
|
||||||
auto-update Perform automatic system update with health checks
|
auto-update Perform automatic system update with health checks
|
||||||
auto-update-status Show auto-update service status and logs
|
auto-update-status Show auto-update service status and logs
|
||||||
health [machine] Check machine health (all if no machine specified)
|
health [machine] Check machine health (all if no machine specified)
|
||||||
ssh <machine> SSH to machine
|
ssh <machine> SSH to machine (using sma user)
|
||||||
test-modules Test modular implementation
|
test-rollback <machine> Test deployment with rollback
|
||||||
help Show this help
|
help Show this help
|
||||||
|
|
||||||
EXAMPLES:
|
EXAMPLES:
|
||||||
lab status
|
lab status
|
||||||
lab machines
|
lab machines
|
||||||
lab deploy congenital-optimist # Deploy with boot mode (default)
|
lab deploy congenital-optimist # Deploy with deploy-rs safety
|
||||||
lab deploy congenital-optimist switch # Deploy and activate immediately
|
lab deploy sleeper-service --dry-run # Test deployment without applying
|
||||||
lab deploy congenital-optimist test # Deploy temporarily for testing
|
lab deploy grey-area --skip-checks # Deploy without health checks
|
||||||
lab deploy-all
|
lab deploy-all # Deploy to all machines
|
||||||
lab update
|
lab deploy-all --dry-run # Test deployment to all machines
|
||||||
lab auto-update # Perform automatic update with reboot
|
lab update # Update flake inputs
|
||||||
lab auto-update-status # Show auto-update logs and status
|
lab test-rollback sleeper-service # Test rollback functionality
|
||||||
lab health
|
lab ssh sleeper-service # SSH to machine as sma user
|
||||||
lab health sleeper-service
|
|
||||||
lab ssh sleeper-service
|
|
||||||
lab test-modules
|
|
||||||
|
|
||||||
This implementation follows K.I.S.S principles:
|
Deploy-rs Features:
|
||||||
- Modular: Each module has single responsibility
|
- Automatic rollback on deployment failure
|
||||||
- Functional: Pure functions separated from side effects
|
- Health checks after deployment
|
||||||
- Small: Individual modules under 50 lines
|
- Magic rollback for network connectivity issues
|
||||||
- Simple: One function does one thing well
|
- Atomic deployments with safety guarantees
|
||||||
|
- Consistent sma user for all deployments
|
||||||
|
|
||||||
|
This implementation uses deploy-rs for all deployments:
|
||||||
|
- Robust: Automatic rollback protection
|
||||||
|
- Safe: Health checks and validation
|
||||||
|
- Consistent: Same deployment method for all machines
|
||||||
|
- Flexible: Dry-run and skip-checks options available
|
||||||
")
|
")
|
||||||
|
|
||||||
;; Pure function: Format machine list
|
;; Pure function: Format machine list
|
||||||
|
@ -109,36 +113,33 @@ Home lab root: ~a
|
||||||
(log-success "Machine list complete")))
|
(log-success "Machine list complete")))
|
||||||
|
|
||||||
(define (cmd-deploy machine-name . args)
|
(define (cmd-deploy machine-name . args)
|
||||||
"Deploy configuration to machine"
|
"Deploy configuration to machine using deploy-rs"
|
||||||
(let* ((mode (if (null? args) "boot" (car args)))
|
(let* ((options (parse-deploy-options args)))
|
||||||
(valid-modes '("boot" "test" "switch")))
|
(log-info "Deploying to machine: ~a using deploy-rs" machine-name)
|
||||||
(log-info "Deploying to machine: ~a (mode: ~a)" machine-name mode)
|
(if (validate-machine-name machine-name)
|
||||||
(if (not (member mode valid-modes))
|
(let ((result (deploy-machine machine-name "default" options)))
|
||||||
|
(if result
|
||||||
|
(log-success "Deploy-rs deployment to ~a completed successfully" machine-name)
|
||||||
|
(log-error "Deploy-rs deployment to ~a failed" machine-name)))
|
||||||
(begin
|
(begin
|
||||||
(log-error "Invalid deployment mode: ~a" mode)
|
(log-error "Invalid machine: ~a" machine-name)
|
||||||
(log-error "Valid modes: ~a" (string-join valid-modes ", "))
|
(log-info "Available machines: ~a" (string-join (get-all-machines) ", "))))))
|
||||||
(format #t "Usage: lab deploy <machine> [boot|test|switch]\n"))
|
|
||||||
(if (validate-machine-name machine-name)
|
|
||||||
(let ((result (deploy-machine machine-name mode '())))
|
|
||||||
(if result
|
|
||||||
(log-success "Deployment to ~a complete (mode: ~a)" machine-name mode)
|
|
||||||
(log-error "Deployment to ~a failed" machine-name)))
|
|
||||||
(begin
|
|
||||||
(log-error "Invalid machine: ~a" machine-name)
|
|
||||||
(log-info "Available machines: ~a" (string-join (get-all-machines) ", ")))))))
|
|
||||||
|
|
||||||
(define (cmd-ssh machine-name)
|
(define (cmd-ssh machine-name)
|
||||||
"SSH to machine"
|
"SSH to machine using sma user"
|
||||||
(log-info "Connecting to machine: ~a" machine-name)
|
(log-info "Connecting to machine: ~a as sma user" machine-name)
|
||||||
(if (validate-machine-name machine-name)
|
(if (validate-machine-name machine-name)
|
||||||
(let ((ssh-config (get-ssh-config machine-name)))
|
(let ((ssh-config (get-ssh-config machine-name)))
|
||||||
(if ssh-config
|
(if ssh-config
|
||||||
(let ((hostname (assoc-ref ssh-config 'hostname))
|
(let ((hostname (assoc-ref ssh-config 'hostname))
|
||||||
(ssh-alias (assoc-ref ssh-config 'ssh-alias))
|
(ssh-alias (assoc-ref ssh-config 'ssh-alias))
|
||||||
|
(ssh-user (assoc-ref ssh-config 'ssh-user))
|
||||||
(is-local (assoc-ref ssh-config 'is-local)))
|
(is-local (assoc-ref ssh-config 'is-local)))
|
||||||
(if is-local
|
(if is-local
|
||||||
(log-info "Machine ~a is local - no SSH needed" machine-name)
|
(begin
|
||||||
(let ((target (or ssh-alias hostname)))
|
(log-info "Machine ~a is local - switching to sma user locally" machine-name)
|
||||||
|
(system "sudo -u sma -i"))
|
||||||
|
(let ((target (format #f "~a@~a" (or ssh-user "sma") (or ssh-alias hostname))))
|
||||||
(log-info "Connecting to ~a via SSH..." target)
|
(log-info "Connecting to ~a via SSH..." target)
|
||||||
(system (format #f "ssh ~a" target)))))
|
(system (format #f "ssh ~a" target)))))
|
||||||
(log-error "No SSH configuration found for ~a" machine-name)))
|
(log-error "No SSH configuration found for ~a" machine-name)))
|
||||||
|
@ -171,20 +172,12 @@ Home lab root: ~a
|
||||||
(log-error "Flake update failed"))))
|
(log-error "Flake update failed"))))
|
||||||
|
|
||||||
(define (cmd-deploy-all)
|
(define (cmd-deploy-all)
|
||||||
"Deploy to all machines"
|
"Deploy to all machines using deploy-rs"
|
||||||
(log-info "Deploying to all machines...")
|
(log-info "Deploying to all machines using deploy-rs...")
|
||||||
(let* ((machines (list-machines))
|
(let ((result (deploy-all-machines '())))
|
||||||
(results (map (lambda (machine)
|
(if result
|
||||||
(log-info "Deploying to ~a..." machine)
|
(log-success "All deploy-rs deployments completed successfully")
|
||||||
(let ((result (deploy-machine machine "boot" '())))
|
(log-error "Some deploy-rs deployments failed"))))
|
||||||
(if result
|
|
||||||
(log-success "✓ ~a deployed" machine)
|
|
||||||
(log-error "✗ ~a failed" machine))
|
|
||||||
result))
|
|
||||||
machines))
|
|
||||||
(successful (filter identity results)))
|
|
||||||
(log-info "Deployment summary: ~a/~a successful"
|
|
||||||
(length successful) (length machines))))
|
|
||||||
|
|
||||||
(define (cmd-health args)
|
(define (cmd-health args)
|
||||||
"Check machine health"
|
"Check machine health"
|
||||||
|
@ -219,6 +212,33 @@ Home lab root: ~a
|
||||||
"Show auto-update status and logs"
|
"Show auto-update status and logs"
|
||||||
(auto-update-status))
|
(auto-update-status))
|
||||||
|
|
||||||
|
;; Parse deployment options from command line arguments
|
||||||
|
(define (parse-deploy-options args)
|
||||||
|
"Parse deployment options from command line arguments"
|
||||||
|
(let ((options '()))
|
||||||
|
(for-each
|
||||||
|
(lambda (arg)
|
||||||
|
(cond
|
||||||
|
((string=? arg "--dry-run")
|
||||||
|
(set! options (cons '(dry-run . #t) options)))
|
||||||
|
((string=? arg "--skip-checks")
|
||||||
|
(set! options (cons '(skip-checks . #t) options)))
|
||||||
|
(else
|
||||||
|
(log-warn "Unknown option: ~a" arg))))
|
||||||
|
args)
|
||||||
|
options))
|
||||||
|
|
||||||
|
(define (cmd-test-rollback machine-name)
|
||||||
|
"Test deployment with rollback functionality"
|
||||||
|
(log-info "Testing rollback deployment for machine: ~a" machine-name)
|
||||||
|
(if (validate-machine-name machine-name)
|
||||||
|
(let ((options '((test-rollback . #t))))
|
||||||
|
(let ((result (deploy-with-rollback machine-name options)))
|
||||||
|
(if result
|
||||||
|
(log-success "Rollback test completed for ~a" machine-name)
|
||||||
|
(log-error "Rollback test failed for ~a" machine-name))))
|
||||||
|
(log-error "Invalid machine: ~a" machine-name)))
|
||||||
|
|
||||||
;; Main command dispatcher
|
;; Main command dispatcher
|
||||||
(define (dispatch-command command args)
|
(define (dispatch-command command args)
|
||||||
"Dispatch command with appropriate handler"
|
"Dispatch command with appropriate handler"
|
||||||
|
@ -236,12 +256,20 @@ Home lab root: ~a
|
||||||
(if (null? args)
|
(if (null? args)
|
||||||
(begin
|
(begin
|
||||||
(log-error "deploy command requires machine name")
|
(log-error "deploy command requires machine name")
|
||||||
(format #t "Usage: lab deploy <machine> [boot|test|switch]\n"))
|
(format #t "Usage: lab deploy <machine> [options]\n")
|
||||||
|
(format #t "Options: --dry-run, --skip-checks\n"))
|
||||||
(apply cmd-deploy args)))
|
(apply cmd-deploy args)))
|
||||||
|
|
||||||
('deploy-all
|
('deploy-all
|
||||||
(cmd-deploy-all))
|
(cmd-deploy-all))
|
||||||
|
|
||||||
|
('test-rollback
|
||||||
|
(if (null? args)
|
||||||
|
(begin
|
||||||
|
(log-error "test-rollback command requires machine name")
|
||||||
|
(format #t "Usage: lab test-rollback <machine>\n"))
|
||||||
|
(cmd-test-rollback (car args))))
|
||||||
|
|
||||||
('update
|
('update
|
||||||
(cmd-update))
|
(cmd-update))
|
||||||
|
|
||||||
|
@ -264,6 +292,13 @@ Home lab root: ~a
|
||||||
('test-modules
|
('test-modules
|
||||||
(cmd-test-modules))
|
(cmd-test-modules))
|
||||||
|
|
||||||
|
('test-rollback
|
||||||
|
(if (null? args)
|
||||||
|
(begin
|
||||||
|
(log-error "test-rollback command requires machine name")
|
||||||
|
(format #t "Usage: lab test-rollback <machine>\n"))
|
||||||
|
(cmd-test-rollback (car args))))
|
||||||
|
|
||||||
(_
|
(_
|
||||||
(log-error "Unknown command: ~a" command)
|
(log-error "Unknown command: ~a" command)
|
||||||
(format #t "Use 'lab help' for available commands\n")
|
(format #t "Use 'lab help' for available commands\n")
|
||||||
|
@ -272,7 +307,7 @@ Home lab root: ~a
|
||||||
;; Main entry point
|
;; Main entry point
|
||||||
(define (main args)
|
(define (main args)
|
||||||
"Main entry point for lab tool"
|
"Main entry point for lab tool"
|
||||||
(log-info "Home Lab Tool - K.I.S.S Refactored Edition")
|
(log-info "Home Lab Tool - Deploy-rs Edition")
|
||||||
|
|
||||||
(let* ((parsed-cmd (if (> (length args) 1) (cdr args) '("help")))
|
(let* ((parsed-cmd (if (> (length args) 1) (cdr args) '("help")))
|
||||||
(command (string->symbol (car parsed-cmd)))
|
(command (string->symbol (car parsed-cmd)))
|
||||||
|
|
|
@ -22,26 +22,31 @@
|
||||||
(machines . ((congenital-optimist
|
(machines . ((congenital-optimist
|
||||||
(type . local)
|
(type . local)
|
||||||
(hostname . "localhost")
|
(hostname . "localhost")
|
||||||
|
(ssh-user . "sma")
|
||||||
(services . (workstation development)))
|
(services . (workstation development)))
|
||||||
(sleeper-service
|
(sleeper-service
|
||||||
(type . remote)
|
(type . remote)
|
||||||
(hostname . "sleeper-service.tail807ea.ts.net")
|
(hostname . "sleeper-service.tail807ea.ts.net")
|
||||||
(ssh-alias . "admin-sleeper")
|
(ssh-alias . "sleeper-service.tail807ea.ts.net")
|
||||||
|
(ssh-user . "sma")
|
||||||
(services . (nfs zfs storage)))
|
(services . (nfs zfs storage)))
|
||||||
(grey-area
|
(grey-area
|
||||||
(type . remote)
|
(type . remote)
|
||||||
(hostname . "grey-area.tail807ea.ts.net")
|
(hostname . "grey-area.tail807ea.ts.net")
|
||||||
(ssh-alias . "admin-grey")
|
(ssh-alias . "grey-area.tail807ea.ts.net")
|
||||||
|
(ssh-user . "sma")
|
||||||
(services . (ollama forgejo git)))
|
(services . (ollama forgejo git)))
|
||||||
(reverse-proxy
|
(reverse-proxy
|
||||||
(type . remote)
|
(type . remote)
|
||||||
(hostname . "reverse-proxy.tail807ea.ts.net")
|
(hostname . "reverse-proxy.tail807ea.ts.net")
|
||||||
(ssh-alias . "admin-reverse")
|
(ssh-alias . "reverse-proxy.tail807ea.ts.net")
|
||||||
|
(ssh-user . "sma")
|
||||||
(services . (nginx proxy ssl)))
|
(services . (nginx proxy ssl)))
|
||||||
(little-rascal
|
(little-rascal
|
||||||
(type . remote)
|
(type . remote)
|
||||||
(hostname . "little-rascal.tail807ea.ts.net")
|
(hostname . "little-rascal.tail807ea.ts.net")
|
||||||
(ssh-alias . "little-rascal")
|
(ssh-alias . "little-rascal.tail807ea.ts.net")
|
||||||
|
(ssh-user . "sma")
|
||||||
(services . (development niri desktop ai-tools)))))
|
(services . (development niri desktop ai-tools)))))
|
||||||
(deployment . ((default-mode . "boot")
|
(deployment . ((default-mode . "boot")
|
||||||
(timeout . 300)
|
(timeout . 300)
|
||||||
|
@ -124,10 +129,12 @@
|
||||||
(if machine-config
|
(if machine-config
|
||||||
(let ((type (assoc-ref machine-config 'type))
|
(let ((type (assoc-ref machine-config 'type))
|
||||||
(hostname (assoc-ref machine-config 'hostname))
|
(hostname (assoc-ref machine-config 'hostname))
|
||||||
(ssh-alias (assoc-ref machine-config 'ssh-alias)))
|
(ssh-alias (assoc-ref machine-config 'ssh-alias))
|
||||||
|
(ssh-user (assoc-ref machine-config 'ssh-user)))
|
||||||
`((type . ,type)
|
`((type . ,type)
|
||||||
(hostname . ,hostname)
|
(hostname . ,hostname)
|
||||||
(ssh-alias . ,ssh-alias)
|
(ssh-alias . ,ssh-alias)
|
||||||
|
(ssh-user . ,ssh-user)
|
||||||
(is-local . ,(eq? type 'local))))
|
(is-local . ,(eq? type 'local))))
|
||||||
#f)))
|
#f)))
|
||||||
|
|
||||||
|
|
34
shell.nix
Normal file
34
shell.nix
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
# Nix shell for Home Lab development with deploy-rs and lab-tool
|
||||||
|
|
||||||
|
{
|
||||||
|
description = "Home Lab dev shell with deploy-rs and lab-tool";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
|
||||||
|
deploy-rs.url = "github:serokell/deploy-rs";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, deploy-rs, ... }@inputs: let
|
||||||
|
system = "x86_64-linux";
|
||||||
|
pkgs = import nixpkgs { inherit system; };
|
||||||
|
in {
|
||||||
|
devShells.${system}.default = pkgs.mkShell {
|
||||||
|
buildInputs = [
|
||||||
|
pkgs.git
|
||||||
|
pkgs.guile_3_0
|
||||||
|
pkgs.guile-ssh
|
||||||
|
pkgs.guile-json
|
||||||
|
pkgs.guile-git
|
||||||
|
pkgs.guile-gcrypt
|
||||||
|
pkgs.openssh
|
||||||
|
pkgs.nixos-rebuild
|
||||||
|
deploy-rs.packages.${system}.deploy-rs
|
||||||
|
(import ./packages/lab-tool/default.nix { inherit (pkgs) lib stdenv makeWrapper guile_3_0 guile-ssh guile-json guile-git guile-gcrypt openssh git nixos-rebuild; })
|
||||||
|
];
|
||||||
|
shellHook = ''
|
||||||
|
echo "Dev shell: deploy-rs and lab-tool available."
|
||||||
|
echo "Try: lab status, lab deploy <machine>, or deploy . <target>"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue