Created
March 31, 2025 09:58
-
-
Save axelsegebrecht/b36a0e9f17fdf4ad553f3c133d116c74 to your computer and use it in GitHub Desktop.
update list of installed apt packages and flatpaks for an easy restoration
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# ============================================================================== | |
# Script Name: update-package-lists.sh | |
# Description: Generates lists of manually installed APT packages and all | |
# installed Flatpak applications for a specified user. These lists | |
# are saved to files in a format suitable for reinstalling the | |
# software after a system restore or on a new Debian-based machine. | |
# Designed to be run before a backup (e.g., using BorgBackup). | |
# Author: Gemini (Initial generation), Axel Segebrecht | |
# Copyright: Copyright (c) 2025 Axel Segebrecht | |
# License: MIT License (see full text below) | |
# Date: 2025-03-31 | |
# Version: 1.3 (Added Copyright and MIT License) | |
# | |
# --- Purpose --- | |
# To capture the state of installed software (APT manually installed & Flatpaks) | |
# so it can be easily restored later. Run this before backing up the home | |
# directory containing the output files. | |
# | |
# --- Output Files --- | |
# By default, saves files to the running user's home directory: | |
# - $HOME/installed-packages.txt (APT packages) | |
# - $HOME/installed-flatpaks.txt (Flatpak applications) | |
# This path changes if the SCRIPT_TARGET_USER environment variable is set. | |
# For user 'axel', the files would be: | |
# - /home/axel/installed-packages.txt | |
# - /home/axel/installed-flatpaks.txt | |
# | |
# --- Setup --- | |
# 1. Save this script to a file on your system, for example: | |
# /usr/local/bin/update-package-lists.sh | |
# or within a user's directory like: | |
# /home/axel/bin/update-package-lists.sh | |
# | |
# 2. Make the script executable: | |
# chmod +x /path/to/your/update-package-lists.sh | |
# | |
# --- Usage --- | |
# Run this script *before* performing your backup operation. | |
# | |
# A. To run for the currently logged-in user: | |
# /path/to/your/update-package-lists.sh | |
# | |
# B. To run via 'sudo' but generate lists for a specific user (e.g., 'axel'): | |
# sudo SCRIPT_TARGET_USER=axel /path/to/your/update-package-lists.sh | |
# (The script attempts to set correct file ownership for the target user.) | |
# | |
# C. Ensure your backup process includes the generated '.txt' files. | |
# If using BorgBackup, make sure the directory containing these files | |
# (e.g., /home/axel/) is included in your backup sources. | |
# | |
# --- Reinstallation Instructions (After System Restore/Setup) --- | |
# After restoring your backup containing the '.txt' files to the correct location | |
# (e.g., /home/axel/): | |
# | |
# 1. Reinstall APT Packages: | |
# a. First, ensure your system's package sources are up-to-date: | |
# sudo apt update | |
# b. Then, install the packages listed in the file. Using 'xargs' is robust: | |
# xargs -a /home/axel/installed-packages.txt sudo apt install -y | |
# (Replace '/home/axel/' if the file is located elsewhere. The '-y' | |
# flag automatically confirms installation; omit it to review first.) | |
# | |
# 2. Reinstall Flatpak Packages: | |
# a. Ensure Flatpak itself is installed on the new system: | |
# sudo apt install flatpak | |
# b. Add the necessary Flatpak remotes you used previously (especially Flathub): | |
# flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo | |
# (Add any other custom remotes you might have used.) | |
# c. Install the Flatpak applications listed in the file using 'xargs': | |
# xargs -a /home/axel/installed-flatpaks.txt flatpak install -y --noninteractive | |
# (Replace '/home/axel/' if needed. Flatpak will search your configured | |
# remotes for the application IDs. '-y --noninteractive' confirms.) | |
# | |
# --- License --- | |
# | |
# MIT License | |
# | |
# Copyright (c) 2025 Axel Segebrecht | |
# | |
# Permission is hereby granted, free of charge, to any person obtaining a copy | |
# of this software and associated documentation files (the "Software"), to deal | |
# in the Software without restriction, including without limitation the rights | |
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
# copies of the Software, and to permit persons to whom the Software is | |
# furnished to do so, subject to the following conditions: | |
# | |
# The above copyright notice and this permission notice shall be included in all | |
# copies or substantial portions of the Software. | |
# | |
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
# SOFTWARE. | |
# ============================================================================== | |
# --- Configuration --- | |
# Set the username and home directory. Defaults to the user running the script | |
# unless SCRIPT_TARGET_USER environment variable is set (useful when run via sudo). | |
TARGET_USER="${SCRIPT_TARGET_USER:-$(whoami)}" | |
TARGET_HOME=$(eval echo "~$TARGET_USER") # Gets the correct home dir even if run with sudo | |
# Define the output file paths using the determined home directory | |
APT_LIST_FILE="$TARGET_HOME/installed-packages.txt" | |
FLATPAK_LIST_FILE="$TARGET_HOME/installed-flatpaks.txt" | |
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" # Optional: Use if script location matters | |
# --- Script Execution Settings --- | |
# Exit immediately if a command exits with a non-zero status. | |
set -e | |
# Treat unset variables (except $SCRIPT_TARGET_USER handled above) as an error. | |
# set -u # Commented out as SCRIPT_TARGET_USER might be intentionally unset | |
# Exit if any command in a pipeline fails, not just the last one. | |
set -o pipefail | |
# --- Functions --- | |
# Helper function to ensure target directory exists and file is writable/owned by target user | |
ensure_dir_exists() { | |
local file_path="$1" | |
local target_user_id | |
local target_group_id | |
target_user_id=$(id -u "$TARGET_USER") | |
target_group_id=$(id -g "$TARGET_USER") | |
local dir | |
dir=$(dirname "$file_path") | |
# Check if directory exists, create if not | |
if [ ! -d "$dir" ]; then | |
echo "Creating directory: $dir" | |
# Create directory, attempting to set ownership if run as root for another user | |
mkdir -p "$dir" | |
if [[ $EUID -eq 0 ]] && [[ "$target_user_id" != "0" ]]; then | |
chown "$target_user_id:$target_group_id" "$dir" || echo "Warning: Could not chown directory $dir" | |
fi | |
fi | |
# Ensure the specific file can be written to by the target user | |
# Touch creates the file if it doesn't exist, updates timestamp if it does. | |
touch "$file_path" | |
# Set ownership of the file if run as root for another user | |
if [[ $EUID -eq 0 ]] && [[ "$target_user_id" != "0" ]]; then | |
chown "$target_user_id:$target_group_id" "$file_path" || echo "Warning: Could not chown file $file_path" | |
fi | |
} | |
# --- Main Script --- | |
echo "--- Starting Package List Update ---" | |
echo "Target User: $TARGET_USER" | |
echo "Target Home: $TARGET_HOME" | |
echo "APT list file: $APT_LIST_FILE" | |
echo "Flatpak list file: $FLATPAK_LIST_FILE" | |
# Ensure target directories exist and files are writable/owned correctly | |
ensure_dir_exists "$APT_LIST_FILE" | |
ensure_dir_exists "$FLATPAK_LIST_FILE" | |
# == Generate APT Package List == | |
echo "Generating list of manually installed APT packages..." | |
if command -v apt-mark >/dev/null 2>&1; then | |
# 'apt-mark showmanual' lists packages explicitly installed by the user (or marked as manual). | |
# This avoids listing dependencies, which apt will handle automatically on reinstall. | |
# Run apt-mark as the target user if possible, though it usually doesn't matter. | |
# If running as root for another user, just run apt-mark directly. | |
apt-mark showmanual > "$APT_LIST_FILE" | |
# Ensure file is owned by target user (redundant if ensure_dir_exists worked, but safe) | |
if [[ $EUID -eq 0 ]] && [[ "$(id -u "$TARGET_USER")" != "0" ]]; then | |
chown "$(id -u "$TARGET_USER"):$(id -g "$TARGET_USER")" "$APT_LIST_FILE" || echo "Warning: Could not chown $APT_LIST_FILE" | |
fi | |
echo "APT package list saved to $APT_LIST_FILE" | |
echo "APT packages found: $(wc -l < "$APT_LIST_FILE")" | |
else | |
echo "Warning: 'apt-mark' command not found. Is APT installed? Skipping APT package list." | |
# Create an empty file so the backup doesn't potentially fail on a missing file | |
> "$APT_LIST_FILE" | |
if [[ $EUID -eq 0 ]] && [[ "$(id -u "$TARGET_USER")" != "0" ]]; then | |
chown "$(id -u "$TARGET_USER"):$(id -g "$TARGET_USER")" "$APT_LIST_FILE" || echo "Warning: Could not chown $APT_LIST_FILE" | |
fi | |
fi | |
# == Generate Flatpak Package List == | |
echo "Generating list of installed Flatpak applications..." | |
if command -v flatpak >/dev/null 2>&1; then | |
# 'flatpak list --app --columns=application' lists only the application IDs. | |
# This ID is needed for reinstallation (e.g., flatpak install org.libreoffice.LibreOffice). | |
# This lists both --user and --system installations by default. | |
# If run as root, it primarily sees system installs unless run specifically for a user. | |
# Attempt to run as the target user if not root, or if specified via sudo. | |
if [[ $EUID -ne 0 ]] || [[ "$TARGET_USER" == "$(whoami)" ]]; then | |
# Run as current user (either non-root, or root running for root) | |
flatpak list --app --columns=application > "$FLATPAK_LIST_FILE" | |
else | |
# Run as root for a different target user - use sudo -u to list user's flatpaks | |
# This captures the user's installations. System ones might need separate handling if needed. | |
# Note: This assumes the root user has sudo privileges to switch to the target user. | |
sudo -u "$TARGET_USER" flatpak list --app --columns=application > "$FLATPAK_LIST_FILE" || { | |
echo "Warning: Failed to list Flatpaks as user '$TARGET_USER'. Listing system Flatpaks only." | |
flatpak list --app --columns=application > "$FLATPAK_LIST_FILE" | |
} | |
fi | |
# Ensure file ownership again | |
if [[ $EUID -eq 0 ]] && [[ "$(id -u "$TARGET_USER")" != "0" ]]; then | |
chown "$(id -u "$TARGET_USER"):$(id -g "$TARGET_USER")" "$FLATPAK_LIST_FILE" || echo "Warning: Could not chown $FLATPAK_LIST_FILE" | |
fi | |
echo "Flatpak list saved to $FLATPAK_LIST_FILE" | |
echo "Flatpak applications found: $(wc -l < "$FLATPAK_LIST_FILE")" | |
else | |
echo "Warning: 'flatpak' command not found. Skipping Flatpak list generation." | |
# Create an empty file | |
> "$FLATPAK_LIST_FILE" | |
if [[ $EUID -eq 0 ]] && [[ "$(id -u "$TARGET_USER")" != "0" ]]; then | |
chown "$(id -u "$TARGET_USER"):$(id -g "$TARGET_USER")" "$FLATPAK_LIST_FILE" || echo "Warning: Could not chown $FLATPAK_LIST_FILE" | |
fi | |
fi | |
echo "--- Package List Update Finished Successfully ---" | |
exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment