Remove hot link / unlink bits

This commit is contained in:
Ryan Hughes
2026-06-08 12:03:40 -04:00
parent 38bb61b685
commit 64581ec289
9 changed files with 130 additions and 150 deletions
+23 -42
View File
@@ -1,26 +1,24 @@
#!/bin/bash
# omarchy:summary=Point Omarchy at a local checkout for live editing
# omarchy:summary=Point Omarchy at a local checkout after reboot
# omarchy:group=dev
# omarchy:args=<path-to-checkout>
# omarchy:examples=omarchy dev link ~/Work/omarchy/omarchy-installer
set -euo pipefail
# Sudo wipes HYPRLAND_INSTANCE_SIGNATURE, so the live-session refresh below
# can't reach hyprctl. Run as user; we sudo internally for the conf write.
if [[ $EUID -eq 0 ]]; then
if (( EUID == 0 )); then
echo "Error: run omarchy-dev-link as your user, not under sudo." >&2
exit 1
fi
if [[ $# -ne 1 || $1 == "-h" || $1 == "--help" ]]; then
if (( $# != 1 )) || [[ $1 == "-h" || $1 == "--help" ]]; then
cat <<USAGE
Usage: omarchy dev link <path-to-checkout>
Writes /etc/omarchy.conf so OMARCHY_PATH resolves to <path-to-checkout>
in all new shells, the Hyprland session, and Quickshell. Restarts
omarchy-shell and reloads hyprctl so changes take effect immediately.
after reboot. This intentionally does not rewrite the running Hyprland,
systemd, shell, or app-launcher environment; reboot to make every layer agree.
Affects only \$OMARCHY_PATH-resolved trees: bin/, default/, shell/,
themes/, applications/, config/. Files installed at fixed system paths
@@ -31,50 +29,33 @@ USAGE
exit 0
fi
omarchy_conf_quote() {
local value="$1"
value=${value//\\/\\\\}
value=${value//\"/\\\"}
value=${value//\$/\\\$}
value=${value//\`/\\\`}
printf '"%s"' "$value"
}
target=$(realpath -e "$1" 2>/dev/null) || {
echo "Error: path does not exist: $1" >&2
exit 1
}
for required in bin default shell; do
if [[ ! -d "$target/$required" ]]; then
if [[ ! -d $target/$required ]]; then
echo "Warning: $target/$required not found — does this look like an Omarchy source checkout?" >&2
fi
done
# Strip any previous dev-link's bin/ from PATH before adding the new one,
# so repeated link calls don't accumulate stale entries.
prior_target=""
if [[ -f /etc/omarchy.conf ]]; then
prior_target=$(sed -n 's/^[[:space:]]*export[[:space:]]\+OMARCHY_PATH="\?\([^"]*\)"\?/\1/p' /etc/omarchy.conf | tail -1)
fi
echo "Pointing Omarchy at $target"
printf 'export OMARCHY_PATH="%s"\n' "$target" | sudo tee /etc/omarchy.conf >/dev/null
export OMARCHY_PATH="$target"
if [[ -n $prior_target && $prior_target != "$target" ]]; then
PATH=$(printf '%s' "$PATH" | tr ':' '\n' | grep -vFx "$prior_target/bin" | paste -sd:)
fi
export PATH="$target/bin:$PATH"
if command -v hyprctl >/dev/null 2>&1 && hyprctl version &>/dev/null; then
hyprctl setenv OMARCHY_PATH "$target" >/dev/null
hyprctl setenv PATH "$PATH" >/dev/null
echo " Updated Hyprland session env."
systemctl --user import-environment OMARCHY_PATH PATH 2>/dev/null || true
echo " Updated systemd --user env."
if pgrep -x quickshell >/dev/null 2>&1; then
omarchy-restart-shell
echo " Restarted omarchy-shell."
fi
hyprctl reload >/dev/null
echo " Reloaded Hyprland config."
fi
{
printf 'export OMARCHY_PATH='
omarchy_conf_quote "$target"
printf '\n'
} | sudo tee /etc/omarchy.conf >/dev/null
echo "Pointed Omarchy at $target"
echo
echo "Done. Open a new shell (or restart existing ones) to pick up the new"
echo "OMARCHY_PATH. Run 'omarchy dev unlink' to restore the package install."
echo "Reboot to activate the linked checkout in Hyprland, app launchers, and new shells."
echo "Run 'omarchy dev unlink' and reboot to restore the package install."
+6 -15
View File
@@ -3,6 +3,8 @@
# omarchy:summary=Show the current Omarchy dev-link state
# omarchy:group=dev
set -euo pipefail
default_target="/usr/share/omarchy"
configured="$default_target"
conf_present=0
@@ -22,8 +24,9 @@ if [[ -f /etc/omarchy.conf ]]; then
fi
if (( linked )); then
echo "dev-link: ACTIVE"
echo "dev-link: configured"
echo " /etc/omarchy.conf -> OMARCHY_PATH=$configured"
echo " status: reboot required before all session layers use this checkout"
else
echo "dev-link: inactive"
if (( conf_present )); then
@@ -33,19 +36,7 @@ fi
echo " current shell: OMARCHY_PATH=${OMARCHY_PATH:-<unset>}"
if (( linked )) && [[ ${OMARCHY_PATH:-} != "$configured" ]]; then
if [[ ${OMARCHY_PATH:-$default_target} != "$configured" ]]; then
echo
echo "Note: this shell predates dev-link. Open a new shell to pick up the change,"
echo "or 'export OMARCHY_PATH=$configured' to update just this shell."
elif (( ! linked )) && [[ ${OMARCHY_PATH:-$default_target} != "$default_target" ]]; then
echo
echo "Note: no dev-link is configured, but this shell still has a stale OMARCHY_PATH."
echo "Open a new shell or run 'export OMARCHY_PATH=$default_target'."
fi
if command -v hyprctl >/dev/null 2>&1 && hyprctl version &>/dev/null; then
hypr_path=$(hyprctl getoption -j env 2>/dev/null | sed -n 's/.*OMARCHY_PATH=\([^"]*\).*/\1/p' | head -1)
if [[ -n "$hypr_path" ]]; then
echo " hyprland session: OMARCHY_PATH=$hypr_path"
fi
echo "Note: the running session does not match /etc/omarchy.conf. Reboot to settle it."
fi
+7 -59
View File
@@ -1,11 +1,11 @@
#!/bin/bash
# omarchy:summary=Restore Omarchy to the package install (undo omarchy-dev-link)
# omarchy:summary=Restore Omarchy to the package install after reboot
# omarchy:group=dev
set -euo pipefail
if [[ $EUID -eq 0 ]]; then
if (( EUID == 0 )); then
echo "Error: run omarchy-dev-unlink as your user, not under sudo." >&2
exit 1
fi
@@ -14,69 +14,17 @@ if [[ ${1:-} == "-h" || ${1:-} == "--help" ]]; then
cat <<USAGE
Usage: omarchy dev unlink
Writes /etc/omarchy.conf defensively so OMARCHY_PATH resolves to
/usr/share/omarchy (the package install), even from stale session env.
Updates Hyprland/systemd session env and restarts omarchy-shell so live
state matches.
Writes /etc/omarchy.conf so OMARCHY_PATH resolves to /usr/share/omarchy
after reboot. This intentionally does not rewrite the running Hyprland,
systemd, shell, or app-launcher environment; reboot to make every layer agree.
USAGE
exit 0
fi
default_target="/usr/share/omarchy"
linked=0
prior_target=""
if [[ -f /etc/omarchy.conf ]]; then
# Capture the path dev-link wrote BEFORE we reset the conf, so we know
# which bin/ to strip from PATH.
prior_target=$(sed -n 's/^[[:space:]]*export[[:space:]]\+OMARCHY_PATH="\?\([^"]*\)"\?/\1/p' /etc/omarchy.conf | tail -1)
if [[ $prior_target != "$default_target" ]]; then
linked=1
echo "Unlinking Omarchy from ${prior_target:-<empty>}"
else
echo "/etc/omarchy.conf already points at $default_target."
fi
elif [[ ${OMARCHY_PATH:-$default_target} != "$default_target" ]]; then
prior_target="$OMARCHY_PATH"
echo "Not currently linked: /etc/omarchy.conf is absent."
echo "This shell still has OMARCHY_PATH=$OMARCHY_PATH; writing the default guard."
else
echo "Not currently linked. Writing the default OMARCHY_PATH guard."
fi
printf 'export OMARCHY_PATH="%s"\n' "$default_target" | sudo tee /etc/omarchy.conf >/dev/null
echo "Set /etc/omarchy.conf -> OMARCHY_PATH=$default_target"
export OMARCHY_PATH="$default_target"
if [[ -n $prior_target && $prior_target != "$default_target" ]]; then
PATH=$(printf '%s' "$PATH" | tr ':' '\n' | awk -v drop="$prior_target/bin" '$0 != drop' | paste -sd:)
export PATH
fi
if command -v systemctl >/dev/null 2>&1; then
if systemctl --user import-environment OMARCHY_PATH PATH 2>/dev/null; then
echo " Updated systemd --user env."
fi
fi
if command -v hyprctl >/dev/null 2>&1 && hyprctl version &>/dev/null; then
hyprctl setenv OMARCHY_PATH "$default_target" >/dev/null
hyprctl setenv PATH "$PATH" >/dev/null
echo " Updated Hyprland session env."
if pgrep -x quickshell >/dev/null 2>&1; then
omarchy-restart-shell
echo " Restarted omarchy-shell."
fi
hyprctl reload >/dev/null
echo " Reloaded Hyprland config."
fi
echo
if (( linked )) || [[ -n $prior_target ]]; then
echo "Done. Existing shells still have the old OMARCHY_PATH until restarted."
echo "For this shell, run: export OMARCHY_PATH=$default_target"
else
echo "Done."
fi
echo "Reboot to restore the package install in Hyprland, app launchers, and new shells."
+2 -13
View File
@@ -1,18 +1,7 @@
-- Learn how to configure Hyprland: https://wiki.hypr.land/Configuring/Start/
-- Drop cached omarchy modules so hyprctl reload re-reads them from disk.
for k in pairs(package.loaded) do
if k:match("^default%.hypr") or k:match("^hypr%.") then
package.loaded[k] = nil
end
end
-- Load user modules from ~/.config and Omarchy defaults from $OMARCHY_PATH.
package.path = os.getenv("HOME")
.. "/.config/?.lua;"
.. (os.getenv("OMARCHY_PATH") or "/usr/share/omarchy")
.. "/?.lua;"
.. package.path
-- Omarchy's bootstrap keeps path setup out of this user config.
dofile((os.getenv("OMARCHY_PATH") or "/usr/share/omarchy") .. "/default/hypr/bootstrap.lua")
-- All Omarchy default setups
require("default.hypr.omarchy")
+2 -3
View File
@@ -17,12 +17,11 @@ export OMARCHY_PATH
# Only prepend in dev-link mode. On a production install, the binaries are
# already on PATH as /usr/bin/omarchy-* via the omarchy package — prepending
# /usr/share/omarchy/bin would just be noise. omarchy-dev-unlink strips its
# checkout bin/ from the active PATH explicitly, so we don't dedupe here.
# /usr/share/omarchy/bin would just be noise.
if [ "$OMARCHY_PATH" != /usr/share/omarchy ]; then
case ":$PATH:" in
*":${OMARCHY_PATH%/}/bin:"*) ;;
*) PATH="${OMARCHY_PATH%/}/bin:$PATH" ;;
*) PATH="${OMARCHY_PATH%/}/bin${PATH:+:$PATH}" ;;
esac
export PATH
fi
+8
View File
@@ -0,0 +1,8 @@
-- Hyprland bootstrap for Omarchy's Lua module path.
-- Load user modules from ~/.config and Omarchy defaults from $OMARCHY_PATH.
package.path = os.getenv("HOME")
.. "/.config/?.lua;"
.. (os.getenv("OMARCHY_PATH") or "/usr/share/omarchy")
.. "/?.lua;"
.. package.path
+1 -18
View File
@@ -4,26 +4,9 @@
local home = os.getenv("HOME")
-- /etc/omarchy.conf wins over process env so dev-link/unlink survives stale sessions.
local function read_dev_link_omarchy_path()
local f = io.open("/etc/omarchy.conf", "r")
if not f then return nil end
local value
for line in f:lines() do
local v = line:match('^%s*export%s+OMARCHY_PATH=%s*"?([^"\n]+)"?')
if v and #v > 0 then value = v end
end
f:close()
return value
end
local omarchy_path = read_dev_link_omarchy_path()
or os.getenv("OMARCHY_PATH")
or "/usr/share/omarchy"
return {
home = home,
config_home = os.getenv("XDG_CONFIG_HOME") or (home .. "/.config"),
state_home = os.getenv("XDG_STATE_HOME") or (home .. "/.local/state"),
omarchy_path = omarchy_path,
omarchy_path = os.getenv("OMARCHY_PATH") or "/usr/share/omarchy",
}
+5
View File
@@ -140,6 +140,11 @@ if errors:
PY
pass "package-owned defaults live outside config"
grep -F 'dofile((os.getenv("OMARCHY_PATH") or "/usr/share/omarchy") .. "/default/hypr/bootstrap.lua")' "$ROOT/config/hypr/hyprland.lua" >/dev/null
grep -F 'require("default.hypr.omarchy")' "$ROOT/config/hypr/hyprland.lua" >/dev/null
grep -F 'package.path = os.getenv("HOME")' "$ROOT/default/hypr/bootstrap.lua" >/dev/null
pass "Hyprland user entrypoint keeps only package path bootstrap in defaults"
TMPDIR=$(mktemp -d)
mkdir -p "$TMPDIR/home/.config/omarchy"
+76
View File
@@ -0,0 +1,76 @@
#!/bin/bash
set -euo pipefail
source "$(dirname "$0")/base-test.sh"
run_bootstrap() {
local shell_bin="$1"
local bootstrap="$2"
local home="$3"
local path_value="$4"
HOME="$home" PATH="$path_value" "$shell_bin" -c '
. "$1"
printf "%s\n%s\n" "$OMARCHY_PATH" "$PATH"
' sh "$bootstrap"
}
assert_path_first() {
local path_value="$1"
local entry="$2"
local description="$3"
[[ ${path_value%%:*} == "$entry" ]] || fail "$description" "expected first PATH entry: $entry\nactual PATH: $path_value"
pass "$description"
}
assert_path_present() {
local path_value="$1"
local entry="$2"
local description="$3"
case ":$path_value:" in
*":$entry:"*) pass "$description" ;;
*) fail "$description" "PATH does not contain $entry in $path_value" ;;
esac
}
tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT
home="$tmpdir/home"
mkdir -p "$tmpdir/active/bin" "$tmpdir/unrelated/bin"
# Test against a copy so the test controls /etc/omarchy.conf without mutating the host.
bootstrap="$tmpdir/env-bootstrap"
sed "s#/etc/omarchy.conf#$tmpdir/omarchy.conf#g" "$ROOT/default/bash/env-bootstrap" >"$bootstrap"
printf 'export OMARCHY_PATH="/usr/share/omarchy"\n' >"$tmpdir/omarchy.conf"
mapfile -t default_result < <(run_bootstrap bash "$bootstrap" "$home" "$tmpdir/unrelated/bin:/usr/bin")
default_path=${default_result[1]}
[[ ${default_result[0]} == /usr/share/omarchy ]] || fail "env-bootstrap resolves default OMARCHY_PATH" "actual: ${default_result[0]}"
pass "env-bootstrap resolves default OMARCHY_PATH"
assert_path_present "$default_path" "$tmpdir/unrelated/bin" "env-bootstrap preserves PATH entries in default mode"
printf 'export OMARCHY_PATH="%s"\n' "$tmpdir/active" >"$tmpdir/omarchy.conf"
mapfile -t linked_result < <(run_bootstrap bash "$bootstrap" "$home" "$tmpdir/unrelated/bin:/usr/bin")
linked_path=${linked_result[1]}
[[ ${linked_result[0]} == "$tmpdir/active" ]] || fail "env-bootstrap resolves linked OMARCHY_PATH" "actual: ${linked_result[0]}"
pass "env-bootstrap resolves linked OMARCHY_PATH"
assert_path_first "$linked_path" "$tmpdir/active/bin" "env-bootstrap prepends active checkout bin in linked mode"
assert_path_present "$linked_path" "$tmpdir/unrelated/bin" "env-bootstrap preserves unrelated PATH entries in linked mode"
mapfile -t linked_duplicate_result < <(run_bootstrap bash "$bootstrap" "$home" "$tmpdir/active/bin:/usr/bin")
linked_duplicate_path=${linked_duplicate_result[1]}
[[ $linked_duplicate_path == "$tmpdir/active/bin:/usr/bin" ]] || fail "env-bootstrap does not duplicate active checkout bin" "actual PATH: $linked_duplicate_path"
pass "env-bootstrap does not duplicate active checkout bin"
if command -v zsh >/dev/null 2>&1; then
mapfile -t zsh_result < <(run_bootstrap zsh "$bootstrap" "$home" "$tmpdir/unrelated/bin:/usr/bin")
zsh_path=${zsh_result[1]}
assert_path_first "$zsh_path" "$tmpdir/active/bin" "env-bootstrap works when sourced by zsh"
assert_path_present "$zsh_path" "$tmpdir/unrelated/bin" "env-bootstrap zsh mode preserves unrelated PATH entries"
fi