diff --git a/bin/check-versions b/bin/check-versions index 9498c44..3fd57df 100755 --- a/bin/check-versions +++ b/bin/check-versions @@ -21,13 +21,23 @@ get_repo_version() { local mirror="$2" local repo_db="$BUILD_ROOT/pkgs.omarchy.org/$mirror/$ARCH/omarchy.db.tar.zst" - if [[ -f "$repo_db" ]]; then - local desc_file - desc_file=$(tar -tf "$repo_db" 2>/dev/null | grep "^${pkg}-[0-9r].*/desc$" | head -1) - if [[ -n "$desc_file" ]]; then - tar -xOf "$repo_db" "$desc_file" 2>/dev/null | awk '/%VERSION%/{getline; print; exit}' - fi - fi + [[ -f "$repo_db" ]] || return 0 + + tar -xOf "$repo_db" --wildcards '*/desc' 2>/dev/null | awk -v pkg="$pkg" ' + function reset() { name=""; base=""; version="" } + function emit() { + if (!found && version != "" && (name == pkg || base == pkg)) { + print version + found=1 + } + reset() + } + $0 == "%FILENAME%" { emit(); next } + $0 == "%NAME%" { if (name != "" && version != "") emit(); getline; name=$0; next } + $0 == "%BASE%" { getline; base=$0; next } + $0 == "%VERSION%" { getline; version=$0; next } + END { emit() } + ' } get_pkgbuild_version() { @@ -37,6 +47,40 @@ get_pkgbuild_version() { fi } +check_vcs_unchanged() { + local pkgdir="$1" + local repo_version="$2" + local pkgbuild="$pkgdir/PKGBUILD" + + [[ -f "$pkgbuild" ]] || return 1 + grep -qE '^pkgver[[:space:]]*\(\)' "$pkgbuild" || return 1 + [[ -n "$repo_version" ]] || return 1 + + # If epoch or pkgrel changed in PKGBUILD, release even if upstream is unchanged. + local pkgbuild_epoch pkgbuild_pkgrel + pkgbuild_epoch=$(cd "$pkgdir" && bash -c 'source PKGBUILD 2>/dev/null; echo "${epoch:-}"') + pkgbuild_pkgrel=$(cd "$pkgdir" && bash -c 'source PKGBUILD 2>/dev/null; echo "${pkgrel}"') + + local repo_pkgrel="${repo_version##*-}" + local repo_no_pkgrel="${repo_version%-*}" + local repo_epoch="" + if [[ "$repo_no_pkgrel" == *:* ]]; then + repo_epoch="${repo_no_pkgrel%%:*}" + fi + + [[ "$pkgbuild_epoch" != "$repo_epoch" ]] && return 1 + [[ "$pkgbuild_pkgrel" != "$repo_pkgrel" ]] && return 1 + + local repo_hash upstream_hash + repo_hash=$(package_extract_vcs_hash_from_version "$repo_version") + [[ -n "$repo_hash" ]] || return 1 + + upstream_hash=$(package_git_upstream_hash "$pkgdir") + [[ -n "$upstream_hash" ]] || return 1 + + [[ "$repo_hash" == "$upstream_hash" ]] +} + check_package() { local pkg="$1" local pkgdir="$2" @@ -50,11 +94,25 @@ check_package() { return 1 fi - if [[ "$pkgbuild_version" != "$repo_version" ]]; then - return 0 + if grep -qE '^pkgver[[:space:]]*\(\)' "$pkgdir/PKGBUILD"; then + if [[ -n "$repo_version" && -n "$(package_extract_vcs_hash_from_version "$repo_version")" ]]; then + if check_vcs_unchanged "$pkgdir" "$repo_version"; then + return 1 + else + return 0 + fi + elif [[ "$pkgbuild_version" == "$repo_version" ]]; then + return 1 + else + return 0 + fi fi - return 1 + if [[ "$pkgbuild_version" == "$repo_version" ]]; then + return 1 + fi + + return 0 } check_mirror() { diff --git a/build/build.sh b/build/build.sh index 5100559..2e346dd 100755 --- a/build/build.sh +++ b/build/build.sh @@ -283,30 +283,9 @@ get_package_deps() { # from the git checkout. Without this check, version comparison always reports a # mismatch and we rebuild on every run, producing a package with the same # name+version as one already in production. Detect this by comparing the -# upstream HEAD commit hash to the hash suffix already in the production version +# upstream commit hash to the hash suffix already in the production version # (both `...gabcdef0` and `...abcdef0` styles are common). Returns 0 when # upstream is unchanged (build can be skipped). -extract_vcs_hash_from_version() { - local version="$1" - local version_no_pkgrel="${version%-*}" - local candidate hash="" - - # Drop an epoch prefix before scanning for commit-looking components. - if [[ "$version_no_pkgrel" == *:* ]]; then - version_no_pkgrel="${version_no_pkgrel#*:}" - fi - - while IFS= read -r candidate; do - # Prefer candidates explicitly prefixed with `g`, but also accept bare hex - # hashes that contain at least one a-f character (e.g. r21251.626ee68). - if [[ "$candidate" == g* || "$candidate" =~ [a-f] ]]; then - hash="${candidate#g}" - fi - done < <(echo "$version_no_pkgrel" | grep -oE 'g?[a-f0-9]{7,40}') - - [[ -n "$hash" ]] && echo "${hash:0:7}" -} - check_vcs_unchanged() { local pkg="$1" local pkgdir="$2" @@ -331,22 +310,13 @@ check_vcs_unchanged() { [[ "$pkgbuild_epoch" != "$prod_epoch" ]] && return 1 [[ "$pkgbuild_pkgrel" != "$prod_pkgrel" ]] && return 1 - # Find the first git+ source URL (skip non-git sources like patch files). - # Bail out on any #fragment (commit/tag/branch pinning) — HEAD comparison - # wouldn't be meaningful there. - local source_url=$(cd "$pkgdir" && bash -c ' - source PKGBUILD 2>/dev/null - for s in "${source[@]}"; do - url="${s#*::}" - [[ "$url" == git+* ]] && { echo "${url#git+}"; break; } - done') - [[ -z "$source_url" ]] && return 1 - [[ "$source_url" == *"#"* ]] && return 1 - - local prod_hash=$(extract_vcs_hash_from_version "$local_version") + # Compare the commit represented in the published version to the current + # upstream ref. Supports unfragmented git sources as well as #branch=, + # #tag=, and #commit= fragments. + local prod_hash=$(package_extract_vcs_hash_from_version "$local_version") [[ -z "$prod_hash" ]] && return 1 - local upstream_hash=$(git ls-remote "$source_url" HEAD 2>/dev/null | awk 'NR==1 {print substr($1, 1, 7)}') + local upstream_hash=$(package_git_upstream_hash "$pkgdir") [[ -z "$upstream_hash" ]] && return 1 [[ "$prod_hash" == "$upstream_hash" ]] @@ -367,10 +337,22 @@ check_needs_build() { # Check if already built local local_version=$(get_local_version "$pkg") + if grep -qE '^pkgver[[:space:]]*\(\)' "$pkgbuild"; then + if [[ -n "$local_version" && -n "$(package_extract_vcs_hash_from_version "$local_version")" ]]; then + if check_vcs_unchanged "$pkg" "$pkgdir"; then + return 1 # VCS upstream ref is already represented in the repo + else + return 0 # New VCS ref, missing repo package, or pkgrel/epoch changed + fi + elif [[ "$local_version" == "$pkgbuild_version" ]]; then + return 1 # VCS package does not expose a hash; fall back to static version + else + return 0 + fi + fi + if [[ "$local_version" == "$pkgbuild_version" ]]; then return 1 # Already up to date - elif check_vcs_unchanged "$pkg" "$pkgdir"; then - return 1 # VCS upstream HEAD is already represented in the repo else return 0 # Needs building fi diff --git a/helpers/package-metadata.sh b/helpers/package-metadata.sh index 68e008b..213de85 100644 --- a/helpers/package-metadata.sh +++ b/helpers/package-metadata.sh @@ -133,6 +133,83 @@ packages_for_mirror() { done } +package_extract_vcs_hash_from_version() { + local version="$1" + local version_no_pkgrel="${version%-*}" + local candidate hash="" + + # Drop an epoch prefix before scanning for commit-looking components. + if [[ "$version_no_pkgrel" == *:* ]]; then + version_no_pkgrel="${version_no_pkgrel#*:}" + fi + + while IFS= read -r candidate; do + # Prefer candidates explicitly prefixed with `g`, but also accept bare hex + # hashes that contain at least one a-f character (e.g. r21251.626ee68). + if [[ "$candidate" == g* || "$candidate" =~ [a-f] ]]; then + hash="${candidate#g}" + fi + done < <(echo "$version_no_pkgrel" | grep -oE 'g?[a-f0-9]{7,40}') + + [[ -n "$hash" ]] && echo "${hash:0:7}" +} + +package_first_git_source() { + local pkgdir="$1" + + (cd "$pkgdir" && env -u OMARCHY_SRC bash -c ' + source PKGBUILD 2>/dev/null + for s in "${source[@]}"; do + url="${s#*::}" + [[ "$url" == git+* ]] && { echo "${url#git+}"; break; } + done') +} + +package_git_upstream_hash() { + local pkgdir="$1" + local source_spec source_url fragment ref hash + + source_spec=$(package_first_git_source "$pkgdir") || return 1 + [[ -n "$source_spec" ]] || return 1 + + source_url="${source_spec%%#*}" + fragment="" + if [[ "$source_spec" == *"#"* ]]; then + fragment="${source_spec#*#}" + fi + + case "$fragment" in + "") + hash=$(git ls-remote "$source_url" HEAD 2>/dev/null | awk 'NR == 1 { print substr($1, 1, 7) }') + ;; + branch=*) + ref="${fragment#branch=}" + [[ -n "$ref" ]] || return 1 + hash=$(git ls-remote "$source_url" "refs/heads/$ref" 2>/dev/null | awk 'NR == 1 { print substr($1, 1, 7) }') + ;; + tag=*) + ref="${fragment#tag=}" + [[ -n "$ref" ]] || return 1 + hash=$(git ls-remote "$source_url" "refs/tags/$ref^{}" "refs/tags/$ref" 2>/dev/null | awk ' + $2 ~ /\^\{\}$/ { print substr($1, 1, 7); found=1; exit } + NR == 1 { first=substr($1, 1, 7) } + END { if (!found && first != "") print first } + ') + ;; + commit=*) + ref="${fragment#commit=}" + [[ "$ref" =~ ^[a-f0-9]{7,40}$ ]] || return 1 + hash="${ref:0:7}" + ;; + *) + return 1 + ;; + esac + + [[ -n "$hash" ]] || return 1 + echo "$hash" +} + validate_package_metadata() { local pkgdir="$1" local metadata source sync aur ring pkgrel_type diff --git a/pkgbuilds/omarchy-dev/.omarchy/package.json b/pkgbuilds/omarchy-dev/.omarchy/package.json new file mode 100644 index 0000000..2a9719d --- /dev/null +++ b/pkgbuilds/omarchy-dev/.omarchy/package.json @@ -0,0 +1,3 @@ +{ + "source": "local" +} diff --git a/pkgbuilds/omarchy-dev/PKGBUILD b/pkgbuilds/omarchy-dev/PKGBUILD new file mode 100644 index 0000000..3d8ea95 --- /dev/null +++ b/pkgbuilds/omarchy-dev/PKGBUILD @@ -0,0 +1,191 @@ +# Maintainer: Ryan Hughes +pkgname='omarchy-dev' +pkgver=4.0.0.r847.g4de185b +pkgrel=1 +_pkgver_base=4.0.0 +_pkgver_base_tag=v3.8.2 +pkgdesc='Beautiful, modern, and opinionated Arch Linux by DHH (omarchy-4 branch tip)' +arch=('any') +url='https://github.com/basecamp/omarchy' +license=('MIT') +provides=('omarchy') +conflicts=('omarchy') +install='omarchy-dev.install' + +# Hard depends: only packages whose removal would brick the desktop. The ISO +# pacstraps the full default install set from install/omarchy-base.packages. +# Keeping optional apps out of hard depends lets users remove them via Omarchy +# commands without pacman refusing because of a hard dependency. +depends=( + # Omarchy meta + 'omarchy-keyring' + 'omarchy-settings-dev' + + # Bootloader stack. Lives here rather than on omarchy-settings because + # omarchy-settings is also installed into the live ISO env (for plymouth + # / /etc/skel seeding), where the limine-mkinitcpio-hook would fail with + # 'Cannot detect an ESP path' inside the chroot. The omarchy-settings + # config drop-ins under /etc/mkinitcpio.conf.d/, /etc/limine-entry-tool.d/, + # and /etc/snapper/config-templates/ only do anything when these are + # installed alongside. + 'limine' + 'limine-mkinitcpio-hook' + 'limine-snapper-sync' + 'snapper' + + # Wayland / Hyprland core + 'hyprland' + 'quickshell' + 'uwsm' + 'sddm' + 'xdg-desktop-portal-hyprland' + + # Audio / auth / portal essentials + 'wireplumber' + 'pipewire' + 'gnome-keyring' + + # Required by omarchy-* scripts and omarchy-shell + 'gum' + 'jq' + 'git' + 'perl' # /usr/bin/omarchy-shell invokes perl directly + + # System font (UI assumes it) + 'ttf-jetbrains-mono-nerd-basic' +) + +makedepends=( + 'git' +) + +optdepends=( + # Development + '1password: Password manager' + '1password-cli: 1Password CLI' + 'github-cli: GitHub CLI tool' + 'lazygit: Terminal UI for git' + 'lazydocker: Terminal UI for docker' + + # Browsers & comms + 'omarchy-chromium-bin: Customized Chromium browser' + 'signal-desktop: Encrypted messaging' + 'spotify: Music streaming' + + # Productivity + 'obsidian: Note-taking app' + 'typora: Markdown editor' + 'libreoffice: Office suite' + + # Media & graphics + 'obs-studio: Screen recording and streaming' + 'mpv: Video player' + 'imv: Image viewer' + 'kdenlive: Video editor' + 'pinta: Image editor' + + # System utilities + 'btop: System monitor' + + # Printing + 'cups: Printing support' + 'system-config-printer: Printer configuration' + + # Hardware support + 'asdcontrol: Apple display brightness control' + 'blueberry: Bluetooth manager' + + # Developer tools + 'cargo: Rust package manager' + 'clang: C/C++ compiler' + 'python-poetry-core: Python packaging' + 'tree-sitter-cli: Parser generator tool' + + # Optional omarchy companion packages +) + +# Source: omarchy-4 branch tip by default; set OMARCHY_SRC=/path/to/checkout +# to build from a local source tree instead (mirrors omarchy-zsh/omarchy-fish DX). +if [[ -n "${OMARCHY_SRC:-}" ]]; then + source=() + sha256sums=() +else + source=("omarchy::git+https://github.com/basecamp/omarchy.git#branch=omarchy-4") + sha256sums=('SKIP') +fi + +pkgver() { + cd "$srcdir/omarchy" + + local commit_count commit_hash + if git rev-parse --verify "${_pkgver_base_tag}^{commit}" >/dev/null 2>&1; then + commit_count=$(git rev-list --count "${_pkgver_base_tag}..HEAD") + else + commit_count=$(git rev-list --count HEAD) + fi + commit_hash=$(git rev-parse --short=7 HEAD) + + printf "%s.r%s.g%s" "$_pkgver_base" "$commit_count" "$commit_hash" +} + +prepare() { + if [[ -n "${OMARCHY_SRC:-}" ]]; then + rm -rf "$srcdir/omarchy" + mkdir -p "$srcdir/omarchy" + cp -a "${OMARCHY_SRC}/." "$srcdir/omarchy/" + fi +} + +package() { + cd "$srcdir/omarchy" + + # Runtime binaries — ship everything in bin/ except the debug helpers + # that ship from omarchy-settings (needed before omarchy is installed, + # e.g. on the ISO live env). + install -d "$pkgdir/usr/bin" "$pkgdir/usr/share/omarchy/bin" + for bin in bin/*; do + [[ -f $bin ]] || continue + local base + base=$(basename "$bin") + case "$base" in + omarchy-debug|omarchy-debug-idle|omarchy-upload-log) + continue + ;; + esac + install -Dm755 "$bin" "$pkgdir/usr/bin/$base" + ln -s "/usr/bin/$base" "$pkgdir/usr/share/omarchy/bin/$base" + done + + install -d "$pkgdir/usr/share/omarchy" + + # Guard direct pacman upgrades from bypassing the Omarchy update pipeline. + # Ship the hook with its Exec target so package skew cannot leave a broken + # hook pointing at a missing binary. + install -Dm644 default/libalpm/hooks/00-omarchy-update-guard.hook "$pkgdir/usr/share/libalpm/hooks/00-omarchy-update-guard.hook" + + # Target-side setup scripts and package lists used by ISO finalization, + # first login, future users, migrations, and reinstall/reset commands. + cp -a install "$pkgdir/usr/share/omarchy/" + + # Theme bundles for theme switching. + cp -a themes "$pkgdir/usr/share/omarchy/" + + # Versioned migrations runner reads from this tree. + cp -a migrations "$pkgdir/usr/share/omarchy/" + + # Fresh users created after install are already on the package layout in this + # build, so seed user migration markers through /etc/skel. Existing users keep + # their own state and still run pending user migrations on update. + if compgen -G 'migrations/user/*.sh' >/dev/null; then + install -d "$pkgdir/etc/skel/.local/state/omarchy/migrations/user" + for migration in migrations/user/*.sh; do + touch "$pkgdir/etc/skel/.local/state/omarchy/migrations/user/$(basename "$migration")" + done + fi + + # Quickshell desktop shell tree. + cp -a shell "$pkgdir/usr/share/omarchy/" + + # Runtime version file. + install -Dm644 version "$pkgdir/usr/share/omarchy/version" +} diff --git a/pkgbuilds/omarchy-dev/omarchy-dev.install b/pkgbuilds/omarchy-dev/omarchy-dev.install new file mode 100644 index 0000000..9b7a0bf --- /dev/null +++ b/pkgbuilds/omarchy-dev/omarchy-dev.install @@ -0,0 +1,5 @@ +post_upgrade() { + if [ -x /usr/bin/omarchy-migrate-system ]; then + /usr/bin/omarchy-migrate-system + fi +} diff --git a/pkgbuilds/omarchy-nvim/PKGBUILD b/pkgbuilds/omarchy-nvim/PKGBUILD index 5d497e7..6f7f949 100644 --- a/pkgbuilds/omarchy-nvim/PKGBUILD +++ b/pkgbuilds/omarchy-nvim/PKGBUILD @@ -1,7 +1,7 @@ # Maintainer: Ryan Hughes pkgname=omarchy-nvim pkgver=2026.5.25 -pkgrel=1 +pkgrel=2 pkgdesc="Pre-built LazyVim configuration with cached plugins" arch=('any') url="https://github.com/LazyVim/LazyVim" @@ -43,6 +43,16 @@ build() { "+qa!" || true } +restore_lazy_worktrees() { + local data_dir="$1" + local dir + + for dir in "$data_dir"/lazy/*/; do + [[ -d "$dir/.git" ]] || continue + git --git-dir="$dir/.git" --work-tree="$dir" restore . + done +} + package() { cd "$srcdir" @@ -59,6 +69,22 @@ package() { chmod -R 755 "$pkgdir/usr/share/$pkgname" find "$pkgdir/usr/share/$pkgname" -type f -exec chmod 644 {} \; - # Install setup script to /usr/bin + # Restore plugin worktree modes after the package-wide chmod so users seeded + # from /etc/skel do not need a first-login omarchy-nvim-setup cleanup pass. + restore_lazy_worktrees "$pkgdir/usr/share/$pkgname/data" + + # Seed new users via /etc/skel. The installer installs omarchy-nvim before + # creating the first user, so this handles initial ISO installs and future + # users without an extra overwrite step. + install -dm755 "$pkgdir/etc/skel/.config" "$pkgdir/etc/skel/.local/share" + cp -a "$pkgdir/usr/share/$pkgname/config" "$pkgdir/etc/skel/.config/nvim" + cp -a "$pkgdir/usr/share/$pkgname/data" "$pkgdir/etc/skel/.local/share/nvim" + ln -snf "../../../omarchy/current/theme/neovim.lua" \ + "$pkgdir/etc/skel/.config/nvim/lua/plugins/theme.lua" + + # Install setup/refresh commands to /usr/bin. setup fills missing pieces; + # refresh explicitly backs up and overwrites with the same /etc/skel defaults + # used for newly-created users. install -Dm755 "$startdir/omarchy-nvim-setup" "$pkgdir/usr/bin/omarchy-nvim-setup" + ln -s omarchy-nvim-setup "$pkgdir/usr/bin/omarchy-nvim-refresh" } diff --git a/pkgbuilds/omarchy-nvim/omarchy-nvim-setup b/pkgbuilds/omarchy-nvim/omarchy-nvim-setup index 4c136c4..5859e5e 100755 --- a/pkgbuilds/omarchy-nvim/omarchy-nvim-setup +++ b/pkgbuilds/omarchy-nvim/omarchy-nvim-setup @@ -1,62 +1,133 @@ #!/bin/bash -# Setup script for omarchy-nvim -# This can be called from Omarchy setup scripts +# Setup/refresh script for omarchy-nvim +# +# omarchy-nvim-setup: install missing config/data for the current user. +# omarchy-nvim-refresh: back up existing config, reset cached data, and copy +# the skel-seeded Omarchy Neovim defaults again. set -euo pipefail +SKEL_CONFIG_DIR="/etc/skel/.config/nvim" +SKEL_DATA_DIR="/etc/skel/.local/share/nvim" PACKAGE_DIR="/usr/share/omarchy-nvim" +CONFIG_SOURCE_DIR="$SKEL_CONFIG_DIR" +DATA_SOURCE_DIR="$SKEL_DATA_DIR" CONFIG_DIR="${HOME}/.config/nvim" DATA_DIR="${HOME}/.local/share/nvim" STATE_DIR="${HOME}/.local/state/nvim" CACHE_DIR="${HOME}/.cache/nvim" -# Check if package is installed -if [[ ! -d "$PACKAGE_DIR" ]]; then - echo "Error: omarchy-nvim package not installed" +command_name="$(basename "$0")" +refresh=false + +if [[ $command_name == "omarchy-nvim-refresh" ]]; then + refresh=true +fi + +while (( $# > 0 )); do + case "$1" in + --force|--refresh) + refresh=true + ;; + -h|--help) + cat <<'EOF' +Usage: omarchy-nvim-setup [--force] + omarchy-nvim-refresh + +omarchy-nvim-setup installs Omarchy's skel-seeded Neovim config/data only when +missing. omarchy-nvim-refresh backs up an existing config and overwrites it with +the skel-seeded defaults. +EOF + exit 0 + ;; + *) + echo "Unknown option: $1" >&2 + exit 1 + ;; + esac + shift +done + +# Prefer /etc/skel so legacy setup/refresh uses the exact seed copied into new +# users' homes. Fall back to the package share dir for older package layouts. +if [[ ! -d "$CONFIG_SOURCE_DIR" || ! -d "$DATA_SOURCE_DIR" ]]; then + CONFIG_SOURCE_DIR="$PACKAGE_DIR/config" + DATA_SOURCE_DIR="$PACKAGE_DIR/data" +fi + +if [[ ! -d "$CONFIG_SOURCE_DIR" || ! -d "$DATA_SOURCE_DIR" ]]; then + echo "Error: omarchy-nvim defaults not found; is omarchy-nvim installed?" >&2 exit 1 fi -# Check if nvim config already exists -if [[ -d "$CONFIG_DIR" ]]; then - if gum confirm "$(echo -e "Neovim configuration already exists at $CONFIG_DIR.\nThis will create a backup and overwrite it. Continue?")"; then - # Backup existing config - BACKUP_DIR="${CONFIG_DIR}.backup.$(date +%Y%m%d-%H%M%S)" - echo "Backing up existing config to $BACKUP_DIR" - mv "$CONFIG_DIR" "$BACKUP_DIR" - else - echo "Setup cancelled." - exit 0 +backup_path() { + local path="$1" + local backup="${path}.backup.$(date +%Y%m%d-%H%M%S)" + + if [[ -e $path || -L $path ]]; then + echo "Backing up $path to $backup" + mv "$path" "$backup" + fi +} + +copy_tree() { + local src="$1" + local dest="$2" + + mkdir -p "$(dirname "$dest")" + cp -a "$src" "$dest" +} + +install_config() { + if [[ -d "$CONFIG_DIR" && $refresh != true ]]; then + echo "Neovim config already exists at $CONFIG_DIR; leaving it in place." + return + fi + + backup_path "$CONFIG_DIR" + copy_tree "$CONFIG_SOURCE_DIR" "$CONFIG_DIR" + echo "Installed Neovim config to $CONFIG_DIR" +} + +install_data() { + if [[ -d "$DATA_DIR" && $refresh != true ]]; then + echo "Neovim data already exists at $DATA_DIR; leaving it in place." + return + fi + + if [[ $refresh == true ]]; then + rm -rf "$DATA_DIR" "$CACHE_DIR" "$STATE_DIR" + fi + + copy_tree "$DATA_SOURCE_DIR" "$DATA_DIR" + echo "Installed Neovim data to $DATA_DIR" +} + +install_config +install_data + +# Files copied into $HOME by the install user already have the right owner. +# Only adjust ownership when this script is explicitly run as root. +if (( EUID == 0 )); then + target_user="${SUDO_USER:-${USER:-root}}" + if [[ $target_user != "root" ]]; then + chown -R "${target_user}:${target_user}" "$CONFIG_DIR" "$DATA_DIR" fi fi -echo "Setting up Neovim configuration..." +# Use a relative symlink so the same config works from /etc/skel and from any +# user's home directory. +mkdir -p "${CONFIG_DIR}/lua/plugins" +ln -snf "../../../omarchy/current/theme/neovim.lua" "${CONFIG_DIR}/lua/plugins/theme.lua" -# Make sure everything is clear -rm -rf $DATA_DIR $CACHE_DIR $STATE_DIR - -# Create directories if needed -mkdir -p "$(dirname "$CONFIG_DIR")" -mkdir -p "$(dirname "$DATA_DIR")" - -# Copy files (cache will be regenerated on first use) -cp -r "$PACKAGE_DIR/config" "$CONFIG_DIR" -cp -r "$PACKAGE_DIR/data" "$DATA_DIR" - -# Ensure proper ownership of all nvim directories -chown -R "${USER}:${USER}" "$CONFIG_DIR" -chown -R "${USER}:${USER}" "$DATA_DIR" - -# Create link for current theme -ln -snf "${HOME}/.config/omarchy/current/theme/neovim.lua" "${CONFIG_DIR}/lua/plugins/theme.lua" - -# Restore git working trees -for dir in $DATA_DIR/lazy/*/; do - if [ -d "$dir/.git" ]; then +# Restore git working trees from the packaged lazy plugin cache. +for dir in "$DATA_DIR"/lazy/*/; do + if [[ -d "$dir/.git" ]]; then git --git-dir="$dir/.git" --work-tree="$dir" restore . fi done -# Set nvim.desktop as default so it takes priority in Nautilus +# Set nvim.desktop as default so it takes priority in Nautilus. xdg-mime default nvim.desktop text/plain xdg-mime default nvim.desktop text/english xdg-mime default nvim.desktop text/x-makefile @@ -75,4 +146,8 @@ xdg-mime default nvim.desktop text/x-c++ xdg-mime default nvim.desktop application/xml xdg-mime default nvim.desktop text/xml -echo "Neovim setup complete!" +if [[ $refresh == true ]]; then + echo "Neovim refresh complete!" +else + echo "Neovim setup complete!" +fi diff --git a/pkgbuilds/omarchy-settings-dev/.omarchy/package.json b/pkgbuilds/omarchy-settings-dev/.omarchy/package.json new file mode 100644 index 0000000..2a9719d --- /dev/null +++ b/pkgbuilds/omarchy-settings-dev/.omarchy/package.json @@ -0,0 +1,3 @@ +{ + "source": "local" +} diff --git a/pkgbuilds/omarchy-settings-dev/PKGBUILD b/pkgbuilds/omarchy-settings-dev/PKGBUILD new file mode 100644 index 0000000..8c29bae --- /dev/null +++ b/pkgbuilds/omarchy-settings-dev/PKGBUILD @@ -0,0 +1,327 @@ +# Maintainer: Ryan Hughes +pkgname='omarchy-settings-dev' +pkgver=4.0.0.r847.g4de185b +pkgrel=1 +_pkgver_base=4.0.0 +_pkgver_base_tag=v3.8.2 +pkgdesc='Omarchy user defaults, /etc/skel content, fonts, plymouth theme, and support helpers (omarchy-4 branch tip)' +arch=('any') +url='https://github.com/basecamp/omarchy' +license=('MIT') +provides=('omarchy-settings') +conflicts=('omarchy-settings') + +# `/etc/default/limine` is intentionally NOT owned by this package. The ISO +# orchestrator generates it at install time from the resolved target boot +# cmdline. We ship a template under /usr/share/omarchy/default/limine/ for the +# orchestrator to read. +# +# limine + limine-mkinitcpio-hook + limine-snapper-sync + snapper are NOT in +# depends because this package gets installed into the live ISO env (for +# plymouth / /etc/skel seeding) where there is no ESP and the mkinitcpio hook +# would fail trying to deploy Limine. The bootloader stack is pulled in by +# the omarchy package on the target install, and by EARLY_BOOTSTRAP_PACKAGES +# in omarchy-iso/orchestrator/phases_impl.py for the target chroot. +depends=( + 'bash' + 'curl' + 'gum' + 'hicolor-icon-theme' + 'plymouth' +) + +makedepends=( + 'git' + 'imagemagick' +) + +# backup=() is pacman's hook for protecting user edits to package-owned files +# on upgrade. Only the paths the package actually installs into /etc qualify. +# The etc-overrides set (faillock.conf, nsswitch.conf, cups-browsed.conf, +# plymouthd.conf, /etc/skel/.bashrc) ships at /usr/share/omarchy/etc-overrides/ +# and is cp -f'd by post_install — those paths are unowned by pacman and the +# scriptlet WILL clobber user edits on each upgrade (documented limitation). +backup=( + 'etc/fastfetch/config.jsonc' + 'etc/mkinitcpio.conf.d/omarchy_hooks.conf' + 'etc/mkinitcpio.conf.d/thunderbolt_module.conf' + 'etc/limine-entry-tool.d/omarchy-defaults.conf' + 'etc/limine-entry-tool.d/omarchy-uki.conf' + 'etc/docker/daemon.json' + 'etc/gnupg/dirmngr.conf' + 'etc/sysctl.d/99-omarchy-sysctl.conf' + 'etc/sysctl.d/90-omarchy-file-watchers.conf' + 'etc/modprobe.d/omarchy-usb-autosuspend.conf' + 'etc/systemd/logind.conf.d/10-ignore-power-button.conf' + 'etc/systemd/resolved.conf.d/10-disable-multicast.conf' + 'etc/systemd/resolved.conf.d/20-docker-dns.conf' + 'etc/systemd/system.conf.d/10-faster-shutdown.conf' + 'etc/systemd/system/user@.service.d/10-faster-shutdown.conf' + 'etc/systemd/system/docker.service.d/no-block-boot.conf' + 'etc/systemd/system/plocate-updatedb.service.d/ac-only.conf' + 'etc/systemd/system.conf.d/20-omarchy-nofile.conf' + 'etc/systemd/user.conf.d/20-omarchy-nofile.conf' + 'etc/sddm.conf.d/10-theme.conf' + 'etc/sddm.conf.d/10-wayland.conf' + 'etc/udev/rules.d/99-omarchy-power-profile.rules' + 'etc/udev/rules.d/99-omarchy-wifi-powersave.rules' +) + +optdepends=( + 'omarchy-dev: Full Omarchy desktop (omarchy-4 branch tip)' + 'inxi: System information for omarchy-debug' + 'fastfetch: System information for omarchy-upload-log' + 'limine: Bootloader the shipped /etc/mkinitcpio.conf.d/ and /etc/limine-entry-tool.d/ drop-ins are for' + 'limine-mkinitcpio-hook: Picks up the shipped /etc/mkinitcpio.conf.d/omarchy_hooks.conf' + 'limine-snapper-sync: Boot-entry sync for snapper snapshots' + 'snapper: Used with the shipped /etc/snapper/config-templates/omarchy template' +) + +install='omarchy-settings-dev.install' + +# Live config files the package can't own outright (the path is owned by an +# upstream Arch package): ship them at /usr/share/omarchy/etc-overrides/ and +# cp -f into place from post_install. See omarchy-settings-dev.install. +_etc_override_paths=( + 'etc/security/faillock.conf' + 'etc/nsswitch.conf' + 'etc/cups/cups-browsed.conf' + 'etc/plymouth/plymouthd.conf' +) + +# Source: omarchy-4 branch tip by default; set OMARCHY_SRC=/path/to/checkout +# to build from a local source tree instead (mirrors omarchy-zsh/omarchy-fish DX). +if [[ -n "${OMARCHY_SRC:-}" ]]; then + source=() + sha256sums=() +else + source=("omarchy::git+https://github.com/basecamp/omarchy.git#branch=omarchy-4") + sha256sums=('SKIP') +fi + +pkgver() { + cd "$srcdir/omarchy" + + local commit_count commit_hash + if git rev-parse --verify "${_pkgver_base_tag}^{commit}" >/dev/null 2>&1; then + commit_count=$(git rev-list --count "${_pkgver_base_tag}..HEAD") + else + commit_count=$(git rev-list --count HEAD) + fi + commit_hash=$(git rev-parse --short=7 HEAD) + + printf "%s.r%s.g%s" "$_pkgver_base" "$commit_count" "$commit_hash" +} + +prepare() { + if [[ -n "${OMARCHY_SRC:-}" ]]; then + rm -rf "$srcdir/omarchy" + mkdir -p "$srcdir/omarchy" + cp -a "${OMARCHY_SRC}/." "$srcdir/omarchy/" + fi +} + +package() { + cd "$srcdir/omarchy" + + # /etc/skel/.config from config/** — system-wide default user config. + # Package-owned defaults that live elsewhere in the system belong under + # default/** or etc/** instead. + install -d "$pkgdir/etc/skel/.config" + cp -a config/. "$pkgdir/etc/skel/.config/" + + # Fastfetch reads /etc/fastfetch/config.jsonc when no user config exists. + install -Dm644 etc/fastfetch/config.jsonc "$pkgdir/etc/fastfetch/config.jsonc" + + # ALSO ship config/** under /usr/share/omarchy/config/. Used as the + # source-of-truth by omarchy-refresh-config, omarchy-reinstall-configs, + # and other commands that copy individual files into a running user's + # ~/.config. /etc/skel only seeds new users; this tree is what existing + # users re-sync against. + install -d "$pkgdir/usr/share/omarchy/config" + cp -a config/. "$pkgdir/usr/share/omarchy/config/" + + # Package-owned defaults with real system/XDG locations. User config remains + # higher priority: ~/.config/uwsm/default, ~/.config/uwsm/env.d, + # ~/.config/environment.d, ~/.config/fontconfig, ~/.config/xdg-terminals.list, + # ~/.config/mimeapps.list, and ~/.config/systemd/user can all override these. + install -Dm644 default/uwsm/env.d/10-omarchy "$pkgdir/usr/share/uwsm/env.d/10-omarchy" + install -Dm644 default/environment.d/10-omarchy-fcitx.conf "$pkgdir/usr/lib/environment.d/10-omarchy-fcitx.conf" + install -Dm644 default/fontconfig/conf.avail/30-omarchy.conf "$pkgdir/usr/share/fontconfig/conf.avail/30-omarchy.conf" + install -d "$pkgdir/etc/fonts/conf.d" + ln -sfn /usr/share/fontconfig/conf.avail/30-omarchy.conf "$pkgdir/etc/fonts/conf.d/30-omarchy.conf" + install -Dm644 default/xdg-terminal-exec/hyprland-xdg-terminals.list "$pkgdir/usr/share/xdg-terminal-exec/hyprland-xdg-terminals.list" + install -Dm644 default/applications/mimeapps.list "$pkgdir/usr/share/applications/mimeapps.list" + install -Dm644 default/systemd/user/bt-agent.service "$pkgdir/usr/lib/systemd/user/bt-agent.service" + install -Dm644 default/systemd/user/omarchy-sleep-lock.service "$pkgdir/usr/lib/systemd/user/omarchy-sleep-lock.service" + install -Dm644 default/systemd/user/omarchy-recover-internal-monitor.service "$pkgdir/usr/lib/systemd/user/omarchy-recover-internal-monitor.service" + install -Dm644 default/systemd/user/omarchy-update-user-notify.service "$pkgdir/usr/lib/systemd/user/omarchy-update-user-notify.service" + install -Dm644 default/systemd/user/omarchy-update-user-notify.path "$pkgdir/usr/lib/systemd/user/omarchy-update-user-notify.path" + + # Same for applications/** — used by omarchy-refresh-applications, + # omarchy-install-gaming-*, etc. to copy .desktop files into ~/.local/share. + install -d "$pkgdir/usr/share/omarchy/applications" + cp -a applications/. "$pkgdir/usr/share/omarchy/applications/" + # Icons are package-owned below in /usr/share/icons/hicolor, not this + # historical app-local folder. + rm -rf "$pkgdir/usr/share/omarchy/applications/icons" + + # /etc tree (drop-ins the package fully owns + the etc-override files we + # stage separately below). + install -d "$pkgdir/etc" + cp -a etc/. "$pkgdir/etc/" + # sudoers.d files must be mode 0440 or sudo will refuse them, and the + # directory must be 0750 to match the Arch sudo package's filesystem + # convention (otherwise pacman warns about dir-mode drift on every install). + if [[ -d "$pkgdir/etc/sudoers.d" ]]; then + chmod 0750 "$pkgdir/etc/sudoers.d" + chmod 0440 "$pkgdir/etc/sudoers.d"/* + fi + + # Stage upstream-owned files at /usr/share/omarchy/etc-overrides/ instead of + # owning their live /etc paths directly (which would conflict with pam, + # filesystem, cups-browsed, plymouth, bash). post_install copies them in. + install -d "$pkgdir/usr/share/omarchy/etc-overrides" + install -Dm644 default/bashrc \ + "$pkgdir/usr/share/omarchy/etc-overrides/dot.bashrc" + cat >"$pkgdir/usr/share/omarchy/etc-overrides/os-release" </dev/null || true + rmdir "$pkgdir/etc/cups" 2>/dev/null || true + rmdir "$pkgdir/etc/plymouth" 2>/dev/null || true + + # /etc/skel/.local/share/applications from applications/**. + install -d "$pkgdir/etc/skel/.local/share/applications" + if compgen -G 'applications/*.desktop' >/dev/null; then + cp applications/*.desktop "$pkgdir/etc/skel/.local/share/applications/" + fi + if [[ -d applications/hidden ]] && compgen -G 'applications/hidden/*.desktop' >/dev/null; then + cp applications/hidden/*.desktop "$pkgdir/etc/skel/.local/share/applications/" + fi + + # Package-owned application icons in standard freedesktop hicolor paths. + # Desktop files and generated webapp/TUI launchers reference these by icon + # name, so user setup no longer needs to copy static Omarchy icons into + # ~/.local/share. + if [[ -d applications/icons ]] && compgen -G 'applications/icons/*' >/dev/null; then + install -d "$pkgdir/usr/share/icons/hicolor/256x256/apps" + install -d "$pkgdir/usr/share/icons/hicolor/48x48/apps" + for icon in applications/icons/*; do + [[ -f $icon ]] || continue + icon_name=$(basename "$icon") + icon_id=$(printf '%s\n' "${icon_name%.*}" \ + | tr '[:upper:]' '[:lower:]' \ + | sed 's/[^[:alnum:]]\+/-/g; s/^-//; s/-$//') + case "$icon_name" in + *.svg) + install -Dm644 "$icon" "$pkgdir/usr/share/icons/hicolor/scalable/apps/$icon_id.svg" + ;; + *) + magick "$icon" -thumbnail 256x256 -background transparent -gravity center -extent 256x256 \ + "PNG32:$pkgdir/usr/share/icons/hicolor/256x256/apps/$icon_id.png" + magick "$icon" -thumbnail 48x48 -background transparent -gravity center -extent 48x48 \ + "PNG32:$pkgdir/usr/share/icons/hicolor/48x48/apps/$icon_id.png" + ;; + esac + done + fi + + # default/** ships to /usr/share/omarchy/default/. The snapper template is + # additionally installed to /etc/snapper/config-templates/ below so snapper + # can pick it up at install time without separate handling. + install -d "$pkgdir/usr/share/omarchy/default" + cp -a default/. "$pkgdir/usr/share/omarchy/default/" + + # Snapper config template used by the install-time `snapper create-config`. + install -Dm644 default/snapper/root \ + "$pkgdir/etc/snapper/config-templates/omarchy" + + # SDDM theme/session assets. These are static package-owned files; the + # installer only writes autologin.conf because that embeds the install user. + install -d -m 0755 "$pkgdir/usr/share/sddm/themes" + cp -a default/sddm/omarchy "$pkgdir/usr/share/sddm/themes/" + find "$pkgdir/usr/share/sddm/themes/omarchy" -type d -exec chmod 0755 {} + + find "$pkgdir/usr/share/sddm/themes/omarchy" -type f -exec chmod 0644 {} + + install -Dm644 default/sddm/hyprland.lua "$pkgdir/usr/share/sddm/hyprland.lua" + install -Dm644 default/wayland-sessions/omarchy.desktop \ + "$pkgdir/usr/local/share/wayland-sessions/omarchy.desktop" + + # Plymouth theme. Files at 0644, dirs at 0755 (the upstream plymouth + # package's convention for /usr/share/plymouth/themes/*). cp -a inherits + # the source dir's mode, which is whatever the build host has — chmod + # explicitly so installs are consistent regardless of build environment. + install -d -m 0755 "$pkgdir/usr/share/plymouth/themes/omarchy" + cp -a default/plymouth/. "$pkgdir/usr/share/plymouth/themes/omarchy/" + find "$pkgdir/usr/share/plymouth/themes/omarchy" -type d -exec chmod 0755 {} + + find "$pkgdir/usr/share/plymouth/themes/omarchy" -type f -exec chmod 0644 {} + + + # System font. + install -Dm644 default/fonts/omarchy/omarchy.ttf "$pkgdir/usr/share/fonts/omarchy/omarchy.ttf" + + # systemd system-sleep hook (lazy-unmounts gvfsd-fuse mounts before + # suspend/hibernate). The script also ships under /usr/share/omarchy/default + # via the default/** copy above; we additionally install it to the live + # systemd path so the hook fires. + install -Dm755 default/systemd/system-sleep/unmount-fuse \ + "$pkgdir/usr/lib/systemd/system-sleep/unmount-fuse" + + # Branding assets (logos, icons). + install -Dm644 logo.txt "$pkgdir/usr/share/omarchy/logo.txt" + install -Dm644 logo.svg "$pkgdir/usr/share/omarchy/logo.svg" + install -Dm644 icon.txt "$pkgdir/usr/share/omarchy/icon.txt" + install -Dm644 icon.png "$pkgdir/usr/share/omarchy/icon.png" + + # Standard icon-theme locations so os-release's LOGO=omarchy resolves in + # desktop/system-info tools that use the freedesktop icon lookup rules. + install -Dm644 icon.png "$pkgdir/usr/share/pixmaps/omarchy.png" + install -Dm644 icon.png "$pkgdir/usr/share/icons/hicolor/256x256/apps/omarchy.png" + + # Seed the user-editable branding files into /etc/skel so fresh users + # have working defaults for `omarchy screensaver` and the About screen + # from the moment they're created. omarchy-reinstall-configs refreshes + # these from the /usr/share/omarchy/ sources for existing users. + install -Dm644 logo.txt "$pkgdir/etc/skel/.config/omarchy/branding/screensaver.txt" + install -Dm644 icon.txt "$pkgdir/etc/skel/.config/omarchy/branding/about.txt" + + # Other static per-user defaults seeded via /etc/skel for new users. + # omarchy-finalize-user no longer copies these into $HOME; existing users + # resync via omarchy-reinstall-configs. + install -Dm644 default/hypr/toggles/flags.lua \ + "$pkgdir/etc/skel/.local/state/omarchy/toggles/hypr/flags.lua" + install -Dm644 default/nautilus-python/extensions/localsend.py \ + "$pkgdir/etc/skel/.local/share/nautilus-python/extensions/localsend.py" + install -Dm644 default/nautilus-python/extensions/transcode.py \ + "$pkgdir/etc/skel/.local/share/nautilus-python/extensions/transcode.py" + + # Support binaries needed before the full omarchy package is installed + # (used by ISO/recovery flows). + install -Dm755 bin/omarchy-upload-log "$pkgdir/usr/bin/omarchy-upload-log" + install -Dm755 bin/omarchy-debug "$pkgdir/usr/bin/omarchy-debug" + install -Dm755 bin/omarchy-debug-idle "$pkgdir/usr/bin/omarchy-debug-idle" +} diff --git a/pkgbuilds/omarchy-settings-dev/omarchy-settings-dev.install b/pkgbuilds/omarchy-settings-dev/omarchy-settings-dev.install new file mode 100644 index 0000000..9f5b058 --- /dev/null +++ b/pkgbuilds/omarchy-settings-dev/omarchy-settings-dev.install @@ -0,0 +1,39 @@ +_etc_overrides_apply() { + echo "Applying Omarchy etc-overrides..." + + # Ensure parent dirs exist. cups-browsed may not be installed yet during ISO + # bootstrap; do not create /etc/cups/cups-browsed.conf before the package is + # installed or pacman will preserve its packaged file as a noisy .pacnew. + install -d /etc/plymouth /etc/security /etc/skel + + # NOTE: these cp -f's are intentionally destructive on every install/upgrade. + # Users who customize /etc/os-release, /etc/plymouth/plymouthd.conf (theme + # switch), /etc/cups/cups-browsed.conf, /etc/nsswitch.conf, + # /etc/security/faillock.conf, or /etc/skel/.bashrc WILL have their changes + # reset to Omarchy defaults each time omarchy-settings-dev is upgraded. This is + # the trade-off of routing upstream-owned paths through etc-overrides instead + # of pacman backup=(). + rm -f /etc/os-release + cp -f /usr/share/omarchy/etc-overrides/os-release /etc/os-release + cp -f /usr/share/omarchy/etc-overrides/security-faillock.conf /etc/security/faillock.conf + cp -f /usr/share/omarchy/etc-overrides/nsswitch.conf /etc/nsswitch.conf + if [[ -f /etc/cups/cups-browsed.conf ]]; then + install -d /etc/cups + cp -f /usr/share/omarchy/etc-overrides/cups-cups-browsed.conf /etc/cups/cups-browsed.conf + fi + cp -f /usr/share/omarchy/etc-overrides/plymouth-plymouthd.conf /etc/plymouth/plymouthd.conf + cp -f /usr/share/omarchy/etc-overrides/dot.bashrc /etc/skel/.bashrc + chmod 0644 /etc/os-release /etc/security/faillock.conf /etc/nsswitch.conf \ + /etc/plymouth/plymouthd.conf /etc/skel/.bashrc + if [[ -f /etc/cups/cups-browsed.conf ]]; then + chmod 0644 /etc/cups/cups-browsed.conf + fi +} + +post_install() { + _etc_overrides_apply +} + +post_upgrade() { + _etc_overrides_apply +} diff --git a/pkgbuilds/omarchy-zsh/PKGBUILD b/pkgbuilds/omarchy-zsh/PKGBUILD index 2939ae5..e89c822 100644 --- a/pkgbuilds/omarchy-zsh/PKGBUILD +++ b/pkgbuilds/omarchy-zsh/PKGBUILD @@ -7,7 +7,7 @@ pkgdesc="Omarchy shell configuration for Zsh" arch=('any') url="https://github.com/omacom-io/omarchy-zsh" license=('MIT') -depends=('zsh' 'eza' 'mise' 'zoxide' 'starship' 'fzf' 'fd' 'bat' 'zsh-autosuggestions' 'zsh-syntax-highlighting') +depends=('zsh' 'eza' 'mise' 'zoxide' 'starship' 'fzf' 'fd' 'bat' 'zsh-syntax-highlighting') options=('!debug') install=omarchy-zsh.install source=("${pkgname}-${pkgver}.tar.gz::${url}/archive/refs/tags/v${pkgver}.tar.gz"