summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/build-emacs.sh246
-rwxr-xr-xscripts/create-elpa-mirrors.sh48
-rwxr-xr-xscripts/delete-elisp-compiled-files.sh24
-rwxr-xr-xscripts/profile-dotemacs.sh20
-rwxr-xr-xscripts/remote-repository-reset.sh19
-rwxr-xr-xscripts/reset-to-first-launch.sh45
-rwxr-xr-xscripts/setup-email.sh47
7 files changed, 449 insertions, 0 deletions
diff --git a/scripts/build-emacs.sh b/scripts/build-emacs.sh
new file mode 100755
index 00000000..6750adce
--- /dev/null
+++ b/scripts/build-emacs.sh
@@ -0,0 +1,246 @@
+#!/usr/bin/env bash
+# Craig Jennings <c@cjennings.net>
+# Build & install Emacs from source
+# safe, user-local, fast, versioned.
+
+set -Eeuo pipefail
+IFS=$'\n\t'
+
+# ------------------------ Config (overwrite via ENV) -----------------------
+
+SRC_DIR="${SRC_DIR:-$HOME/code/emacs-src}"
+EMACS_REPO="${EMACS_REPO:-https://git.savannah.gnu.org/git/emacs.git}"
+CHECKOUT_REF="${CHECKOUT_REF:-emacs-30.2}"
+PREFIX_BASE="${PREFIX_BASE:-$HOME/.local/src/emacs}"
+
+# Add DEBUG_BUILD flag
+DEBUG_BUILD="${DEBUG_BUILD:-1}"
+if [[ "$DEBUG_BUILD" == "1" ]]; then
+ PREFIX="${PREFIX:-$PREFIX_BASE/${CHECKOUT_REF}-debug}"
+ CFLAGS="${CFLAGS:--O0 -g}"
+ ENABLE_CHECKING="${ENABLE_CHECKING:-yes,glyphs}"
+ ENABLE_NATIVE="${ENABLE_NATIVE:-0}" # Disable native comp for debug
+else
+ PREFIX="${PREFIX:-$PREFIX_BASE/${CHECKOUT_REF}}"
+ CFLAGS="${CFLAGS:--O2 -g}"
+ ENABLE_CHECKING="${ENABLE_CHECKING:-no}"
+ ENABLE_NATIVE="${ENABLE_NATIVE:-1}"
+fi
+
+LOG_DIR="${LOG_DIR:-$HOME/}"
+WITH_PGTK="${WITH_PGTK:-0}"
+JOBS="${JOBS:-auto}"
+EXTRA_CONFIG="${EXTRA_CONFIG:-}"
+
+# --------------------------------- Preflight ---------------------------------
+
+umask 022
+mkdir -p "$LOG_DIR" "$PREFIX_BASE" "$HOME/.local/bin"
+: "${LOGFILE:=$LOG_DIR/emacs-build-$(date +%Y%m%d-%H%M%S)-${CHECKOUT_REF}${DEBUG_BUILD:+-debug}.log}"
+
+say() { printf '>>> %s\n' "$*" | tee -a "$LOGFILE" ; }
+run() {
+ say "+ $*"
+ if ! eval "$@" >>"$LOGFILE" 2>&1; then
+ echo "ERROR: Command failed: $*" >&2
+ echo "Last 20 lines of output:" >&2
+ tail -n 20 "$LOGFILE" >&2
+ return 1
+ fi
+}
+
+on_err(){
+ ec=$?
+ echo "ERROR [$ec] - Full log at: $LOGFILE" >&2
+ echo "Last 100 lines of log:" >&2
+ tail -n 100 "$LOGFILE" >&2 || true
+ exit "$ec"
+}
+
+trap on_err ERR
+
+# -------------------------- Arch Linux Dependencies --------------------------
+
+if [[ -r /etc/os-release ]]; then
+ . /etc/os-release
+fi
+
+if [[ "${ID:-}" == "arch" || "${ID_LIKE:-}" == *arch* ]]; then
+ say "Arch Linux detected; checking required build/runtime packages"
+
+ # Base packages needed for the requested configure flags
+ pkgs=(jansson tree-sitter imagemagick mailutils harfbuzz cairo gnutls libxml2 texinfo gtk3)
+
+ # Only if native-compilation is enabled
+ if [[ "${ENABLE_NATIVE:-1}" == "1" ]]; then
+ pkgs+=(libgccjit)
+ fi
+
+ # List packages that are not installed
+ missing="$(pacman -T "${pkgs[@]}" || true)"
+
+ if [[ -z "$missing" ]]; then
+ say "All required packages are already installed."
+ else
+ say "Missing packages: $missing"
+ if command -v sudo >/dev/null 2>&1 && sudo -n true 2>/dev/null; then
+ run "sudo -n pacman -Sy --needed --noconfirm $missing"
+ else
+ say "sudo (passwordless) not available; please install missing packages manually:"
+ echo " sudo pacman -Sy --needed $missing"
+ exit 70
+ fi
+ fi
+else
+ say "Non-Arch system detected; skipping Arch-specific dependency check."
+fi
+
+# ----------------------------- Clone And Update ----------------------------
+
+if [[ -d "$SRC_DIR/.git" ]]; then
+ run "git -C '$SRC_DIR' fetch --tags --prune"
+else
+ mkdir -p "$(dirname "$SRC_DIR")"
+ run "git clone --origin origin '$EMACS_REPO' '$SRC_DIR'"
+fi
+
+run "git -C '$SRC_DIR' reset --hard HEAD"
+run "git -C '$SRC_DIR' clean -fdx"
+run "git -C '$SRC_DIR' checkout -f '$CHECKOUT_REF'"
+run "git -C '$SRC_DIR' submodule update --init --recursive || true"
+
+# ---------------------------------- Autogen ----------------------------------
+
+if [[ -x "$SRC_DIR/autogen.sh" ]]; then
+ run "cd '$SRC_DIR' && ./autogen.sh"
+fi
+
+# ------------------------------ Configure Flags ------------------------------
+
+conf_flags=(
+ "--prefix=${PREFIX}"
+ "--with-json"
+ "--with-modules"
+)
+
+# Add debug-specific flags
+if [[ "$DEBUG_BUILD" == "1" ]]; then
+ say "Building DEBUG version with symbols and checking"
+ conf_flags+=(
+ "--enable-checking=${ENABLE_CHECKING}"
+ "--enable-check-lisp-object-type"
+ # Note the quotes around the entire CFLAGS assignment:
+ "CFLAGS=${CFLAGS}" # This keeps it as a single argument
+ )
+fi
+
+# Wayland/X choice
+if [[ "$WITH_PGTK" == "auto" ]]; then
+ if [[ -n "${WAYLAND_DISPLAY:-}" ]]; then WITH_PGTK="yes"; else WITH_PGTK="no"; fi
+fi
+if [[ "$WITH_PGTK" == "yes" ]]; then
+ conf_flags+=("--with-pgtk")
+else
+ conf_flags+=("--with-x-toolkit=gtk3")
+fi
+
+# Native-compilation
+if [[ "$ENABLE_NATIVE" == "1" ]]; then
+ conf_flags+=("--with-native-compilation=yes")
+else
+ conf_flags+=("--with-native-compilation=no")
+fi
+
+# Useful extras
+conf_flags+=(
+ "--with-cairo"
+ "--with-harfbuzz"
+ "--with-tree-sitter"
+ "--with-imagemagick"
+ "--with-mailutils"
+)
+
+# Optional extra flags from env
+if [[ -n "$EXTRA_CONFIG" ]]; then
+ conf_flags+=($EXTRA_CONFIG)
+fi
+
+# ----------------------------- Build And Install -----------------------------
+
+mkdir -p "$PREFIX"
+
+# Temporarily change IFS to space for configure argument expansion
+old_ifs="$IFS"
+IFS=' '
+cd "$SRC_DIR"
+"./configure" "${conf_flags[@]}"
+IFS="$old_ifs"
+
+if [[ "$JOBS" == "auto" ]]; then
+ if command -v nproc >/dev/null 2>&1; then JOBS=$(nproc); else JOBS=4; fi
+fi
+run "cd '$SRC_DIR' && make -j$JOBS"
+
+# Build documentation (info files)
+say "...building info files"
+(
+ cd "$SRC_DIR"
+ run "make info"
+)
+
+run "cd '$SRC_DIR' && make install"
+run "cd '$SRC_DIR' && make install-info"
+
+# --------------------------------- Symlinks --------------------------------
+
+if [[ "$DEBUG_BUILD" == "1" ]]; then
+ run "ln -sfn '$PREFIX' '$PREFIX_BASE/emacs-debug'"
+ # Create debug-specific symlinks
+ for exe in emacs emacsclient; do
+ target="$PREFIX/bin/$exe"
+ link="$HOME/.local/bin/${exe}-debug"
+ if [[ -x "$target" ]]; then
+ run "rm -f '$link'"
+ run "ln -s '$target' '$link'"
+ fi
+ done
+ say "Debug build available as 'emacs-debug' and 'emacsclient-debug'"
+else
+ run "ln -sfn '$PREFIX' '$PREFIX_BASE/emacs-current'"
+ for exe in emacs emacsclient; do
+ target="$PREFIX/bin/$exe"
+ link="$HOME/.local/bin/$exe"
+ if [[ -x "$target" ]]; then
+ run "rm -f '$link'"
+ run "ln -s '$target' '$link'"
+ fi
+ done
+fi
+
+# ---------------------------------- Wrap Up ----------------------------------
+
+command -v emacs >/dev/null && emacs --version | head -n1 || true
+command -v emacsclient >/dev/null && emacsclient --version | head -n1 || true
+
+# ----------------------------- Show Build Features ----------------------------
+
+say "Launching Emacs to display version and build features..."
+"$HOME/.local/bin/emacs" -Q --batch --eval '
+(progn
+ (princ (format "Emacs version: %s\n" emacs-version))
+ (princ (format "Build configuration:\n"))
+ (princ (format " Native compilation: %s\n"
+ (if (and (fboundp (quote native-comp-available-p))
+ (native-comp-available-p))
+ "yes" "no")))
+ (princ (format " PGTK: %s\n" (if (featurep (quote pgtk)) "yes" "no")))
+ (princ (format " Tree-sitter: %s\n"
+ (if (fboundp (quote treesit-available-p)) "yes" "no")))
+ (princ (format " JSON: %s\n" (if (fboundp (quote json-parse-string)) "yes" "no")))
+ (princ (format " ImageMagick: %s\n" (if (image-type-available-p (quote imagemagick)) "yes" "no")))
+ (princ (format " Cairo: %s\n" (if (featurep (quote cairo)) "yes" "no")))
+ (princ (format "\nFull system configuration:\n%s\n" system-configuration))
+ (princ (format "\nConfigured features:\n%s\n" system-configuration-features)))
+' 2>&1 | tee -a "$LOGFILE"
+
+echo "Done. See $LOGFILE"
diff --git a/scripts/create-elpa-mirrors.sh b/scripts/create-elpa-mirrors.sh
new file mode 100755
index 00000000..58d02e07
--- /dev/null
+++ b/scripts/create-elpa-mirrors.sh
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+# Craig Jennings <c@cjennings.net>
+
+# Clones the Elpa mirrors repository to a local directory
+
+ELPA_MIRRORS_REPO="https://github.com/d12frosted/elpa-mirror.git"
+ELPA_MIRRORS_DIR=".elpa-mirrors"
+
+
+# Identify EMACS_CONFIG location
+if [ $# -eq 1 ] && [ -d "$1" ]; then
+ EMACS_CONFIG="$1"
+elif [ -d "$HOME/.emacs.d" ]; then
+ EMACS_CONFIG="$HOME/.emacs.d"
+elif [ -d "$HOME/.config/emacs" ]; then
+ EMACS_CONFIG="$HOME/.config/emacs"
+else
+ echo
+ "Unable to locate Emacs configuration directory. Please check that your Emacs
+ configuration is in ~/.emacs.d/ or ~/.config/emacs/. Alternatively, you can
+ specify a different directory by passing the directory path as an argument."
+ exit 1
+fi
+
+# Check if git is installed
+if ! command -v git &> /dev/null; then
+ echo "git was not found. Please install git first."
+ exit 1
+fi
+
+# Check if the .elpa-mirrors already exists
+if [ -d "$EMACS_CONFIG/$ELPA_MIRRORS_DIR" ]; then
+ echo "The directory $EMACS_CONFIG/$ELPA_MIRRORS_DIR already exists. Please remove or rename this directory and run the script again."
+ exit 1
+fi
+
+# Confirm directory selection
+read -p "The following directory has been selected for cloning ELPA mirror repo: $EMACS_CONFIG. Continue? [y/N] " REPLY
+if ! [[ $REPLY =~ ^[Yy]$ ]]; then
+ echo "Operation cancelled by user."
+ exit 0
+fi
+
+# Proceed with cloning
+git clone --depth 1 "$ELPA_MIRRORS_REPO" "$EMACS_CONFIG/$ELPA_MIRRORS_DIR"
+
+# Display completion notification with location of mirrors.
+printf "\n\nCompleted. Elpa mirrors cloned to %s\n\n" "$EMACS_CONFIG/$ELPA_MIRRORS_DIR"
diff --git a/scripts/delete-elisp-compiled-files.sh b/scripts/delete-elisp-compiled-files.sh
new file mode 100755
index 00000000..b64a6540
--- /dev/null
+++ b/scripts/delete-elisp-compiled-files.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+location=$HOME/.emacs.d/
+
+echo ""; echo "You are about to delete emacs lisp compiled files (.eln and .elc) recursively from $location";
+
+# Show the files it will delete
+echo "The following files will be deleted:"
+find $location -type f \( -name "*.eln" -o -name "*.elc" \) -print
+
+
+echo ""; echo ""
+read -p "Are you sure you want to continue? (y/n) " -n 1 -r
+echo # move to a new line
+if [[ $REPLY =~ ^[Yy]$ ]]
+then
+ echo "Deleting files..."
+ find $location -type f \( -name "*.eln" -o -name "*.elc" \) -exec rm -f {} +
+ echo "Files deleted."
+else
+ echo "Operation cancelled."
+fi
+
+echo ""; echo ""
diff --git a/scripts/profile-dotemacs.sh b/scripts/profile-dotemacs.sh
new file mode 100755
index 00000000..b31d078b
--- /dev/null
+++ b/scripts/profile-dotemacs.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+# profile-dotemacs.sh
+# Craig Jennings <c@cjennings.net>
+# a convenience script to load an emacs-lisp file which will
+# startup emacs (with or without an early-init) and provide
+# benchmark information on the Emacs config.
+
+EMACS_HOME="$HOME/.emacs.d/"
+EARLY_INIT_FILE="$EMACS_HOME/early-init.el"
+PROFILE_FILE="$EMACS_HOME/custom/profile-dotemacs.el"
+
+if [ -f "$EARLY_INIT_FILE" ]
+then
+ emacs -Q --load $PROFILE_FILE --eval "(progn (load-file \"~/.emacs.d/early-init.el\") (profile-dotemacs))"
+else
+ echo "No early init found. Proceeding to benchmark init.el."
+ emacs -Q --load $PROFILE_FILE --eval "(profile-dotemacs)"
+fi
+
diff --git a/scripts/remote-repository-reset.sh b/scripts/remote-repository-reset.sh
new file mode 100755
index 00000000..e9a243a8
--- /dev/null
+++ b/scripts/remote-repository-reset.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+# Craig Jennings
+# post archsetup step to reset remote upstream repositories on emacs
+# configuration and doftiles.
+
+cd ~/emacs.d/
+git remote remove origin
+git remote add github git@github.com:cjennings/dotemacs.git
+git remote add origin git@cjennings.net:dotemacs.git
+git branch -M main
+git push -u origin main
+
+
+cd ~/.dotfiles/
+git remote remove origin
+git remote add github git@github.com:cjennings/dotfiles.git
+git remote add origin git@cjennings.net:dotfiles.git
+git branch -M main
+git push -u origin main
diff --git a/scripts/reset-to-first-launch.sh b/scripts/reset-to-first-launch.sh
new file mode 100755
index 00000000..3922aaf8
--- /dev/null
+++ b/scripts/reset-to-first-launch.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+# script for Emacs config testing
+# - clears out all but necessary init/config files
+# - removes native ad bytecode files.
+
+rm -rf ~/.cache/org-persist/
+rm -rf ~/.emacs.d/.cache/
+rm -rf ~/.emacs.d/.elfeed-db/
+rm -rf ~/.emacs.d/auto-save-list/
+rm -rf ~/.emacs.d/backups/
+rm -rf ~/.emacs.d/crossword/
+rm -rf ~/.emacs.d/dirvish/
+rm -rf ~/.emacs.d/eln-cache/
+rm -rf ~/.emacs.d/elpa/
+rm -rf ~/.emacs.d/emojis/
+rm -rf ~/.emacs.d/erc/
+rm -rf ~/.emacs.d/eshell/
+rm -rf ~/.emacs.d/multisession
+rm -rf ~/.emacs.d/nov-places/
+rm -rf ~/.emacs.d/persist/
+rm -rf ~/.emacs.d/quelpa/
+rm -rf ~/.emacs.d/tramp-auto-save/
+rm -rf ~/.emacs.d/transient/
+rm -rf ~/.emacs.d/tree-sitter/
+rm -rf ~/.emacs.d/url/
+rm -rf ~/.emacs.d/var
+rm ~/.emacs.d/.elfeed-db
+rm ~/.emacs.d/.emacs-history
+rm ~/.emacs.d/.lsp-session*
+rm ~/.emacs.d/.org-id-locations
+rm ~/.emacs.d/.pdf-view-restore
+rm ~/.emacs.d/.scratch
+rm ~/.emacs.d/forge-database.sqlite
+rm ~/.emacs.d/forge-database.sqlite
+rm ~/.emacs.d/nov-places
+rm ~/.emacs.d/org-roam.db
+rm ~/.emacs.d/pomm
+rm ~/.emacs.d/projectile-bookmarks.eld
+rm ~/.emacs.d/projects
+rm ~/.emacs.d/recentf
+rm ~/.emacs.d/tramp-connection-history
+rm ~/sync/org/emacs-theme.persist
+
+find ~/.emacs.d -name "*.eln" -type f -delete
+find ~/.emacs.d -name "*.elc" -type f -delete
diff --git a/scripts/setup-email.sh b/scripts/setup-email.sh
new file mode 100755
index 00000000..7607eb61
--- /dev/null
+++ b/scripts/setup-email.sh
@@ -0,0 +1,47 @@
+#!/usr/bin/env bash
+# Craig Jennings <c@cjennings.net>
+
+# Typically run on a fresh installation on a new machine.
+# - Validates all email components of my Emacs email setup are in place
+# - Validates local email directories exist; creates them if they don't exist
+# - Performs initial email sync to local directories
+# - Performs initial email indexing for both of my email accounts
+
+set -euo pipefail
+
+MBSYNC="$(command -v mbsync || true)"
+MU="$(command -v mu || true)"
+MU4EDIR="/usr/share/emacs/site-lisp/mu4e"
+MSMTP="$(command -v msmtp || true)"
+
+MBSYNCRC="$HOME/.mbsyncrc"
+MSMTPRC="$HOME/.msmtprc"
+MAILROOT="$HOME/.mail"
+GMAILDIR="$MAILROOT/gmail"
+CMAILDIR="$MAILROOT/cmail"
+
+# Check All Prerequisites
+[[ -x "$MBSYNC" ]] || { echo "ERROR: mbsync not found. Install 'isync'."; exit 1; }
+[[ -x "$MU" ]] || { echo "ERROR: mu not found. Install 'mu'."; exit 1; }
+[[ -d "$MU4EDIR" ]] || { echo "ERROR: mu4e elisp not found at $MU4EDIR. Install 'mu'."; exit 1; }
+[[ -f "$MBSYNCRC" ]] || { echo "ERROR: '~/.mbsyncrc' missing."; exit 1; }
+[[ -x "$MSMTP" ]] || { echo "ERROR: msmtp not found. Install 'msmtp'."; exit 1; }
+[[ -f "$MSMTPRC" ]] || { echo "ERROR: '~/.msmtprc' missing."; exit 1; }
+
+# Ensure Mail Dirs Exist
+mkdir -p "$GMAILDIR" "$CMAILDIR"
+
+# Initial Sync
+echo "→ syncing all mail with mbsync ..."
+"$MBSYNC" -aV
+
+# Init MU and Index Email
+echo "→ initializing mu ..."
+"$MU" init --maildir="$MAILROOT" \
+ --my-address="craigmartinjennings@gmail.com" \
+ --my-address="c@cjennings.net"
+
+echo "→ indexing mail ..."
+"$MU" index
+
+echo "✅ Mail setup complete."