diff options
Diffstat (limited to 'scripts')
| -rwxr-xr-x | scripts/build-emacs.sh | 246 | ||||
| -rwxr-xr-x | scripts/create-elpa-mirrors.sh | 48 | ||||
| -rwxr-xr-x | scripts/delete-elisp-compiled-files.sh | 24 | ||||
| -rwxr-xr-x | scripts/profile-dotemacs.sh | 20 | ||||
| -rwxr-xr-x | scripts/remote-repository-reset.sh | 19 | ||||
| -rwxr-xr-x | scripts/reset-to-first-launch.sh | 45 | ||||
| -rwxr-xr-x | scripts/setup-email.sh | 47 |
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." |
