Rearrange for tidier structure (#2212)

This commit is contained in:
clsty
2025-10-16 07:19:55 +08:00
parent 13065d7e5a
commit 8b493e091d
529 changed files with 165 additions and 138 deletions
+1
View File
@@ -0,0 +1 @@
This folder mainly contains data for install scripts.
+86
View File
@@ -0,0 +1,86 @@
## Status: WIP
This file was generated by AI (see [#2102](https://github.com/end-4/dots-hyprland/issues/2102)).
It still needs manual correction.
## Information
Meta-packages (from sdist/arch/install-deps.sh)
- illogical-impulse-basic
- Purpose: Core shell tooling used by scripts (general CLI utilities, build helpers, JSON processing, etc.).
- illogical-impulse-audio
- Purpose: Audio stack (e.g., PipeWire/WirePlumber, mixers, control UIs) used by widgets and desktop integrations.
- illogical-impulse-backlight
- Purpose: Screen brightness control utilities (e.g., brightnessctl).
- illogical-impulse-fonts-themes
- Purpose: Fonts and themes used across the shell/widgets (Noto, emoji fonts, icon themes, GTK/Qt themes).
- illogical-impulse-kde
- Purpose: KDE integration bits (dialogs, theming helpers, optional browser integration).
- illogical-impulse-portal
- Purpose: Desktop portals (e.g., xdg-desktop-portal and Wayland compositor-specific portals).
- illogical-impulse-python
- Purpose: Python 3 and libs for repo Python scripts and virtualenv activation.
- illogical-impulse-screencapture
- Purpose: Screenshot/recording tools on Wayland (e.g., grim, slurp, wf-recorder or similar).
- illogical-impulse-toolkit
- Purpose: General utilities used by scripts (jq, imagemagick, bc, etc.).
- illogical-impulse-widgets
- Purpose: Runtime deps for Quickshell widgets and supporting tools used in the UI modules.
- illogical-impulse-hyprland
- Purpose: Hyprland compositor and related tools (hyprland, hyprctl, hypridle, hyprlock, hyprcursor, portals).
- illogical-impulse-microtex-git
- Purpose: MicroTeX-related setup used by this config (custom packaging).
- illogical-impulse-bibata-modern-classic-bin (optional)
- Purpose: Bibata Modern Classic mouse cursor theme (installed only if not present).
Concrete dependencies inferred from repository scripts
- hyprland (provides hyprctl)
- Purpose: Compositor
- jq
- Used by: switchwall.sh (JSON parsing), multiple scripts reading config.json, hyprctl -j output.
- Purpose: JSON parsing and transformation.
- matugen (AUR)
- Used by: switchwall.sh to generate Material You colors from image or color input.
- Purpose: Color extraction and scheme generation.
- python (python3) + virtualenv (python-virtualenv)
- Used by: switchwall.sh activates $ILLOGICAL_IMPULSE_VIRTUAL_ENV and runs generate_colors_material.py.
- Purpose: Color processing
- imagemagick (identify)
- Used by: switchwall.sh to probe image width/height to suggest upscaling.
- Purpose: Image metadata inspection.
- bc
- Used by: switchwall.sh for simple arithmetic on cursor coordinates.
- Purpose: Shell-friendly math.
- xdg-user-dirs (xdg-user-dir)
- Used by: switchwall.sh to locate Pictures folder.
- Purpose: XDG directories resolution.
- libnotify (notify-send)
- Used by: switchwall.sh to interactively prompt actions (install/open apps) via notifications.
- Purpose: Desktop notifications with actions.
- hyprpicker (AUR)
- Used by: switchwall.sh for picking colors from screen when --color is passed without hex.
- Purpose: On-screen color picker (Wayland).
- mpvpaper (AUR)
- Used by: switchwall.sh to set video wallpapers per monitor.
- Purpose: Video wallpaper playback under Wayland.
- ffmpeg
- Used by: switchwall.sh to extract a frame from videos to derive colors and thumbnails.
- Purpose: Video frame extraction and media handling.
- kitty
- Used by: switchwall.sh to run interactive installs or external tools in a terminal (kitty -1 ...).
- Purpose: Terminal emulator integration.
- kdialog (KDE)
- Used by: switchwall.sh to open a file picker for choosing wallpapers.
- Purpose: GUI file selection dialog.
- glib2 (gsettings) + dconf
- Used by: switchwall.sh to set GNOME interface color-scheme and GTK theme.
- Purpose: System settings manipulation.
- yay (or yay-bin from AUR)
- Used by: sdist/arch/install-deps.sh to build/install local PKGBUILDs and dependencies.
- Purpose: AUR helper used by installer.
- base-devel, git, makepkg (core Arch tooling)
- Used by: sdist/arch/install-deps.sh and update.sh for building AUR/PKGBUILD packages and repository management.
- Purpose: Build toolchain and VCS for packaging.
Notes
- Some Hyprland-adjacent packages appear in a legacy removal list as -git variants (e.g., hypridle, hyprlock, xdg-desktop-portal-hyprland). This suggests the meta-packages likely standardized on stable repo versions now.
- Exact package lists per meta-package should be verified against the PKGBUILD files in sdist/arch/*; the above is aligned with how the code uses these tools.
+77
View File
@@ -0,0 +1,77 @@
# This script is meant to be sourced.
# It's not for directly running.
printf 'Hi there!\n'
printf 'This script 1. will uninstall [end-4/dots-hyprland > illogical-impulse] dotfiles\n'
printf ' 2. will try to revert *mostly everything* installed using install.sh, so it'\''s pretty destructive\n'
printf ' 3. has not been tested, use at your own risk.\n'
printf ' 4. will show all commands that it runs.\n'
printf 'Ctrl+C to exit. Enter to continue.\n'
read -r
##############################################################################################################################
# Undo Step 3: Removing copied config and local folders
printf "${STY_CYAN}Removing copied config and local folders...\n${STY_RESET}"
dirs=(
Kvantum/
fish/
fontconfig/
foot/
fuzzel/
hypr/
kde-material-you-colors/
kitty/
matugen/
mpv/
qt5ct/
qt6ct/
quickshell/
wlogout/
xdg-desktop-portal/
zshrc.d/
chrome-flags.conf
code-flags.conf
darklyrc
dolphinrc
kdeglobals
konsolerc
starship.toml
thorium-flags.conf
)
for i in ${dirs[@]}
do v rm -rf "$XDG_CONFIG_HOME/$i"
done
for i in "glib-2.0/schemas/com.github.GradienceTeam.Gradience.Devel.gschema.xml" "gradience"
do v rm -rf "$XDG_DATA_HOME/$i"
done
v rm -rf "$XDG_CACHE_HOME/quickshell"
v sudo rm -rf "$XDG_STATE_HOME/quickshell"
##############################################################################################################################
# Undo Step 2: Uninstall AGS - Disabled for now, check issues
# echo 'Uninstalling AGS...'
# sudo meson uninstall -C ~/ags/build
# rm -rf ~/ags
##############################################################################################################################
# Undo Step 1: Remove added user from video, i2c, and input groups and remove yay packages
printf "${STY_CYAN}Removing user from video, i2c, and input groups and removing packages...\n${STY_RESET}"
user=$(whoami)
v sudo gpasswd -d "$user" video
v sudo gpasswd -d "$user" i2c
v sudo gpasswd -d "$user" input
v sudo rm /etc/modules-load.d/i2c-dev.conf
##############################################################################################################################
read -p "Do you want to uninstall the illogical-impulse-* meta packages (Arch Linux only)?
Ctrl+C to exit, or press Enter to proceed" p
# Removing installed yay packages and dependencies
v yay -Rns illogical-impulse-{audio,backlight,basic,bibata-modern-classic-bin,fonts-themes,hyprland,kde,microtex-git,oneui4-icons-git,portal,python,screencapture,toolkit,widgets} plasma-browser-integration
printf "${STY_CYAN}Uninstall Complete.\n${STY_RESET}"
+860
View File
@@ -0,0 +1,860 @@
#!/usr/bin/env bash
#
# update.sh - Enhanced dotfiles update script
#
# Features:
# - Pull latest commits from remote
# - Rebuild packages if PKGBUILD files changed (user choice)
# - Handle config file conflicts with user choices
# - Respect .updateignore file for exclusions
#
set -uo pipefail
# === Configuration ===
FORCE_CHECK=false
CHECK_PACKAGES=false
REPO_DIR="$(cd $(dirname $(dirname $(dirname $0))) &>/dev/null && pwd)"
ARCH_PACKAGES_DIR="${REPO_DIR}/sdist/arch"
UPDATE_IGNORE_FILE="${REPO_DIR}/.updateignore"
HOME_UPDATE_IGNORE_FILE="${HOME}/.updateignore"
# Directories to monitor for changes
MONITOR_DIRS=(".config" ".local/bin")
# === Color Codes ===
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
PURPLE='\033[0;35m'
NC='\033[0m' # No Color
# === Helper Functions ===
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1" >&2
}
log_header() {
echo -e "\n${PURPLE}=== $1 ===${NC}"
}
die() {
log_error "$1"
exit 1
}
# Function to safely read input with terminal compatibility
safe_read() {
local prompt="$1"
local varname="$2"
local default="${3:-}"
# Simple approach: just use read with /dev/tty and handle errors
local input_value=""
# Display prompt and read from terminal
echo -n "$prompt"
if read input_value </dev/tty 2>/dev/null || read input_value 2>/dev/null; then
eval "$varname='$input_value'"
return 0
else
# If read failed and we have a default, use it
if [[ -n "$default" ]]; then
echo
log_warning "Using default: $default"
eval "$varname='$default'"
return 0
else
echo
log_error "Failed to read input"
return 1
fi
fi
}
# Function to check if a file should be ignored
should_ignore() {
local file_path="$1"
local relative_path="${file_path#$HOME/}"
# Also get path relative to repo for repo-level ignores
local repo_relative=""
if [[ "$file_path" == "$REPO_DIR"* ]]; then
repo_relative="${file_path#$REPO_DIR/}"
fi
# Check both repo and home ignore files
for ignore_file in "$UPDATE_IGNORE_FILE" "$HOME_UPDATE_IGNORE_FILE"; do
if [[ -f "$ignore_file" ]]; then
while IFS= read -r pattern || [[ -n "$pattern" ]]; do
# Skip empty lines and comments
[[ -z "$pattern" || "$pattern" =~ ^[[:space:]]*# ]] && continue
# Remove leading/trailing whitespace
pattern=$(echo "$pattern" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
[[ -z "$pattern" ]] && continue
# Handle different gitignore-style patterns
local should_skip=false
# Exact match
if [[ "$relative_path" == "$pattern" ]] || [[ "$repo_relative" == "$pattern" ]]; then
should_skip=true
fi
# Wildcard patterns (basic glob matching)
if [[ "$relative_path" == $pattern ]] || [[ "$repo_relative" == $pattern ]]; then
should_skip=true
fi
# Directory patterns (ending with /)
if [[ "$pattern" == */ ]]; then
local dir_pattern="${pattern%/}"
if [[ "$relative_path" == "$dir_pattern"/* ]] || [[ "$repo_relative" == "$dir_pattern"/* ]]; then
should_skip=true
fi
fi
# Patterns starting with / (from root)
if [[ "$pattern" == /* ]]; then
local root_pattern="${pattern#/}"
if [[ "$relative_path" == "$root_pattern" ]] || [[ "$relative_path" == "$root_pattern"/* ]] ||
[[ "$repo_relative" == "$root_pattern" ]] || [[ "$repo_relative" == "$root_pattern"/* ]]; then
should_skip=true
fi
fi
# Patterns with wildcards
if [[ "$pattern" == *"*"* ]]; then
if [[ "$relative_path" == $pattern ]] || [[ "$repo_relative" == $pattern ]]; then
should_skip=true
fi
# Also check if any parent directory matches
local temp_path="$relative_path"
while [[ "$temp_path" == */* ]]; do
temp_path="${temp_path%/*}"
if [[ "$temp_path" == $pattern ]]; then
should_skip=true
break
fi
done
fi
# Simple substring matching (for backward compatibility)
if [[ ! "$should_skip" == true ]]; then
if [[ "$file_path" == *"$pattern"* ]] || [[ "$relative_path" == *"$pattern"* ]]; then
should_skip=true
fi
fi
if [[ "$should_skip" == true ]]; then
return 0
fi
done <"$ignore_file"
fi
done
return 1
}
# Function to show file diff with syntax highlighting if possible
show_diff() {
local file1="$1"
local file2="$2"
echo -e "\n${CYAN}Showing differences:${NC}"
echo -e "${CYAN}Old file: $file1${NC}"
echo -e "${CYAN}New file: $file2${NC}"
echo "----------------------------------------"
if command -v diff &>/dev/null; then
diff -u "$file1" "$file2" || true
else
echo "diff command not available"
fi
echo "----------------------------------------"
}
# Function to handle file conflicts
handle_file_conflict() {
local repo_file="$1"
local home_file="$2"
local filename=$(basename "$home_file")
local dirname=$(dirname "$home_file")
echo -e "\n${YELLOW}Conflict detected:${NC} $home_file"
echo "Repository version differs from your local version."
echo
echo "Choose an action:"
echo "1) Replace local file with repository version"
echo "2) Keep local file unchanged"
echo "3) Backup local file as ${filename}.old, use repository version"
echo "4) Save repository version as ${filename}.new, keep local file"
echo "5) Show diff and decide"
echo "6) Skip this file"
echo "7) Add to ignore and skip"
echo
while true; do
if ! safe_read "Enter your choice (1-7): " choice "6"; then
echo
log_warning "Failed to read input. Skipping file."
return
fi
case $choice in
1)
cp -p "$repo_file" "$home_file"
log_success "Replaced $home_file with repository version"
break
;;
2)
log_info "Keeping local version of $home_file"
break
;;
3)
mv "$home_file" "${dirname}/${filename}.old"
cp -p "$repo_file" "$home_file"
log_success "Backed up local file to ${filename}.old and updated with repository version"
break
;;
4)
cp -p "$repo_file" "${dirname}/${filename}.new"
log_success "Saved repository version as ${filename}.new, kept local file"
break
;;
5)
show_diff "$home_file" "$repo_file"
echo
echo "After reviewing the diff, choose:"
echo "r) Replace with repository version"
echo "k) Keep local version"
echo "b) Backup local and use repository version"
echo "n) Save repository version as .new"
echo "s) Skip this file"
echo "i) Add to ignore and skip"
if ! safe_read "Enter your choice (r/k/b/n/s/i): " subchoice "s"; then
echo
log_warning "Failed to read input. Skipping file."
return
fi
case $subchoice in
r)
cp -p "$repo_file" "$home_file"
log_success "Replaced $home_file with repository version"
break
;;
k)
log_info "Keeping local version of $home_file"
break
;;
b)
mv "$home_file" "${dirname}/${filename}.old"
cp -p "$repo_file" "$home_file"
log_success "Backed up local file to ${filename}.old and updated"
break
;;
n)
cp -p "$repo_file" "${dirname}/${filename}.new"
log_success "Saved repository version as ${filename}.new"
break
;;
s)
log_info "Skipping $home_file"
break
;;
i)
local relative_path_to_home="${home_file#$HOME/}"
echo "$relative_path_to_home" >>"$HOME_UPDATE_IGNORE_FILE"
log_success "Added '$relative_path_to_home' to $HOME_UPDATE_IGNORE_FILE and skipped."
break
;;
*)
echo "Invalid choice. Please try again."
;;
esac
;;
6)
log_info "Skipping $home_file"
break
;;
7)
local relative_path_to_home="${home_file#$HOME/}"
echo "$relative_path_to_home" >>"$HOME_UPDATE_IGNORE_FILE"
log_success "Added '$relative_path_to_home' to $HOME_UPDATE_IGNORE_FILE and skipped."
break
;;
*)
echo "Invalid choice. Please enter 1-7."
;;
esac
done
}
# Function to check if PKGBUILD has changed
check_pkgbuild_changed() {
local pkg_dir="$1"
local pkgbuild_path="${pkg_dir}/PKGBUILD"
[[ ! -f "$pkgbuild_path" ]] && return 1
# Get the path relative to repo
local relative_path="${pkgbuild_path#$REPO_DIR/}"
# If force check is enabled, always return true
if [[ "$FORCE_CHECK" == true ]]; then
return 0
fi
# Check if file changed in the last pull
if git diff --name-only HEAD@{1} HEAD 2>/dev/null | grep -q "^${relative_path}$"; then
return 0
fi
return 1
}
# Function to list available packages
list_packages() {
local available_packages=()
local changed_packages=()
if [[ ! -d "$ARCH_PACKAGES_DIR" ]]; then
log_warning "No sdist/arch directory found"
return 1
fi
for pkg_dir in "$ARCH_PACKAGES_DIR"/*/; do
if [[ -f "${pkg_dir}/PKGBUILD" ]]; then
local pkg_name=$(basename "$pkg_dir")
available_packages+=("$pkg_name")
if check_pkgbuild_changed "$pkg_dir"; then
changed_packages+=("$pkg_name")
fi
fi
done
if [[ ${#available_packages[@]} -eq 0 ]]; then
log_info "No packages found in sdist/arch directory"
return 1
fi
echo -e "\n${CYAN}Available packages:${NC}"
for pkg in "${available_packages[@]}"; do
if [[ " ${changed_packages[*]} " =~ " ${pkg} " ]]; then
echo -e " ${GREEN}${pkg}${NC} (PKGBUILD changed)"
else
echo -e "${pkg}"
fi
done
if [[ ${#changed_packages[@]} -gt 0 ]]; then
echo -e "\n${YELLOW}Packages with changed PKGBUILDs: ${changed_packages[*]}${NC}"
fi
return 0
}
# Function to build selected packages
build_packages() {
local build_mode="$1" # "changed", "all", or "select"
local packages_to_build=()
local rebuilt_packages=0
case "$build_mode" in
"changed")
for pkg_dir in "$ARCH_PACKAGES_DIR"/*/; do
if [[ -f "${pkg_dir}/PKGBUILD" ]]; then
local pkg_name=$(basename "$pkg_dir")
if check_pkgbuild_changed "$pkg_dir"; then
packages_to_build+=("$pkg_name")
fi
fi
done
;;
"all")
for pkg_dir in "$ARCH_PACKAGES_DIR"/*/; do
if [[ -f "${pkg_dir}/PKGBUILD" ]]; then
local pkg_name=$(basename "$pkg_dir")
packages_to_build+=("$pkg_name")
fi
done
;;
"select")
echo -e "\nEnter package names separated by spaces (or 'all' for all packages):"
if ! safe_read "Packages to build: " user_selection ""; then
log_warning "Failed to read input. Skipping package builds."
return
fi
if [[ "$user_selection" == "all" ]]; then
for pkg_dir in "$ARCH_PACKAGES_DIR"/*/; do
if [[ -f "${pkg_dir}/PKGBUILD" ]]; then
local pkg_name=$(basename "$pkg_dir")
packages_to_build+=("$pkg_name")
fi
done
else
read -ra packages_to_build <<<"$user_selection"
fi
;;
esac
if [[ ${#packages_to_build[@]} -eq 0 ]]; then
log_info "No packages selected for building"
return
fi
echo -e "\n${CYAN}Packages to build: ${packages_to_build[*]}${NC}"
if ! safe_read "Proceed with building these packages? (Y/n): " confirm "Y"; then
log_warning "Failed to read input. Skipping package builds."
return
fi
if [[ "$confirm" =~ ^[Nn]$ ]]; then
log_info "Package building cancelled by user"
return
fi
for pkg_name in "${packages_to_build[@]}"; do
local pkg_dir="${ARCH_PACKAGES_DIR}/${pkg_name}"
if [[ ! -d "$pkg_dir" || ! -f "${pkg_dir}/PKGBUILD" ]]; then
log_error "Package not found or missing PKGBUILD: $pkg_name"
continue
fi
log_info "Building package: $pkg_name"
cd "$pkg_dir" || continue
if makepkg -si --noconfirm; then
log_success "Successfully built and installed $pkg_name"
((rebuilt_packages++))
else
log_error "Failed to build package $pkg_name"
fi
cd "$REPO_DIR" || die "Failed to return to repository directory"
done
if [[ $rebuilt_packages -eq 0 ]]; then
log_warning "No packages were successfully built"
else
log_success "Successfully rebuilt $rebuilt_packages package(s)"
fi
}
# Function to get list of changed files since last pull or all files if force check
get_changed_files() {
local dir_path="$1"
if [[ "$FORCE_CHECK" == true ]]; then
# Return all files in the directory
find "$dir_path" -type f -print0 2>/dev/null
else
# Get files that changed in the last pull
local changed_files=()
while IFS= read -r file; do
local full_path="${REPO_DIR}/${file}"
# Check if file is in the directory we're processing
if [[ "$full_path" == "$dir_path"/* ]] && [[ -f "$full_path" ]]; then
printf '%s\0' "$full_path"
fi
done < <(git diff --name-only HEAD@{1} HEAD 2>/dev/null || true)
# If no files changed via git, but force_check is false, still check all files
# This handles the case where there were no new commits but files might differ
if ! git diff --quiet HEAD@{1} HEAD 2>/dev/null; then
: # Files were found via git diff
else
# No git changes detected, check all files anyway for local differences
find "$dir_path" -type f -print0 2>/dev/null
fi
fi
}
# Function to check if we have new commits
has_new_commits() {
# Check if HEAD@{1} exists (meaning there was a previous commit)
if git rev-parse --verify HEAD@{1} &>/dev/null; then
# Check if HEAD and HEAD@{1} are different
[[ "$(git rev-parse HEAD)" != "$(git rev-parse HEAD@{1})" ]]
else
# No previous commit reference, assume we have commits
return 0
fi
}
# Main script starts here
log_header "Dotfiles Update Script"
check=true
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
-f | --force)
FORCE_CHECK=true
log_info "Force check mode enabled - will check all files regardless of git changes"
shift
;;
-p | --packages)
CHECK_PACKAGES=true
log_info "Package checking enabled"
shift
;;
-h | --help)
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " -f, --force Force check all files even if no new commits"
echo " -p, --packages Enable package checking and building"
echo " -h, --help Show this help message"
echo ""
echo "This script updates your dotfiles by:"
echo " 1. Pulling latest changes from git remote"
echo " 2. Optionally rebuilding packages (if -p flag is used)"
echo " 3. Syncing configuration files"
echo " 4. Updating script permissions"
echo ""
echo "Package modes (when -p is used):"
echo " - If no PKGBUILDs changed: asks if you want to check packages anyway"
echo " - If PKGBUILDs changed: offers to build changed packages"
echo " - Interactive selection of packages to build"
exit 0
;;
--skip-notice)
log_warning "Skipping notice about script being untested"
check=false
shift
;;
*)
log_error "Unknown option: $1"
echo "Use --help for usage information"
exit 1
;;
esac
done
if [[ "$check" == true ]]; then
log_warning "THIS SCRIPT IS NOT FULLY TESTED AND MAY CAUSE ISSUES!"
log_warning "It might be safer if you want to preserve your modifications and not delete added files,"
log_warning " but this can cause partial updates and therefore unexpected behavior like in #1856."
log_warning "In general, prefer install.sh for updates."
safe_read "Continue? (y/N): " response "N"
if [[ ! "$response" =~ ^[Yy]$ ]]; then
log_error "Update aborted by user"
exit 1
fi
fi
# Check if we're in a git repository
cd "$REPO_DIR" || die "Failed to change to repository directory"
if git rev-parse --is-inside-work-tree &>/dev/null; then
log_info "Running in git repository: $(git rev-parse --show-toplevel)"
else
log_error "Not in a git repository. Please run this script from your dotfiles repository."
exit 1
fi
# Step 1: Pull latest commits
log_header "Pulling Latest Changes"
# Check current branch
current_branch=$(git branch --show-current)
if [[ -z "$current_branch" ]]; then
log_warning "In detached HEAD state. Checking out main/master branch..."
if git show-ref --verify --quiet refs/heads/main; then
git checkout main
current_branch="main"
elif git show-ref --verify --quiet refs/heads/master; then
git checkout master
current_branch="master"
else
die "Could not find main or master branch"
fi
fi
log_info "Current branch: $current_branch"
# Check for uncommitted changes
if ! git diff --quiet || ! git diff --cached --quiet; then
log_warning "You have uncommitted changes:"
git status --short
echo
if ! safe_read "Do you want to continue? This will stash your changes. (y/N): " response "N"; then
echo
log_error "Failed to read input. Aborting."
exit 1
fi
if [[ ! "$response" =~ ^[Yy]$ ]]; then
die "Aborted by user"
fi
git stash push -m "Auto-stash before update $(date)"
log_info "Changes stashed"
fi
# Check if remote exists
if git remote get-url origin &>/dev/null; then
# Pull changes
log_info "Pulling changes from origin/$current_branch..."
if git pull; then
log_success "Successfully pulled latest changes"
else
log_warning "Failed to pull changes from remote. Continuing with local repository..."
log_info "You may need to resolve conflicts manually later."
fi
else
log_warning "No remote 'origin' configured. Skipping pull operation."
log_info "This appears to be a local-only repository."
fi
# Step 2: Handle package building (only if requested)
rebuilt_packages=0
if [[ "$CHECK_PACKAGES" == true ]]; then
log_header "Package Management"
if [[ ! -d "$ARCH_PACKAGES_DIR" ]]; then
log_warning "No sdist/arch directory found. Skipping package management."
else
# Check if any PKGBUILDs have changed
changed_pkgbuilds=()
for pkg_dir in "$ARCH_PACKAGES_DIR"/*/; do
if [[ -f "${pkg_dir}/PKGBUILD" ]]; then
local pkg_name=$(basename "$pkg_dir")
if check_pkgbuild_changed "$pkg_dir"; then
changed_pkgbuilds+=("$pkg_name")
fi
fi
done
if [[ ${#changed_pkgbuilds[@]} -gt 0 ]]; then
log_info "Found ${#changed_pkgbuilds[@]} package(s) with changed PKGBUILDs: ${changed_pkgbuilds[*]}"
echo
echo "Package build options:"
echo "1) Build only packages with changed PKGBUILDs"
echo "2) List all packages and select which to build"
echo "3) Build all packages"
echo "4) Skip package building"
echo
if safe_read "Choose an option (1-4): " pkg_choice "1"; then
case $pkg_choice in
1)
build_packages "changed"
;;
2)
if list_packages; then
build_packages "select"
fi
;;
3)
build_packages "all"
;;
4 | *)
log_info "Skipping package building"
;;
esac
else
log_warning "Failed to read input. Skipping package building."
fi
else
log_info "No PKGBUILDs have changed since last update."
echo
if safe_read "Do you want to check and build packages anyway? (y/N): " check_anyway "N"; then
if [[ "$check_anyway" =~ ^[Yy]$ ]]; then
if list_packages; then
echo
echo "Package build options:"
echo "1) Select specific packages to build"
echo "2) Build all packages"
echo "3) Skip package building"
if safe_read "Choose an option (1-3): " build_choice "3"; then
case $build_choice in
1)
build_packages "select"
;;
2)
build_packages "all"
;;
3 | *)
log_info "Skipping package building"
;;
esac
else
log_info "Skipping package building"
fi
fi
else
log_info "Skipping package management"
fi
else
log_info "Skipping package management"
fi
fi
fi
else
log_header "Package Management"
log_info "Package checking disabled. Use -p or --packages flag to enable package management."
# Still show a hint if there are changed PKGBUILDs
if [[ -d "$ARCH_PACKAGES_DIR" ]]; then
changed_count=0
for pkg_dir in "$ARCH_PACKAGES_DIR"/*/; do
if [[ -f "${pkg_dir}/PKGBUILD" ]] && check_pkgbuild_changed "$pkg_dir"; then
((changed_count++))
fi
done
if [[ $changed_count -gt 0 ]]; then
log_warning "Note: $changed_count package(s) have changed PKGBUILDs. Use -p flag to manage packages."
fi
fi
fi
# Step 3: Update configuration files
log_header "Updating Configuration Files"
# Check if we should process files
process_files=false
if [[ "$FORCE_CHECK" == true ]]; then
process_files=true
log_info "Force mode: checking all configuration files"
elif has_new_commits; then
process_files=true
log_info "New commits detected: checking changed configuration files"
else
log_info "No new commits found: checking for local file differences"
process_files=true # Always check for differences even without commits
fi
if [[ "$process_files" == true ]]; then
files_processed=0
files_updated=0
files_created=0
for dir_name in "${MONITOR_DIRS[@]}"; do
repo_dir_path="${REPO_DIR}/${dir_name}"
home_dir_path="${HOME}/${dir_name}"
if [[ ! -d "$repo_dir_path" ]]; then
log_warning "Repository directory not found: $repo_dir_path"
continue
fi
log_info "Processing directory: $dir_name"
# Create home directory if it doesn't exist
mkdir -p "$home_dir_path"
# Get files to process (changed files or all files based on mode)
while IFS= read -r -d '' repo_file; do
# Calculate relative path and corresponding home file path
rel_path="${repo_file#$repo_dir_path/}"
home_file="${home_dir_path}/${rel_path}"
# Check if file should be ignored
if should_ignore "$home_file"; then
continue
fi
((files_processed++))
# Create directory structure if needed
mkdir -p "$(dirname "$home_file")"
if [[ -f "$home_file" ]]; then
# File exists, check if different
if ! cmp -s "$repo_file" "$home_file"; then
log_info "Found difference in: $rel_path"
handle_file_conflict "$repo_file" "$home_file"
((files_updated++))
fi
else
# New file, copy it
cp -p "$repo_file" "$home_file"
log_success "Created new file: $home_file"
((files_created++))
fi
done < <(get_changed_files "$repo_dir_path")
done
# Show processing summary
echo
log_info "File processing summary:"
log_info "- Files processed: $files_processed"
log_info "- Files with conflicts: $files_updated"
log_info "- New files created: $files_created"
else
log_info "Skipping file updates (no changes detected and not in force mode)"
fi
# Step 4: Update script permissions
log_header "Updating Script Permissions"
# Make sure local bin scripts are executable
if [[ -d "${HOME}/.local/bin" ]]; then
find "${HOME}/.local/bin" -type f -exec chmod +x {} \; 2>/dev/null || true
log_success "Updated ~/.local/bin script permissions"
fi
log_header "Update Complete"
log_success "Dotfiles update completed successfully!"
# Show summary
echo
echo -e "${CYAN}Summary:${NC}"
echo "- Repository: $(git log -1 --pretty=format:'%h - %s (%cr)')"
echo "- Branch: $current_branch"
echo "- Mode: $([ "$FORCE_CHECK" == true ] && echo "Force check" || echo "Normal")"
echo "- Package checking: $([ "$CHECK_PACKAGES" == true ] && echo "Enabled" || echo "Disabled")"
if [[ $rebuilt_packages -gt 0 ]]; then
echo "- Packages rebuilt: $rebuilt_packages"
fi
if [[ "$process_files" == true ]]; then
echo "- Files processed: $files_processed"
echo "- Files updated/conflicted: $files_updated"
echo "- New files created: $files_created"
fi
echo "- Configuration directories: ${MONITOR_DIRS[*]}"
# Remind about ignore files and show examples
if [[ ! -f "$HOME_UPDATE_IGNORE_FILE" && ! -f "$UPDATE_IGNORE_FILE" ]]; then
echo
log_info "Tip: Create ignore files to exclude files from updates:"
echo " - Repository ignore: ${REPO_DIR}/.updateignore"
echo " - User ignore: ~/.updateignore"
echo
echo "Example patterns:"
echo " *.log # Ignore all .log files"
echo " .config/personal/ # Ignore entire directory"
echo " secret-config.conf # Ignore specific file"
echo " /temp-file # Ignore from root only"
echo " *secret* # Ignore files containing 'secret'"
fi
echo
+31
View File
@@ -0,0 +1,31 @@
# This is NOT a script for execution, but for loading functions, so NOT need execution permission or shebang.
XDG_BIN_HOME=${XDG_BIN_HOME:-$HOME/.local/bin}
XDG_CACHE_HOME=${XDG_CACHE_HOME:-$HOME/.cache}
XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config}
XDG_DATA_HOME=${XDG_DATA_HOME:-$HOME/.local/share}
XDG_STATE_HOME=${XDG_STATE_HOME:-$HOME/.local/state}
BACKUP_DIR=${BACKUP_DIR:-$HOME/backup}
# Note that all color styles contains a STY_RESET before it.
STY_RED='\e[00m\e[31m'
STY_GREEN='\e[00m\e[32m'
STY_YELLOW='\e[00m\e[33m'
STY_BLUE='\e[00m\e[34m'
STY_PURPLE='\e[00m\e[35m'
STY_CYAN='\e[00m\e[36m'
STY_BG_RED='\e[30m\e[41m'
STY_BG_GREEN='\e[30m\e[42m'
STY_BG_YELLOW='\e[30m\e[43m'
STY_BG_BLUE='\e[30m\e[44m'
STY_BG_PURPLE='\e[30m\e[45m'
STY_BG_CYAN='\e[30m\e[46m'
STY_BOLD='\e[1m'
STY_FAINT='\e[2m'
STY_SLANT='\e[3m'
STY_UNDERLINE='\e[4m'
STY_BLINK='\e[5m'
STY_INVERT='\e[7m'
STY_RESET='\e[00m'
+97
View File
@@ -0,0 +1,97 @@
# This is NOT a script for execution, but for loading functions, so NOT need execution permission or shebang.
# NOTE that you NOT need to `cd ..' because the `$0' is NOT this file, but the script file which will source this file.
# The script that use this file should have two lines on its top as follows:
# cd "$(dirname "$0")"
# export base="$(pwd)"
function try { "$@" || sleep 0; }
function v(){
echo -e "####################################################"
echo -e "${STY_BLUE}[$0]: Next command:${STY_RESET}"
echo -e "${STY_GREEN}$@${STY_RESET}"
local execute=true
if $ask;then
while true;do
echo -e "${STY_BLUE}Execute? ${STY_RESET}"
echo " y = Yes"
echo " e = Exit now"
echo " s = Skip this command (NOT recommended - your setup might not work correctly)"
echo " yesforall = Yes and don't ask again; NOT recommended unless you really sure"
local p; read -p "====> " p
case $p in
[yY]) echo -e "${STY_BLUE}OK, executing...${STY_RESET}" ;break ;;
[eE]) echo -e "${STY_BLUE}Exiting...${STY_RESET}" ;exit ;break ;;
[sS]) echo -e "${STY_BLUE}Alright, skipping this one...${STY_RESET}" ;execute=false ;break ;;
"yesforall") echo -e "${STY_BLUE}Alright, won't ask again. Executing...${STY_RESET}"; ask=false ;break ;;
*) echo -e "${STY_RED}Please enter [y/e/s/yesforall].${STY_RESET}";;
esac
done
fi
if $execute;then x "$@";else
echo -e "${STY_YELLOW}[$0]: Skipped \"$@\"${STY_RESET}"
fi
}
# When use v() for a defined function, use x() INSIDE its definition to catch errors.
function x(){
if "$@";then local cmdstatus=0;else local cmdstatus=1;fi # 0=normal; 1=failed; 2=failed but ignored
while [ $cmdstatus == 1 ] ;do
echo -e "${STY_RED}[$0]: Command \"${STY_GREEN}$@${STY_RED}\" has failed."
echo -e "You may need to resolve the problem manually BEFORE repeating this command."
echo -e "[Tip] If a certain package is failing to install, try installing it separately in another terminal.${STY_RESET}"
echo " r = Repeat this command (DEFAULT)"
echo " e = Exit now"
echo " i = Ignore this error and continue (your setup might not work correctly)"
local p; read -p " [R/e/i]: " p
case $p in
[iI]) echo -e "${STY_BLUE}Alright, ignore and continue...${STY_RESET}";cmdstatus=2;;
[eE]) echo -e "${STY_BLUE}Alright, will exit.${STY_RESET}";break;;
*) echo -e "${STY_BLUE}OK, repeating...${STY_RESET}"
if "$@";then cmdstatus=0;else cmdstatus=1;fi
;;
esac
done
case $cmdstatus in
0) echo -e "${STY_BLUE}[$0]: Command \"${STY_GREEN}$@${STY_BLUE}\" finished.${STY_RESET}";;
1) echo -e "${STY_RED}[$0]: Command \"${STY_GREEN}$@${STY_RED}\" has failed. Exiting...${STY_RESET}";exit 1;;
2) echo -e "${STY_RED}[$0]: Command \"${STY_GREEN}$@${STY_RED}\" has failed but ignored by user.${STY_RESET}";;
esac
}
function showfun(){
echo -e "${STY_BLUE}[$0]: The definition of function \"$1\" is as follows:${STY_RESET}"
printf "${STY_GREEN}"
type -a $1
printf "${STY_RESET}"
}
function pause(){
if [ ! "$ask" == "false" ];then
printf "${STY_FAINT}${STY_SLANT}"
local p; read -p "(Ctrl-C to abort, others to proceed)" p
printf "${STY_RESET}"
fi
}
function remove_bashcomments_emptylines(){
mkdir -p $(dirname $2)
cat $1 | sed -e '/^[[:blank:]]*#/d;s/#.*//' -e '/^[[:space:]]*$/d' > $2
}
function prevent_sudo_or_root(){
case $(whoami) in
root) echo -e "${STY_RED}[$0]: This script is NOT to be executed with sudo or as root. Aborting...${STY_RESET}";exit 1;;
esac
}
function git_auto_unshallow(){
# We need this function for latest_commit_hash to work properly
if [[ -f "$(git rev-parse --git-dir)/shallow" ]]; then
echo "Shallow clone detected. Unshallowing..."
git fetch --unshallow
fi
}
function latest_commit_timestamp(){
local target_path="$1"
local result=$(git log -1 --format="%ct" -- "$target_path" 2>/dev/null)
if [[ -z "$result" ]]; then
echo "[latest_commit_timestamp] The timestamp of \"$target_path\" is empty. Aborting..." >&2
return 1
fi
echo $result
}
+88
View File
@@ -0,0 +1,88 @@
# This is NOT a script for execution, but for loading functions, so NOT need execution permission or shebang.
# NOTE that you NOT need to `cd ..' because the `$0' is NOT this file, but the script file which will source this file.
# The script that use this file should have two lines on its top as follows:
# cd "$(dirname "$0")" export base="$(pwd)"
showhelp(){
echo -e "Syntax: $0 [Options]...
Idempotent installation script for dotfiles.
If no option is specified, run default install process.
-h, --help Print this help message and exit
-f, --force (Dangerous) Force mode without any confirm
-c, --clean Clean the build cache first
--skip-allgreeting Skip the whole process greeting
--skip-alldeps Skip the whole process installing dependency
--skip-allsetups Skip the whole process setting up permissions/services etc
--skip-allfiles Skip the whole process copying configuration files
-s, --skip-sysupdate Skip system package upgrade e.g. \"sudo pacman -Syu\"
--skip-hyprland Skip installing the config for Hyprland
--skip-fish Skip installing the config for Fish
--skip-plasmaintg Skip installing plasma-browser-integration
--skip-miscconf Skip copying the dirs and files to \".configs\" except for
AGS, Fish and Hyprland
--exp-files Use experimental script for the third step copying files
--fontset <set> (Unavailable yet) Use a set of pre-defined font and config
--via-nix (Unavailable yet) Use Nix to install dependencies
--exp-uninstall Use experimental uninstall script
"
}
cleancache(){
rm -rf "$base/cache"
}
# `man getopt` to see more
para=$(getopt \
-o hfk:cs \
-l help,force,fontset:,clean,skip-allgreeting,skip-alldeps,skip-allsetups,skip-allfiles,skip-sysupdate,skip-fish,skip-hyprland,skip-plasmaintg,skip-miscconf,exp-files,via-nix,exp-uninstall \
-n "$0" -- "$@")
[ $? != 0 ] && echo "$0: Error when getopt, please recheck parameters." && exit 1
#####################################################################################
## getopt Phase 1
# ignore parameter's order, execute options below first
eval set -- "$para"
while true ; do
case "$1" in
-h|--help) showhelp;exit;;
-c|--clean) cleancache;shift;;
--) break ;;
*) shift ;;
esac
done
#####################################################################################
## getopt Phase 2
eval set -- "$para"
while true ; do
case "$1" in
## Already processed in phase 1, but not exited
-c|--clean) shift;;
## Ones without parameter
-f|--force) ask=false;shift;;
--skip-allgreeting) SKIP_ALLGREETING=true;shift;;
--skip-alldeps) SKIP_ALLDEPS=true;shift;;
--skip-allsetups) SKIP_ALLSETUPS=true;shift;;
--skip-allfiles) SKIP_ALLFILES=true;shift;;
-s|--skip-sysupdate) SKIP_SYSUPDATE=true;shift;;
--skip-hyprland) SKIP_HYPRLAND=true;shift;;
--skip-fish) SKIP_FISH=true;shift;;
--skip-miscconf) SKIP_MISCCONF=true;shift;;
--skip-plasmaintg) SKIP_PLASMAINTG=true;shift;;
--exp-files) EXPERIMENTAL_FILES_SCRIPT=true;shift;;
--via-nix) INSTALL_VIA_NIX=true;shift;;
--exp-uninstall) EXPERIMENTAL_UNINSTALL_SCRIPT=true;shift;;
## Ones with parameter
--fontset)
case $2 in
"default"|"zh-CN"|"vi") fontset="$2";;
*) echo -e "Wrong argument for $1.";exit 1;;
esac;echo "The fontset is ${fontset}.";shift 2;;
## Ending
--) break ;;
*) echo -e "$0: Wrong parameters.";exit 1;;
esac
done
+111
View File
@@ -0,0 +1,111 @@
# This script depends on `functions.sh' .
# This is NOT a script for execution, but for loading functions, so NOT need execution permission or shebang.
# NOTE that you NOT need to `cd ..' because the `$0' is NOT this file, but the script file which will source this file.
# This file is provided for any distros, mainly non-Arch(based) distros.
# The script that use this file should have two lines on its top as follows:
# cd "$(dirname "$0")"
# export base="$(pwd)"
install-agsv1(){
x mkdir -p $base/cache/agsv1
x cd $base/cache/agsv1
try git init -b main
try git remote add origin https://github.com/Aylur/ags.git
x git pull origin main && git submodule update --init --recursive
x git fetch --tags
x git checkout v1.9.0
x npm install
x meson setup build # --reconfigure
x meson install -C build
x sudo mv /usr/local/bin/ags{,v1}
x cd $base
}
install-Rubik(){
x mkdir -p $base/cache/Rubik
x cd $base/cache/Rubik
try git init -b main
try git remote add origin https://github.com/googlefonts/rubik.git
x git pull origin main && git submodule update --init --recursive
x sudo mkdir -p /usr/local/share/fonts/TTF/
x sudo cp fonts/variable/Rubik*.ttf /usr/local/share/fonts/TTF/
x sudo mkdir -p /usr/local/share/licenses/ttf-rubik/
x sudo cp OFL.txt /usr/local/share/licenses/ttf-rubik/LICENSE
x fc-cache -fv
x gsettings set org.gnome.desktop.interface font-name 'Rubik 11'
x cd $base
}
install-Gabarito(){
x mkdir -p $base/cache/Gabarito
x cd $base/cache/Gabarito
try git init -b main
try git remote add origin https://github.com/naipefoundry/gabarito.git
x git pull origin main && git submodule update --init --recursive
x sudo mkdir -p /usr/local/share/fonts/TTF/
x sudo cp fonts/ttf/Gabarito*.ttf /usr/local/share/fonts/TTF/
x sudo mkdir -p /usr/local/share/licenses/ttf-gabarito/
x sudo cp OFL.txt /usr/local/share/licenses/ttf-gabarito/LICENSE
x fc-cache -fv
x cd $base
}
install-OneUI(){
x mkdir -p $base/cache/OneUI4-Icons
x cd $base/cache/OneUI4-Icons
try git init -b main
try git remote add origin https://github.com/end-4/OneUI4-Icons.git
# try git remote add origin https://github.com/mjkim0727/OneUI4-Icons.git
x git pull origin main && git submodule update --init --recursive
x sudo mkdir -p /usr/local/share/icons
x sudo cp -r OneUI /usr/local/share/icons
x sudo cp -r OneUI-dark /usr/local/share/icons
x sudo cp -r OneUI-light /usr/local/share/icons
x cd $base
}
install-bibata(){
x mkdir -p $base/cache/bibata-cursor
x cd $base/cache/bibata-cursor
name="Bibata-Modern-Classic"
file="$name.tar.xz"
# Use axel because `curl -O` always downloads a file with 0 byte size, idk why
x axel https://github.com/ful1e5/Bibata_Cursor/releases/latest/download/$file
tar -xf $file
x sudo mkdir -p /usr/local/share/icons
x sudo cp -r $name /usr/local/share/icons
x cd $base
}
install-MicroTeX(){
x mkdir -p $base/cache/MicroTeX
x cd $base/cache/MicroTeX
try git init -b master
try git remote add origin https://github.com/NanoMichael/MicroTeX.git
x git pull origin master && git submodule update --init --recursive
x mkdir -p build
x cd build
x cmake ..
x make -j32
x sudo mkdir -p /opt/MicroTeX
x sudo cp ./LaTeX /opt/MicroTeX/
x sudo cp -r ./res /opt/MicroTeX/
x cd $base
}
install-uv(){
x bash <(curl -LJs "https://astral.sh/uv/install.sh")
}
install-python-packages(){
UV_NO_MODIFY_PATH=1
ILLOGICAL_IMPULSE_VIRTUAL_ENV=$XDG_STATE_HOME/quickshell/.venv
x mkdir -p $(eval echo $ILLOGICAL_IMPULSE_VIRTUAL_ENV)
# we need python 3.12 https://github.com/python-pillow/Pillow/issues/8089
x uv venv --prompt .venv $(eval echo $ILLOGICAL_IMPULSE_VIRTUAL_ENV) -p 3.12
x source $(eval echo $ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate
x uv pip install -r sdata/uv/requirements.txt
x deactivate # We don't need the virtual environment anymore
}
+45
View File
@@ -0,0 +1,45 @@
# This script is meant to be sourced.
# It's not for directly running.
#####################################################################################
printf "${STY_CYAN}[$0]: Hi there! Before we start:${STY_RESET}\n"
printf "\n"
printf "${STY_PURPLE}${STY_BOLD}[NEW] illogical-impulse is now powered by Quickshell.${STY_PURPLE}\n"
printf '# If you were using the old version with AGS and would like to keep it, do not run this script.\n'
printf '# The AGS version, although uses less memory, has much worse performance (it uses Gtk3). \n'
printf '# If you aren'\''t running on ewaste, the Quickshell version is recommended. \n'
printf "# If you would like the AGS version anyway, run the following to switch to its branch first:\n ${STY_INVERT} git checkout ii-ags && ./install.sh ${STY_RESET}\n"
printf "\n"
pause
printf "${STY_CYAN}${STY_BOLD}Quick overview about what this script does:${STY_CYAN}\n"
printf " 1. Install dependencies.\n"
printf " 2. Setup permissions/services etc.\n"
printf " 3. Copying config files.${STY_RESET}\n"
pause
printf "${STY_CYAN}${STY_BOLD}Tips:${STY_CYAN}\n"
printf " a) It has been designed to be idempotent which means you can run it multiple times.\n"
printf " b) Use ${STY_INVERT} --help ${STY_CYAN} for more options.${STY_RESET}\n"
printf "${STY_YELLOW}${STY_BOLD}Note: ${STY_YELLOW}"
printf "It does not handle system-level/hardware stuff like Nvidia drivers. Please do it by yourself.\n"
printf "${STY_RESET}"
printf "\n"
pause
case $ask in
false) sleep 0 ;;
*)
printf "${STY_BLUE}"
printf "${STY_BOLD}Do you want to confirm every time before a command executes?${STY_BLUE}\n"
printf " y = Yes, ask me before executing each of them. (DEFAULT)\n"
printf " n = No, I know everything this script will do, just execute them automatically.\n"
printf " a = Abort.\n"
read -p "===> [Y/n/a]: " p
case $p in
n) ask=false ;;
a) exit 1 ;;
*) ask=true ;;
esac
printf "${STY_RESET}"
;;
esac
+171
View File
@@ -0,0 +1,171 @@
# This script is meant to be sourced.
# It's not for directly running.
function outdate_detect(){
# Shallow clone prevent latest_commit_timestamp() from working.
v git_auto_unshallow
local source_path="$1"
local target_path="$2"
local source_timestamp="$(latest_commit_timestamp $source_path 2>/dev/null)"
local target_timestamp="$(latest_commit_timestamp $target_path 2>/dev/null)"
local outdate_detect_mode="$(cat ${target_path}/outdate-detect-mode)"
# outdate-detect-mode possible modes:
# - WIP: Work in progress (should be taken as outdated)
# - FORCE_OUTDATED: forcely taken as outdated
# - FORCE_UPDATED: forcely taken as updated
# - AUTO: Let the script decide automatically
#
# outdate status possible values:
# - WIP,FORCE_OUTDATED,FORCE_UPDATED: Inherited directly from outdate-detect-mode
# - EMPTY_SOURCE: source path has empty timestamp, maybe not tracked by git (should be taken as outdated)
# - EMPTY_TARGET: target path has empty timestamp, maybe not tracked by git (should be taken as outdated)
# - OUTDATED: target path is older than source path.
# - UPDATED: target path is not older than source path.
# Does target path have an outdate-detect-mode file which content is special?
if [[ "${outdate_detect_mode}" =~ ^(WIP|FORCE_OUTDATED|FORCE_UPDATED)$ ]]; then
echo "${outdate_detect_mode}"
# Does source path has an empty timestamp?
elif [ -z "$source_timestamp" ]; then
echo "EMPTY_SOURCE"
# Does target path has an empty timestamp?
elif [ -z "$target_timestamp" ]; then
echo "EMPTY_TARGET"
# If target path is older than source path, it's outdated.
elif [[ "$target_timestamp" -lt "$source_timestamp" ]]; then
echo "OUTDATED"
else
echo "UPDATED"
fi
}
####################
# Detect architecture
# Helpful link(s):
# http://stackoverflow.com/questions/45125516
export MACHINE_ARCH=$(uname -m)
case $MACHINE_ARCH in
"x86_64") sleep 0;;
*)
printf "${STY_YELLOW}"
printf "===WARNING===\n"
printf "Detected machine architecture: ${MACHINE_ARCH}\n"
printf "This script only supports x86_64.\n"
printf "It is very likely to fail when installing dependencies on your machine.\n"
printf "\n"
printf "${STY_RESET}"
pause
;;
esac
####################
# Detect distro
# Helpful link(s):
# http://stackoverflow.com/questions/29581754
# https://github.com/which-distro/os-release
export OS_RELEASE_FILE=${OS_RELEASE_FILE:-/etc/os-release}
test -f ${OS_RELEASE_FILE} || \
( echo "${OS_RELEASE_FILE} does not exist. Aborting..." ; exit 1 ; )
export OS_DISTRO_ID=$(awk -F'=' '/^ID=/ { gsub("\"","",$2); print tolower($2) }' ${OS_RELEASE_FILE} 2> /dev/null)
export OS_DISTRO_ID_LIKE=$(awk -F'=' '/^ID_LIKE=/ { gsub("\"","",$2); print tolower($2) }' ${OS_RELEASE_FILE} 2> /dev/null)
if [[ "$INSTALL_VIA_NIX" == "true" ]]; then
TARGET_ID=nix
printf "${STY_YELLOW}"
printf "===WARNING===\n"
printf "./sdist/${TARGET_ID}/install-deps.sh will be used.\n"
printf "The process is still WIP.\n"
printf "Proceed only at your own risk.\n"
printf "\n"
printf "${STY_RESET}"
pause
source ./sdist/${TARGET_ID}/install-deps.sh
elif [[ "$OS_DISTRO_ID" =~ ^(arch|endeavouros)$ ]]; then
TARGET_ID=arch
printf "${STY_GREEN}"
printf "===INFO===\n"
printf "Detected distro ID: ${OS_DISTRO_ID}\n"
printf "./sdist/${TARGET_ID}/install-deps.sh will be used.\n"
printf "\n"
printf "${STY_RESET}"
pause
source ./sdist/${TARGET_ID}/install-deps.sh
elif [[ -f "./sdist/${OS_DISTRO_ID}/install-deps.sh" ]]; then
TARGET_ID=${OS_DISTRO_ID}
printf "${STY_PURPLE}"
printf "===NOTICE===\n"
printf "Detected distro ID: ${OS_DISTRO_ID}\n"
printf "./sdist/${TARGET_ID}/install-deps.sh will be used.\n"
printf "This file is provided by the community.\n"
printf "It is not officially supported by github:end-4/dots-hyprland .\n"
test -f "./sdist/${TARGET_ID}/README.md" && \
printf "Read ${STY_INVERT} ./sdist/${TARGET_ID}/README.md ${STY_PURPLE} for more information.\n"
printf "${STY_BOLD}"
printf "If you find out any problems about it, PR is welcomed if you are able to address it. Or, create a discussion about it, but please do not submit issue, because the developers do not use this distro, therefore they cannot help.${STY_RESET}\n"
printf "${STY_PURPLE}"
printf "Proceed only at your own risk.\n"
printf "\n"
printf "${STY_RESET}"
pause
tmp_update_status="$(outdate_detect sdist/arch sdist/${TARGET_ID})"
if [[ "${tmp_update_status}" =~ ^(OUTDATED|EMPTY_TARGET|EMPTY_SOURCE|FORCE_OUTDATED|WIP)$ ]]; then
printf "${STY_RED}"
printf "${STY_BOLD}===URGENT===${STY_RED}\n"
printf "The community provided ./sdist/${TARGET_ID}/ is not updated (update status: ${tmp_update_status}),\n"
printf "which means it does not fully reflect the latest changes of ./sdist/arch/ .\n"
printf "You are highly recommended to abort this script, until someone (maybe you?) has updated the ./sdist/${TARGET_ID}/ to fully reflect the latest changes in ./sdist/arch/ .\n"
printf "PR is welcomed. Please see discussion#2140 for details.\n"
printf "${STY_UNDERLINE}https://github.com/end-4/dots-hyprland/discussions/2140${STY_RESET}\n"
printf "${STY_RED}${STY_INVERT}If you are proceeding anyway, illogical-impulse will very likely not work as expected.${STY_RESET}\n"
if [ "$ask" = "false" ]; then
echo "Urgent problem encountered, aborting...";exit 1
fi
printf "${STY_RED}Still proceed?${STY_RESET}\n"
read -p "[y/N]: " p
case "$p" in
[yY])sleep 0;;
*)echo "Aborting...";exit 1;;
esac
fi
source ./sdist/${TARGET_ID}/install-deps.sh
elif [[ "$OS_DISTRO_ID_LIKE" == "arch" || "$OS_DISTRO_ID" == "cachyos" ]]; then
TARGET_ID=arch
printf "${STY_YELLOW}"
printf "===WARNING===\n"
printf "Detected distro ID: ${OS_DISTRO_ID}\n"
printf "Detected distro ID_LIKE: ${OS_DISTRO_ID_LIKE}\n"
printf "./sdist/${TARGET_ID}/install-deps.sh will be used.\n"
printf "Ideally, it should also work for your distro.\n"
printf "Still, there is a chance that it not works as expected or even fails.\n"
printf "Proceed only at your own risk.\n"
printf "\n"
printf "${STY_RESET}"
pause
source ./sdist/${TARGET_ID}/install-deps.sh
else
TARGET_ID=fallback
printf "${STY_RED}"
printf "${STY_BOLD}===URGENT===${STY_RED}\n"
printf "Detected distro ID: ${OS_DISTRO_ID}\n"
printf "Detected distro ID_LIKE: ${OS_DISTRO_ID_LIKE}\n"
printf "./sdist/${OS_DISTRO_ID}/install-deps.sh not found.\n"
printf "./sdist/${TARGET_ID}/install-deps.sh will be used.\n"
printf "1. It may disrupt your system and will likely fail without your manual intervention.\n"
printf "2. It's WIP and only contains small number of dependencies far from enough.\n"
printf "Proceed only at your own risk.\n"
printf "${STY_RESET}"
pause
source ./sdist/${TARGET_ID}/install-deps.sh
fi
+92
View File
@@ -0,0 +1,92 @@
# This script is meant to be sourced.
# It's not for directly running.
####################
# Detect distro
# Helpful link(s):
# http://stackoverflow.com/questions/29581754
# https://github.com/which-distro/os-release
export OS_RELEASE_FILE=${OS_RELEASE_FILE:-/etc/os-release}
test -f ${OS_RELEASE_FILE} || \
( echo "${OS_RELEASE_FILE} does not exist. Aborting..." ; exit 1 ; )
export OS_DISTRO_ID=$(awk -F'=' '/^ID=/ { gsub("\"","",$2); print tolower($2) }' ${OS_RELEASE_FILE} 2> /dev/null)
export OS_DISTRO_ID_LIKE=$(awk -F'=' '/^ID_LIKE=/ { gsub("\"","",$2); print tolower($2) }' ${OS_RELEASE_FILE} 2> /dev/null)
if [[ "$INSTALL_VIA_NIX" == "true" ]]; then
TARGET_ID=fallback
printf "${STY_YELLOW}"
printf "===WARNING===\n"
printf "./sdist/${TARGET_ID}/install-setups.sh will be used.\n"
printf "The process is still WIP.\n"
printf "Proceed only at your own risk.\n"
printf "\n"
printf "${STY_RESET}"
pause
source ./sdist/${TARGET_ID}/install-setups.sh
elif [[ "$OS_DISTRO_ID" == "arch" ]]; then
TARGET_ID=arch
printf "${STY_GREEN}"
printf "===INFO===\n"
printf "Detected distro ID: ${OS_DISTRO_ID}\n"
printf "./sdist/${TARGET_ID}/install-setups.sh will be used.\n"
printf "\n"
printf "${STY_RESET}"
pause
source ./sdist/${TARGET_ID}/install-setups.sh
elif [[ -f "./sdist/${OS_DISTRO_ID}/install-setups.sh" ]]; then
TARGET_ID=${OS_DISTRO_ID}
printf "${STY_PURPLE}"
printf "===NOTICE===\n"
printf "Detected distro ID: ${OS_DISTRO_ID}\n"
printf "./sdist/${TARGET_ID}/install-setups.sh will be used.\n"
printf "This file is provided by the community.\n"
printf "It is not officially supported by github:end-4/dots-hyprland .\n"
printf "${STY_BG_PURPLE}"
printf "If you find out any problems about it, PR is welcomed if you are able to address it. Or, create a discussion about it, but please do not submit issue, because the developers do not use this distro, therefore they cannot help.${STY_RESET}\n"
printf "${STY_PURPLE}"
printf "Proceed only at your own risk.\n"
printf "\n"
printf "${STY_RESET}"
pause
source ./sdist/${TARGET_ID}/install-setups.sh
elif [[ "$OS_DISTRO_ID_LIKE" == "arch" || "$OS_DISTRO_ID" == "cachyos" ]]; then
TARGET_ID=arch
printf "${STY_YELLOW}"
printf "===WARNING===\n"
printf "Detected distro ID: ${OS_DISTRO_ID}\n"
printf "Detected distro ID_LIKE: ${OS_DISTRO_ID_LIKE}\n"
printf "./sdist/${TARGET_ID}/install-setups.sh will be used.\n"
printf "Ideally, it should also work for your distro.\n"
printf "Still, there is a chance that it not works as expected or even fails.\n"
printf "Proceed only at your own risk.\n"
printf "\n"
printf "${STY_RESET}"
pause
source ./sdist/${TARGET_ID}/install-setups.sh
else
TARGET_ID=fallback
printf "${STY_RED}"
printf "===WARNING===\n"
printf "Detected distro ID: ${OS_DISTRO_ID}\n"
printf "Detected distro ID_LIKE: ${OS_DISTRO_ID_LIKE}\n"
printf "./sdist/${OS_DISTRO_ID}/install-setups.sh not found.\n"
printf "./sdist/${TARGET_ID}/install-setups.sh will be used.\n"
printf "It might fail or disrupt your system.\n"
printf "Proceed only at your own risk.\n"
printf "\n"
printf "${STY_RESET}"
pause
source ./sdist/${TARGET_ID}/install-setups.sh
fi
+201
View File
@@ -0,0 +1,201 @@
# This script is meant to be sourced.
# It's not for directly running.
# TODO: https://github.com/end-4/dots-hyprland/issues/2137
# TODO: make function backup_configs only cover the possibly overwritten ones.
function backup_configs(){
local backup_dir="$BACKUP_DIR"
mkdir -p "$backup_dir"
echo "Backing up $XDG_CONFIG_HOME to $backup_dir/config_backup"
rsync -av --progress "$XDG_CONFIG_HOME/" "$backup_dir/config_backup/"
echo "Backing up $HOME/.local to $backup_dir/local_backup"
declare -a arg_excludes=()
arg_excludes+=(--exclude "$HOME/.local/share/Steam")
arg_excludes+=(--exclude "$HOME/.local/share/steam")
rsync -av --progress "${arg_excludes[@]}" "$HOME/.local/" "$backup_dir/local_backup/"
declare -a arg_excludes=()
}
function warning_rsync(){
printf "${STY_YELLOW}"
printf "The commands using rsync will overwrite the destination when it exists already.\n"
printf "${STY_RESET}"
}
function ask_backup_configs(){
printf "${STY_RED}"
printf "Would you like to create a backup for \"$XDG_CONFIG_HOME\" and \"$HOME/.local/\" folders?\n[y/N]: "
read -p " " backup_confirm
case $backup_confirm in
[yY][eE][sS]|[yY]) backup_configs ;;
*) echo "Skipping backup..." ;;
esac
printf "${STY_RESET}"
}
#####################################################################################
# In case some folders does not exists
v mkdir -p $XDG_BIN_HOME $XDG_CACHE_HOME $XDG_CONFIG_HOME $XDG_DATA_HOME
case $ask in
false) sleep 0 ;;
*) ask_backup_configs ;;
esac
# TODO: A better method for users to choose their customization,
# for example some users may prefer ZSH over FISH, and foot over kitty.
# But the dot files are using FISH and kitty as the default software, e.g. `.local/share/Konsole` has `Command=/bin/fish`.
# It may be possible that we provide options for users to make their decision.
# `--delete' for rsync to make sure that
# original dotfiles and new ones in the SAME DIRECTORY
# (eg. in ~/.config/hypr) won't be mixed together
# MISC (For dots/.config/* but not fish, not Hyprland)
case $SKIP_MISCCONF in
true) sleep 0;;
*)
for i in $(find dots/.config/ -mindepth 1 -maxdepth 1 ! -name 'fish' ! -name 'hypr' -exec basename {} \;); do
# i="dots/.config/$i"
echo "[$0]: Found target: dots/.config/$i"
if [ -d "dots/.config/$i" ];then warning_rsync; v rsync -av --delete "dots/.config/$i/" "$XDG_CONFIG_HOME/$i/"
elif [ -f "dots/.config/$i" ];then warning_rsync; v rsync -av "dots/.config/$i" "$XDG_CONFIG_HOME/$i"
fi
done
;;
esac
case $SKIP_FISH in
true) sleep 0;;
*)
warning_rsync; v rsync -av --delete dots/.config/fish/ "$XDG_CONFIG_HOME"/fish/
;;
esac
# For Hyprland
declare -a arg_excludes=()
arg_excludes+=(--exclude '/custom')
arg_excludes+=(--exclude '/hyprlock.conf')
arg_excludes+=(--exclude '/hypridle.conf')
arg_excludes+=(--exclude '/hyprland.conf')
case $SKIP_HYPRLAND in
true) sleep 0;;
*)
warning_rsync; v rsync -av --delete "${arg_excludes[@]}" dots/.config/hypr/ "$XDG_CONFIG_HOME"/hypr/
t="$XDG_CONFIG_HOME/hypr/hyprland.conf"
if [ -f $t ];then
echo -e "${STY_BLUE}[$0]: \"$t\" already exists.${STY_RESET}"
v mv $t $t.old
v cp -f dots/.config/hypr/hyprland.conf $t
existed_hypr_conf_firstrun=y
else
echo -e "${STY_YELLOW}[$0]: \"$t\" does not exist yet.${STY_RESET}"
v cp dots/.config/hypr/hyprland.conf $t
existed_hypr_conf=n
fi
t="$XDG_CONFIG_HOME/hypr/hypridle.conf"
if [ -f $t ];then
echo -e "${STY_BLUE}[$0]: \"$t\" already exists.${STY_RESET}"
v cp -f dots/.config/hypr/hypridle.conf $t.new
existed_hypridle_conf=y
else
echo -e "${STY_YELLOW}[$0]: \"$t\" does not exist yet.${STY_RESET}"
v cp dots/.config/hypr/hypridle.conf $t
existed_hypridle_conf=n
fi
t="$XDG_CONFIG_HOME/hypr/hyprlock.conf"
if [ -f $t ];then
echo -e "${STY_BLUE}[$0]: \"$t\" already exists.${STY_RESET}"
v cp -f dots/.config/hypr/hyprlock.conf $t.new
existed_hyprlock_conf=y
else
echo -e "${STY_YELLOW}[$0]: \"$t\" does not exist yet.${STY_RESET}"
v cp dots/.config/hypr/hyprlock.conf $t
existed_hyprlock_conf=n
fi
t="$XDG_CONFIG_HOME/hypr/custom"
if [ -d $t ];then
echo -e "${STY_BLUE}[$0]: \"$t\" already exists, will not do anything.${STY_RESET}"
else
echo -e "${STY_YELLOW}[$0]: \"$t\" does not exist yet.${STY_RESET}"
warning_rsync; v rsync -av --delete dots/.config/hypr/custom/ $t/
fi
;;
esac
declare -a arg_excludes=()
# some foldes (eg. .local/bin) should be processed separately to avoid `--delete' for rsync,
# since the files here come from different places, not only about one program.
# v rsync -av ".local/bin/" "$XDG_BIN_HOME" # No longer needed since scripts are no longer in ~/.local/bin
warning_rsync; v rsync -av ".local/share/icons/" "${XDG_DATA_HOME:-$HOME/.local/share}"/icons/
warning_rsync; v rsync -av ".local/share/konsole/" "${XDG_DATA_HOME:-$HOME/.local/share}"/konsole/
# Prevent hyprland from not fully loaded
sleep 1
try hyprctl reload
existed_zsh_conf=n
grep -q 'source ${XDG_CONFIG_HOME:-~/.config}/zshrc.d/dots-hyprland.zsh' ~/.zshrc && existed_zsh_conf=y
warn_files=()
warn_files_tests=()
warn_files_tests+=(/usr/local/lib/{GUtils-1.0.typelib,Gvc-1.0.typelib,libgutils.so,libgvc.so})
warn_files_tests+=(/usr/local/share/fonts/TTF/Rubik{,-Italic}'[wght]'.ttf)
warn_files_tests+=(/usr/local/share/licenses/ttf-rubik)
warn_files_tests+=(/usr/local/share/fonts/TTF/Gabarito-{Black,Bold,ExtraBold,Medium,Regular,SemiBold}.ttf)
warn_files_tests+=(/usr/local/share/licenses/ttf-gabarito)
warn_files_tests+=(/usr/local/share/icons/OneUI{,-dark,-light})
warn_files_tests+=(/usr/local/share/icons/Bibata-Modern-Classic)
warn_files_tests+=(/usr/local/bin/{LaTeX,res})
for i in ${warn_files_tests[@]}; do
echo $i
test -f $i && warn_files+=($i)
test -d $i && warn_files+=($i)
done
#####################################################################################
# TODO: output the logs below to a temp file and cat that file, also show the path of the file so users will be able to read it again.
printf "\n"
printf "\n"
printf "\n"
printf "${STY_CYAN}[$0]: Finished${STY_RESET}\n"
printf "\n"
printf "${STY_CYAN}When starting Hyprland from your display manager (login screen) ${STY_RED} DO NOT SELECT UWSM ${STY_RESET}\n"
printf "\n"
printf "${STY_CYAN}If you are already running Hyprland,${STY_RESET}\n"
printf "${STY_CYAN}Press ${STY_BG_CYAN} Ctrl+Super+T ${STY_BG_CYAN} to select a wallpaper${STY_RESET}\n"
printf "${STY_CYAN}Press ${STY_BG_CYAN} Super+/ ${STY_CYAN} for a list of keybinds${STY_RESET}\n"
printf "\n"
printf "${STY_CYAN}For suggestions/hints after installation:${STY_RESET}\n"
printf "${STY_CYAN}${STY_UNDERLINE} https://ii.clsty.link/en/ii-qs/01setup/#post-installation ${STY_RESET}\n"
printf "\n"
case $existed_hypr_conf_firstrun in
y) printf "\n${STY_YELLOW}[$0]: Warning: \"$XDG_CONFIG_HOME/hypr/hyprland.conf\" already existed before. As it seems it is your first run, we replaced it with a new one. ${STY_RESET}\n"
printf "${STY_YELLOW}As it seems it is your first run, we replaced it with a new one. The old one has been renamed to \"$XDG_CONFIG_HOME/hypr/hyprland.conf.old\".${STY_RESET}\n"
;;esac
case $existed_hypr_conf in
y) printf "\n${STY_YELLOW}[$0]: Warning: \"$XDG_CONFIG_HOME/hypr/hyprland.conf\" already existed before and we didn't overwrite it. ${STY_RESET}\n"
printf "${STY_YELLOW}Please use \"$XDG_CONFIG_HOME/hypr/hyprland.conf.new\" as a reference for a proper format.${STY_RESET}\n"
;;esac
case $existed_hypridle_conf in
y) printf "\n${STY_YELLOW}[$0]: Warning: \"$XDG_CONFIG_HOME/hypr/hypridle.conf\" already existed before and we didn't overwrite it. ${STY_RESET}\n"
printf "${STY_YELLOW}Please use \"$XDG_CONFIG_HOME/hypr/hypridle.conf.new\" as a reference for a proper format.${STY_RESET}\n"
;;esac
case $existed_hyprlock_conf in
y) printf "\n${STY_YELLOW}[$0]: Warning: \"$XDG_CONFIG_HOME/hypr/hyprlock.conf\" already existed before and we didn't overwrite it. ${STY_RESET}\n"
printf "${STY_YELLOW}Please use \"$XDG_CONFIG_HOME/hypr/hyprlock.conf.new\" as a reference for a proper format.${STY_RESET}\n"
;;esac
if [[ -z "${ILLOGICAL_IMPULSE_VIRTUAL_ENV}" ]]; then
printf "\n${STY_RED}[$0]: \!! Important \!! : Please ensure environment variable ${STY_RESET} \$ILLOGICAL_IMPULSE_VIRTUAL_ENV ${STY_RED} is set to proper value (by default \"~/.local/state/quickshell/.venv\"), or Quickshell config will not work. We have already provided this configuration in ~/.config/hypr/hyprland/env.conf, but you need to ensure it is included in hyprland.conf, and also a restart is needed for applying it.${STY_RESET}\n"
fi
if [[ ! -z "${warn_files[@]}" ]]; then
printf "\n${STY_RED}[$0]: \!! Important \!! : Please delete ${STY_RESET} ${warn_files[*]} ${STY_RED} manually as soon as possible, since we\'re now using AUR package or local PKGBUILD to install them for Arch(based) Linux distros, and they'll take precedence over our installation, or at least take up more space.${STY_RESET}\n"
fi
+139
View File
@@ -0,0 +1,139 @@
## Why is this important?
Instead of installing python packages via system package manager, we should install them into virtual environment.
This is important because there has been so many complaints about the failure installing/updating python packages via system package manager, see [#1017](https://github.com/end-4/dots-hyprland/issues/1017).
## How to add/remove python package?
1. Edit `requirements.in`. You may refer to [PyPI](https://pypi.org/) for possible package names.
- If PyPI does not have the needed package, we probably need to build it manually inside the venv. In such case we need to edit the install scripts.
2. Run `uv pip compile requirements.in -o requirements.txt` in this folder.
**Notes:**
- For reference see [uv doc](https://docs.astral.sh/uv/pip/dependencies/#using-requirementsin).
- `requirements.txt` is included in Git. It's for locking package versions to enhance stability and reproducibility.[^1]
[^1]: In fact, including package version lock file in Git is also the most common way for similar situations, for example the `package-lock.json` of Node.js projects (see also [this stackoverflow question](https://stackoverflow.com/questions/48524417/should-the-package-lock-json-file-be-added-to-gitignore)). Although there are some situations when it's not suitable to include the lock file, for example [the poetry document](https://python-poetry.org/docs/basic-usage/#committing-your-poetrylock-file-to-version-control) recommend application developers to include package version lock file in Git, but library developers should consider more, such as not inluding the lock file or including it but refreshing regularly.
## How will the python packages get installed?
For summary:
- They will be installed to the virtual environment `$ILLOGICAL_IMPULSE_VIRTUAL_ENV`.
- The default value of `$ILLOGICAL_IMPULSE_VIRTUAL_ENV` is `$XDG_STATE_HOME/quickshell/.venv`.
- The default value of `$XDG_STATE_HOME` is `$HOME/.local/state`.
- Currently we use `env = ILLOGICAL_IMPULSE_VIRTUAL_ENV, ~/.local/state/quickshell/.venv` in `~/.config/hypr/hyprland/env.conf` to set this environment variable.[^2]
For details: see the function `install-python-packages()` defined in `/sdata/lib/package-installers.sh`.
[^2]: Hyprland seems to have weird problem dealing with recursive variable, so we can not use `$XDG_STATE_HOME/quickshell/.venv` even if we had set `$XDG_STATE_HOME` to `~/.local/state` explicitly, else `$XDG_STATE_HOME` will possibly not get expanded but get recognised as literally `$XDG_STATE_HOME`. This problem never happens for some users, but according to some issues when we were using recursive variable setting in the past, it's possible to happen for other users. Reason unknown.
## How to use the python packages installed through here?
Basically you'll need to activate the virtual environment first:
```bash
source $(eval echo $ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate
```
It will add the python executable located in the venv to `$PATH` and give it the highest priority.
Run `which python` and you'll understand.
This python executable will also search and use the python package inside the venv,
which enables running any python script or running command provided via python package using the venv.
After that you probably need to deactivate it:
```bash
deactivate
```
### Situation 1: As a single command
**Description:** At someplace which accept a single command,
- run a python script,
- or run a command provided by python package.
Example: In `~/.config/quickshell/ii/screenshot.qml`:
```qml
Process {
id: imageDetectionProcess
command: ["bash", "-c", `${Directories.scriptPath}/images/find_regions.py `
+ `--hyprctl `
+ `--image '${StringUtils.shellSingleQuoteEscape(panelWindow.screenshotPath)}' `
+ `--max-width ${Math.round(panelWindow.screen.width * root.falsePositivePreventionRatio)} `
```
In this example, python script `find_regions.py` is called and receives some arguments.
#### Solution A: shebang
Add the shebang below to the beginning of python script:
```python
#!/usr/bin/env -S\_/bin/sh\_-c\_"source\_\$(eval\_echo\_\$ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate&&exec\_python\_-E\_"\$0"\_"\$@""
```
And that's it!
**Note:** This is the simplest solution as it only modifies the shebang of python script.
However:
- It's only for python script, not the command provided by python package.
- It can not deal with complex argument (e.g. filename containing spaces) passed to the python script.
- If we apply this solution to the example above, it may cause problem, considering that `--image '${StringUtils.shellSingleQuoteEscape(panelWindow.screenshotPath)}'` could be a rather complex argument passed to `find_regions.py`.
- This solution rely on shebang to activate the correct python venv, but the shebang will be ignored if the script is passed as a parameter to python, e.g. `python3 foo.py`.
#### Solution B: bash script as wrapper
First make sure the python script is using the shebang `#!/usr/bin/env python3`, instead of `#!/usr/bin/python3` or something else.
Then write a wrapper script in bash.
Let's continue the `screenshot.qml` example, in the same directory as `find_regions.py`, write a `find-regions-venv.sh`:
```bash
#!/usr/bin/env bash
# Specify the path of the python script.
# The example below only applies when `find_regions.py` and this wrapper script are under the same folder.
PY_SCRIPT="$(cd $(dirname "${BASH_SOURCE[0]}") && pwd)/find_regions.py"
source $(eval echo $ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate
"$PY_SCRIPT" "$@"
deactivate
```
**Not done yet!** Do not forget to update the code calling the original python script.
In this example, in `~/.config/quickshell/ii/screenshot.qml` we should modify `find_regions.py` to the wrapper script `find-regions-venv.sh`:
```qml
Process {
id: imageDetectionProcess
command: ["bash", "-c", `${Directories.scriptPath}/images/find-regions-venv.sh `
+ `--hyprctl `
+ `--image '${StringUtils.shellSingleQuoteEscape(panelWindow.screenshotPath)}' `
+ `--max-width ${Math.round(panelWindow.screen.width * root.falsePositivePreventionRatio)} `
```
### Situation 2: Inside a bash script
Note: the solutions for `Situation 1: As a single command` also apply here; but **not** vice versa.
**Description:**
Inside a bash script,
- run a python script,
- or run a command provided by python package.
**Solution:**
- Add "activation command" before the target line,
- Also add "deactivation command" after the target line.
**Example:**
For running a python script,
take `generate_colors_material.py` as example:
```bash
source "$(eval echo $ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate"
python3 "$SCRIPT_DIR/generate_colors_material.py" "${generate_colors_material_args[@]}" \
> "$STATE_DIR"/user/generated/material_colors.scss
"$SCRIPT_DIR"/applycolor.sh
```
For running a python script provided by python package,
take `kde-material-you-colors` as example:
```bash
source "$(eval echo $ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate"
kde-material-you-colors "$mode_flag" --color "$color" -sv "$sv_num"
deactivate
```
+18
View File
@@ -0,0 +1,18 @@
build
pillow
setuptools-scm
wheel
pywayland
psutil
kde-material-you-colors
materialyoucolor
libsass
material-color-utilities
setproctitle
click
loguru
pycairo
pygobject
tqdm
numpy
opencv-contrib-python
+63
View File
@@ -0,0 +1,63 @@
# This file was autogenerated by uv via the following command:
# uv pip compile sdata/uv/requirements.in -o sdata/uv/requirements.txt
build==1.2.2.post1
# via -r sdata/uv/requirements.in
cffi==1.17.1
# via pywayland
click==8.2.1
# via -r sdata/uv/requirements.in
dbus-python==1.4.0
# via kde-material-you-colors
kde-material-you-colors==1.10.1
# via -r sdata/uv/requirements.in
libsass==0.23.0
# via -r sdata/uv/requirements.in
loguru==0.7.3
# via -r sdata/uv/requirements.in
material-color-utilities==0.2.1
# via -r sdata/uv/requirements.in
materialyoucolor==2.0.10
# via
# -r sdata/uv/requirements.in
# kde-material-you-colors
numpy==2.2.2
# via
# -r sdata/uv/requirements.in
# kde-material-you-colors
# material-color-utilities
# opencv-contrib-python
opencv-contrib-python==4.12.0.88
# via -r sdata/uv/requirements.in
packaging==24.2
# via
# build
# setuptools-scm
pillow==11.1.0
# via
# -r sdata/uv/requirements.in
# kde-material-you-colors
# material-color-utilities
psutil==6.1.1
# via -r sdata/uv/requirements.in
pycairo==1.28.0
# via
# -r sdata/uv/requirements.in
# pygobject
pycparser==2.22
# via cffi
pygobject==3.52.3
# via -r sdata/uv/requirements.in
pyproject-hooks==1.2.0
# via build
pywayland==0.4.18
# via -r sdata/uv/requirements.in
setproctitle==1.3.4
# via -r sdata/uv/requirements.in
setuptools==80.9.0
# via setuptools-scm
setuptools-scm==8.1.0
# via -r sdata/uv/requirements.in
tqdm==4.67.1
# via -r sdata/uv/requirements.in
wheel==0.45.1
# via -r sdata/uv/requirements.in