Initial Ubuntu 24.04 Niri installer

This commit is contained in:
wuyang
2026-07-27 13:39:29 +08:00
commit 1b0af7b3ff
12 changed files with 900 additions and 0 deletions
Executable
+323
View File
@@ -0,0 +1,323 @@
#!/usr/bin/env bash
set -Eeuo pipefail
readonly PROJECT="niri-beyond-glass"
readonly NIRI_TAG="v26.04"
readonly XWS_TAG="v0.8.2"
readonly RUST_TOOLCHAIN="1.85.1"
readonly ARCHIVE_URL="https://git.k1412.top/wuyang/niri-beyond-glass/archive/main.tar.gz"
wallpaper=""
config_only=0
dry_run=0
rebuild=0
source_dir="${NBG_SOURCE_DIR:-}"
tmp_dir=""
usage() {
cat <<'EOF'
用法:install.sh [选项]
--wallpaper PATH 使用指定的静态壁纸
--config-only 只更新配置,不安装/编译软件
--rebuild 强制重新编译 Niri 和 Xwayland Satellite
--dry-run 显示将执行的主要步骤,不修改系统
-h, --help 显示帮助
EOF
}
log() {
printf '\033[1;36m[Niri]\033[0m %s\n' "$*"
}
die() {
printf '\033[1;31m错误:\033[0m %s\n' "$*" >&2
exit 1
}
run() {
if (( dry_run )); then
printf '+'
printf ' %q' "$@"
printf '\n'
else
"$@"
fi
}
cleanup() {
[[ -n "$tmp_dir" && -d "$tmp_dir" ]] && rm -rf "$tmp_dir"
}
trap cleanup EXIT
while (($#)); do
case "$1" in
--wallpaper)
(($# >= 2)) || die "--wallpaper 缺少路径"
wallpaper="$2"
shift 2
;;
--config-only)
config_only=1
shift
;;
--rebuild)
rebuild=1
shift
;;
--dry-run)
dry_run=1
shift
;;
-h|--help)
usage
exit 0
;;
*)
die "未知参数:$1"
;;
esac
done
[[ ${EUID:-$(id -u)} -ne 0 ]] || die "请用普通用户运行,脚本会在需要时调用 sudo。"
[[ -z "$wallpaper" || -f "$wallpaper" ]] || die "壁纸不存在:$wallpaper"
if [[ -r /etc/os-release ]]; then
# shellcheck disable=SC1091
. /etc/os-release
else
die "无法识别操作系统。"
fi
if [[ "${ID:-}" != "ubuntu" || "${VERSION_ID:-}" != "24.04" ]]; then
die "只支持 Ubuntu 24.04;当前是 ${PRETTY_NAME:-未知系统}"
fi
case "$(uname -m)" in
x86_64|aarch64) ;;
*) die "目前只支持 x86_64 和 aarch64。" ;;
esac
fetch_source() {
if [[ -n "$source_dir" ]]; then
[[ -f "$source_dir/config/niri/config.kdl" ]] || die "NBG_SOURCE_DIR 不是有效源码目录。"
return
fi
tmp_dir="$(mktemp -d)"
log "下载配置仓库"
curl -fL --retry 3 "$ARCHIVE_URL" -o "$tmp_dir/source.tar.gz"
mkdir -p "$tmp_dir/source"
tar -xzf "$tmp_dir/source.tar.gz" -C "$tmp_dir/source" --strip-components=1
source_dir="$tmp_dir/source"
}
install_packages() {
log "安装 Ubuntu 24.04 依赖"
run sudo apt-get update
run sudo env DEBIAN_FRONTEND=noninteractive apt-get install -y \
build-essential clang git curl ca-certificates pkg-config \
meson ninja-build cmake \
libudev-dev libgbm-dev libxkbcommon-dev libegl1-mesa-dev \
libwayland-dev libinput-dev libdbus-1-dev libsystemd-dev \
libseat-dev libpipewire-0.3-dev libpango1.0-dev \
libdisplay-info-dev libcairo2-dev libglib2.0-dev \
libxcb1-dev libxcb-composite0-dev libxcb-randr0-dev \
libxcb-res0-dev libxcb-xfixes0-dev libxcb-cursor-dev \
xwayland xdg-desktop-portal-gnome xdg-desktop-portal-gtk \
alacritty fuzzel waybar swaybg swaylock swayidle mako-notifier \
nautilus policykit-1-gnome pipewire-pulse wireplumber \
brightnessctl playerctl grim slurp wl-clipboard wlogout \
fonts-noto-core fonts-noto-cjk fonts-noto-color-emoji fonts-font-awesome
}
install_rust() {
export RUSTUP_HOME="${XDG_DATA_HOME:-$HOME/.local/share}/$PROJECT/rustup"
export CARGO_HOME="${XDG_DATA_HOME:-$HOME/.local/share}/$PROJECT/cargo"
export PATH="$CARGO_HOME/bin:$PATH"
if [[ ! -x "$CARGO_HOME/bin/rustup" ]]; then
log "安装隔离的 Rust $RUST_TOOLCHAIN 工具链"
if (( dry_run )); then
printf '+ curl https://sh.rustup.rs | sh -s -- -y --no-modify-path --profile minimal --default-toolchain %q\n' "$RUST_TOOLCHAIN"
return
fi
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs |
sh -s -- -y --no-modify-path --profile minimal --default-toolchain "$RUST_TOOLCHAIN"
else
run "$CARGO_HOME/bin/rustup" toolchain install "$RUST_TOOLCHAIN" --profile minimal
run "$CARGO_HOME/bin/rustup" default "$RUST_TOOLCHAIN"
fi
}
version_ge() {
[[ "$(printf '%s\n%s\n' "$2" "$1" | sort -V | head -n1)" == "$2" ]]
}
install_libdisplay_info() {
local installed=""
installed="$(pkg-config --modversion libdisplay-info 2>/dev/null || true)"
if [[ -n "$installed" ]] && version_ge "$installed" "0.3.0"; then
return
fi
log "编译 libdisplay-info 0.3.0Ubuntu 24.04 自带版本较旧)"
local build_root="${XDG_CACHE_HOME:-$HOME/.cache}/$PROJECT/build"
local src="$build_root/libdisplay-info"
run mkdir -p "$build_root"
if [[ ! -d "$src/.git" ]]; then
run git clone --depth 1 --branch 0.3.0 \
https://gitlab.freedesktop.org/emersion/libdisplay-info.git "$src"
fi
run meson setup "$src/build" "$src" --prefix=/usr/local --buildtype=release --wipe
run ninja -C "$src/build"
run sudo ninja -C "$src/build" install
run sudo ldconfig
}
install_niri() {
local current=""
current="$(niri --version 2>/dev/null || true)"
if (( ! rebuild )) && [[ "$current" == *"26.4"* || "$current" == *"26.04"* ]]; then
log "已安装兼容的 $current,跳过编译"
return
fi
log "编译 Niri $NIRI_TAG"
local build_root="${XDG_CACHE_HOME:-$HOME/.cache}/$PROJECT/build"
local src="$build_root/niri"
run mkdir -p "$build_root"
if [[ ! -d "$src/.git" ]]; then
run git clone --depth 1 --branch "$NIRI_TAG" https://github.com/niri-wm/niri.git "$src"
else
run git -C "$src" fetch --depth 1 origin "refs/tags/$NIRI_TAG:refs/tags/$NIRI_TAG"
run git -C "$src" checkout -f "$NIRI_TAG"
fi
run cargo build --manifest-path "$src/Cargo.toml" --release --locked
run sudo install -Dm755 "$src/target/release/niri" /usr/local/bin/niri
run sudo install -Dm755 "$src/resources/niri-session" /usr/local/bin/niri-session
run sudo install -Dm644 "$src/resources/niri.service" /usr/local/lib/systemd/user/niri.service
run sudo install -Dm644 "$src/resources/niri-shutdown.target" /usr/local/lib/systemd/user/niri-shutdown.target
run sudo install -Dm644 "$src/resources/niri.desktop" /usr/local/share/wayland-sessions/niri.desktop
run sudo install -Dm644 "$src/resources/niri-portals.conf" /usr/local/share/xdg-desktop-portal/niri-portals.conf
}
install_xwayland_satellite() {
if (( ! rebuild )) && command -v xwayland-satellite >/dev/null 2>&1; then
return
fi
log "编译 Xwayland Satellite $XWS_TAG"
local build_root="${XDG_CACHE_HOME:-$HOME/.cache}/$PROJECT/build"
local src="$build_root/xwayland-satellite"
run mkdir -p "$build_root"
if [[ ! -d "$src/.git" ]]; then
run git clone --depth 1 --branch "$XWS_TAG" \
https://github.com/Supreeeme/xwayland-satellite.git "$src"
else
run git -C "$src" fetch --depth 1 origin "refs/tags/$XWS_TAG:refs/tags/$XWS_TAG"
run git -C "$src" checkout -f "$XWS_TAG"
fi
run cargo build --manifest-path "$src/Cargo.toml" --release --locked
run sudo install -Dm755 "$src/target/release/xwayland-satellite" /usr/local/bin/xwayland-satellite
}
backup_and_install_config() {
local config_home="${XDG_CONFIG_HOME:-$HOME/.config}"
local state_home="${XDG_STATE_HOME:-$HOME/.local/state}"
local stamp
stamp="$(date +%Y%m%d-%H%M%S)"
local backup="$state_home/$PROJECT/backups/$stamp/config"
local names=(niri waybar fuzzel mako swaylock niri-beyond-glass)
log "备份并安装用户配置"
run mkdir -p "$backup"
local name
for name in "${names[@]}"; do
if [[ -e "$config_home/$name" ]]; then
run cp -a "$config_home/$name" "$backup/$name"
fi
done
run mkdir -p \
"$config_home/niri" \
"$config_home/waybar" \
"$config_home/fuzzel" \
"$config_home/mako" \
"$config_home/swaylock" \
"$config_home/niri-beyond-glass" \
"$HOME/.local/bin" \
"$HOME/Pictures/Screenshots"
run install -m644 "$source_dir/config/niri/config.kdl" "$config_home/niri/config.kdl"
run install -m644 "$source_dir/config/waybar/config.jsonc" "$config_home/waybar/config.jsonc"
run install -m644 "$source_dir/config/waybar/style.css" "$config_home/waybar/style.css"
run install -m644 "$source_dir/config/fuzzel/fuzzel.ini" "$config_home/fuzzel/fuzzel.ini"
run install -m644 "$source_dir/config/mako/config" "$config_home/mako/config"
run install -m644 "$source_dir/config/swaylock/config" "$config_home/swaylock/config"
run install -m755 "$source_dir/scripts/niri-beyond-wallpaper" "$HOME/.local/bin/niri-beyond-wallpaper"
select_wallpaper "$config_home/niri-beyond-glass/wallpaper"
}
select_wallpaper() {
local state_file="$1"
local selected="$wallpaper"
if [[ -z "$selected" ]]; then
local candidates=(
/usr/share/backgrounds/warty-final-ubuntu.png
/usr/share/backgrounds/ubuntu-default-greyscale-wallpaper.png
)
local candidate
for candidate in "${candidates[@]}"; do
if [[ -f "$candidate" ]]; then
selected="$candidate"
break
fi
done
fi
if [[ -z "$selected" ]]; then
selected="$(find /usr/share/backgrounds -maxdepth 2 -type f \
\( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' \) \
-print -quit 2>/dev/null || true)"
fi
if (( dry_run )); then
printf '+ write wallpaper path %q to %q\n' "$selected" "$state_file"
else
printf '%s\n' "$selected" > "$state_file"
fi
}
validate_config() {
if (( dry_run )); then
printf '+ niri validate -c %q\n' "${XDG_CONFIG_HOME:-$HOME/.config}/niri/config.kdl"
return
fi
command -v niri >/dev/null 2>&1 || die "找不到 niri,无法验证配置。"
niri validate -c "${XDG_CONFIG_HOME:-$HOME/.config}/niri/config.kdl"
}
main() {
fetch_source
if (( ! config_only )); then
install_packages
install_rust
install_libdisplay_info
install_niri
install_xwayland_satellite
fi
backup_and_install_config
validate_config
log "安装完成"
printf '\n请注销,在 GDM 会话菜单中选择“Niri”后登录。\n'
printf 'GNOME 和 GDM 均未被修改;快捷键说明:Super+Shift+/。\n'
}
main