Files
shredos.x86_64/build_all_shredos.sh

646 lines
18 KiB
Bash
Raw Normal View History

#!/bin/bash
set -euo pipefail
################################################################################
# Usage: ./build_all_shredos.sh [x64|x32|all]
#
# Arguments:
# x64 - Build only x86-64 configurations
# x32 - Build only i686 (32-bit) configurations
# all - Build all configurations (64-bit first, then 32-bit)
#
# Environment Variables:
# DRY_RUN=0|1 - Output all commands that would be executed (default: 0)
# PRE_CLEAN=0|1 - Do an initial 'make clean' before starting (default: 1)
# QUICK_BUILD=0|1 - Do not full rebuild for same architecture (default: 0)
# FAST_FAIL=0|1 - Exit on first configuration build failure (default: 1)
# NEW_VERSION=STR - Set version string (default: prompts user)
#
# Examples:
# ./build_all_shredos.sh x64
# ./build_all_shredos.sh all
# QUICK_BUILD=1 ./build_all_shredos.sh x32
# NEW_VERSION="2024.11_27_x86-64_0.38" ./build_all_shredos.sh x64
################################################################################
# Location of the version file:
VERSION_FILE="board/shredos/fsoverlay/etc/shredos/version.txt"
# 64-bit configurations to build:
X64_CONFIGS=(
"shredos_defconfig"
"shredos_lite_defconfig"
"shredos_iso_extra_defconfig"
)
# 32-bit configurations to build:
X32_CONFIGS=(
"shredos_i686_lite_defconfig"
"shredos_iso_extra_i686_lite_defconfig"
)
# Packages always needing rebuild between runs, even for the same architecture.
# This only applies when QUICK_BUILD is enabled, otherwise rebuilds everything.
ALWAYS_REBUILD_PKGS=(
"grub2"
)
################################################################################
DRY_RUN="${DRY_RUN:-0}"
PRE_CLEAN="${PRE_CLEAN:-1}"
QUICK_BUILD="${QUICK_BUILD:-0}"
FAST_FAIL="${FAST_FAIL:-1}"
NEW_VERSION="${NEW_VERSION:-}"
X64_SUCCESS=0
X64_FAILED=0
X32_SUCCESS=0
X32_FAILED=0
GREEN="\033[0;32m"
YELLOW="\033[0;33m"
RED="\033[0;31m"
RESET="\033[0m"
FORCE_CLEAN=0
print_usage() {
echo
echo "Usage: $0 [x64|x32|all]"
echo ""
echo "Arguments:"
echo " x64 - Build only x86-64 configurations"
echo " x32 - Build only i686 (32-bit) configurations"
echo " all - Build all configurations (64-bit first, then 32-bit)"
echo ""
echo "Environment Variables:"
echo " DRY_RUN=0|1 - Output all commands that would be executed (default: 0)"
echo " PRE_CLEAN=0|1 - Do an initial 'make clean' before starting (default: 1)"
echo " QUICK_BUILD=0|1 - Do not full rebuild for same architecture (default: 0)"
echo " FAST_FAIL=0|1 - Exit on first failure (default: 1)"
echo " NEW_VERSION=STR - Set version string (default: prompts user)"
echo ""
echo "Examples:"
echo " $0 x64"
echo " $0 all"
echo " QUICK_BUILD=1 PRE_CLEAN=0 $0 x32"
echo
}
parse_arguments() {
if [ $# -eq 0 ]; then
printf "%b" "$RED"
echo "Error: Missing architecture argument"
printf "%b" "$RESET"
print_usage
exit 1
fi
BUILD_TARGET="$1"
case "$BUILD_TARGET" in
x64)
X32_CONFIGS=()
;;
x32)
X64_CONFIGS=()
;;
all)
;;
*)
printf "%b" "$RED"
echo "Error: Invalid architecture '$BUILD_TARGET'"
echo "Must be one of: x64, x32, all"
printf "%b" "$RESET"
print_usage
exit 1
;;
esac
}
prompt_version() {
local current_version=""
if [ -f "$VERSION_FILE" ]; then
current_version=$(cat "$VERSION_FILE")
else
printf "%b" "$RED"
echo
echo "==============================================="
echo "Version file not found: $VERSION_FILE"
echo "==============================================="
echo
printf "%b" "$RESET"
exit 1
fi
if [ -z "$NEW_VERSION" ]; then
echo
echo "x86-64 and i686 will be replaced/switched around during builds (depending on architecture)"
read -rp "Enter new version or press ENTER to keep existing [${current_version}]: " NEW_VERSION
[ -z "$NEW_VERSION" ] && NEW_VERSION="$current_version"
fi
run_cmd_change_version "$NEW_VERSION"
printf "%b" "$GREEN"
echo
echo "==============================================="
echo "Version updated to: $NEW_VERSION"
echo "==============================================="
echo
printf "%b" "$RESET"
}
display_build_plan() {
local total_configs=$((${#X64_CONFIGS[@]} + ${#X32_CONFIGS[@]}))
printf "%b" "$GREEN"
echo
echo "==============================================="
echo "PLANNING TO BUILD:"
echo "==============================================="
echo "Version: $NEW_VERSION"
echo "Dry-Run: $DRY_RUN"
echo "Pre-Clean: $PRE_CLEAN"
echo "Quick Build: $QUICK_BUILD"
echo "Fast Failure: $FAST_FAIL"
echo "Total Configurations: $total_configs"
echo "Building Architectures: $BUILD_TARGET"
echo "==============================================="
echo
printf "%b" "$RESET"
if [ ${#X64_CONFIGS[@]} -gt 0 ]; then
echo "64-bit configurations (${#X64_CONFIGS[@]}):"
for config in "${X64_CONFIGS[@]}"; do
echo " - $config"
done
echo
fi
if [ ${#X32_CONFIGS[@]} -gt 0 ]; then
echo "32-bit configurations (${#X32_CONFIGS[@]}):"
for config in "${X32_CONFIGS[@]}"; do
echo " - $config"
done
echo
fi
if [ ${#ALWAYS_REBUILD_PKGS[@]} -gt 0 ]; then
echo "Packages that will be re-built between same-architecture runs (${#ALWAYS_REBUILD_PKGS[@]}):"
for package in "${ALWAYS_REBUILD_PKGS[@]}"; do
echo " - $package"
done
echo
fi
printf "%b" "$GREEN"
echo "==============================================="
echo "Configurations to build can be amended inside the script."
echo "==============================================="
echo
printf "%b" "$RESET"
}
replace_version() {
local from=$1
local to=$2
if [ -f "$VERSION_FILE" ]; then
run_cmd sed -i "s@$from@$to@g" "$VERSION_FILE"
fi
}
run_cmd() {
local timestamp
timestamp=$(date '+%d.%m.%Y %H:%M:%S')
if [ "$DRY_RUN" -eq 1 ]; then
if [[ $* == make* ]]; then
printf "%b" "$YELLOW"
echo "[DRY_RUN] $*"
printf "%b" "$RESET"
else
echo "[DRY_RUN] $*"
fi
else
echo "[$timestamp] $*" >> "build_all_shredos.log"
"$@"
fi
}
run_cmd_tee() {
local timestamp
timestamp=$(date '+%d.%m.%Y %H:%M:%S')
local log_file="$1"
if [ "$DRY_RUN" -eq 1 ]; then
echo "[DRY_RUN] tee $log_file"
cat
else
echo "[$timestamp] tee $log_file" >> "build_all_shredos.log"
tee "$log_file"
fi
}
run_cmd_change_version() {
local timestamp
timestamp=$(date '+%d.%m.%Y %H:%M:%S')
local new_version="$1"
if [ "$DRY_RUN" -eq 1 ]; then
echo "[DRY_RUN] echo \"$new_version\" > \"$VERSION_FILE\""
else
echo "[$timestamp] echo \"$new_version\" > \"$VERSION_FILE\"" >> "build_all_shredos.log"
echo "$new_version" > "$VERSION_FILE"
fi
}
build_config() {
local index="$1"
local config="$2"
local arch="$3"
local log_file="dist/${config}.log"
printf "%b" "$YELLOW"
echo
echo "============================================"
echo "Started: '$config' ($arch)"
echo "============================================"
echo
printf "%b" "$RESET"
# Build | QuickBuild=1, PreClean=1 | QuickBuild=0, PreClean=1 | QuickBuild=1, PreClean=0 | QuickBuild=0, PreClean=0
# -------|---------------------------|---------------------------|---------------------------|---------------------------
# x64 #0 | clean* -> config -> make | clean* -> config -> make | config -> rebuild -> make | config -> rebuild -> make
# x64 #1 | config -> rebuild -> make | clean -> config -> make | config -> rebuild -> make | clean -> config -> make
# x64 #2+| config -> rebuild -> make | clean -> config -> make | config -> rebuild -> make | clean -> config -> make
# x32 #0 | clean -> config -> make | clean -> config -> make | clean -> config -> make | clean -> config -> make
# x32 #1+| config -> rebuild -> make | clean -> config -> make | config -> rebuild -> make | clean -> config -> make
# -------|---------------------------|---------------------------|---------------------------|---------------------------
# *: This clean is ensured in another part of the script before reaching this point.
if [ "$index" -ne 0 ] && [ "$QUICK_BUILD" -eq 1 ] && [ "$FORCE_CLEAN" -ne 1 ]; then
# If it's not the first configuration, and quick-build is enabled,
# and a clean is not otherwise forced, just rebuild necessary packages.
echo
echo "============================================"
echo "Loading configuration '$config' ($arch)..."
echo "============================================"
echo
if ! run_cmd make "$config"; then
build_config_failed "$config" "$arch" "$log_file"
return 1
fi
echo
echo "============================================"
echo "Rebuilding packages for '$config' ($arch)..."
echo "============================================"
echo
for pkg in "${ALWAYS_REBUILD_PKGS[@]}"; do
# Reconfigure starts one stage before rebuild, just to be safe.
# It is the earliest step after the source download and patching.
if ! run_cmd make "${pkg}-reconfigure"; then
build_config_failed "$config" "$arch" "$log_file"
return 1
fi
done
else
if [ "$index" -ne 0 ] || [ "$FORCE_CLEAN" -eq 1 ]; then
# If it's not the first configuration, or the clean was forced
# (due to architecture change), clean the building environment.
echo
echo "============================================"
echo "Running 'make clean' for '$config' ($arch)..."
echo "============================================"
echo
if ! run_cmd make clean; then
build_config_failed "$config" "$arch" "$log_file"
return 1
fi
fi
echo
echo "============================================"
echo "Loading configuration '$config' ($arch)..."
echo "============================================"
echo
if ! run_cmd make "$config"; then
build_config_failed "$config" "$arch" "$log_file"
return 1
fi
if [ "$index" -eq 0 ] && [ "$PRE_CLEAN" -eq 0 ] && [ "$FORCE_CLEAN" -ne 1 ]; then
# If it's the first configuration in a deliberately unclean environment,
# and clean was not otherwise forced, at least rebuild the necessary packages.
echo
echo "============================================"
echo "Rebuilding packages for '$config' ($arch)..."
echo "============================================"
echo
for pkg in "${ALWAYS_REBUILD_PKGS[@]}"; do
# Reconfigure starts one stage before rebuild, just to be safe.
# It is the earliest step after the source download and patching.
if ! run_cmd make "${pkg}-reconfigure"; then
build_config_failed "$config" "$arch" "$log_file"
return 1
fi
done
fi
fi
FORCE_CLEAN=0 # Reset previous dirty state
echo
echo "============================================"
echo "Building '$config' ($arch)..."
echo "============================================"
echo
if run_cmd make 2>&1 | run_cmd_tee "$log_file"; then
echo
echo "============================================"
echo "Finishing '$config' ($arch)..."
echo "============================================"
echo
build_config_success "$config" "$arch" "$log_file"
return 0
else
echo
echo "============================================"
echo "Finishing '$config' ($arch)..."
echo "============================================"
echo
build_config_failed "$config" "$arch" "$log_file"
return 1
fi
}
print_summary_and_exit() {
local return_code="$1"
local total_success=$((X64_SUCCESS + X32_SUCCESS))
local total_failed=$((X64_FAILED + X32_FAILED))
local total_builds=$((total_success + total_failed))
echo
echo "============================================"
echo "BUILD SUMMARY"
echo "============================================"
echo "64-bit builds: $X64_SUCCESS succeeded, $X64_FAILED failed"
echo "32-bit builds: $X32_SUCCESS succeeded, $X32_FAILED failed"
echo "--------------------------------------------"
echo "Total: $total_success succeeded, $total_failed failed (out of $total_builds)"
echo "--------------------------------------------"
echo "You will find all output files of the builds in the 'dist/' folder."
echo "Check 'build_all_shredos.log' for all the commands that were executed."
echo "============================================"
echo
if [ "$return_code" -ne 0 ]; then
exit "$return_code"
elif [ "$total_failed" -gt 0 ]; then
exit 1
else
exit 0
fi
}
build_config_success() {
local config="$1"
local arch="$2"
local log_file="$3"
if [ -f "$log_file" ]; then
run_cmd mv "$log_file" "dist/${config}-SUCCESS.log"
fi
rename_and_checksum_images "$config"
run_cmd mkdir -p "dist/$config"
run_cmd mv output/images/shredos*.iso "dist/$config/" 2>/dev/null || true
run_cmd mv output/images/shredos*.img "dist/$config/" 2>/dev/null || true
run_cmd mv output/images/shredos*.sha1 "dist/$config/" 2>/dev/null || true
printf "%b" "$GREEN"
echo
echo "==============================================="
echo "SUCCESS: '$config' ($arch)"
echo "==============================================="
echo
printf "%b" "$RESET"
if [ "$arch" = "x64" ]; then
((X64_SUCCESS++))
else
((X32_SUCCESS++))
fi
}
build_config_failed() {
local config="$1"
local arch="$2"
local log_file="$3"
if [ -f "$log_file" ]; then
run_cmd mv "$log_file" "dist/${config}-FAILED.log"
fi
printf "%b" "$RED"
echo
echo "==============================================="
echo "FAILURE: '$config' ($arch)"
echo "==============================================="
echo
printf "%b" "$RESET"
if [ "$arch" = "x64" ]; then
((X64_FAILED++))
else
((X32_FAILED++))
fi
if [ "$FAST_FAIL" -eq 1 ]; then
printf "%b" "$RED"
echo
echo "==============================================="
echo "Fast Failure Mode is enabled - not proceeding..."
echo "==============================================="
echo
printf "%b" "$RESET"
exit 1
fi
}
# Function to handle suffix insertion before the extension
insert_suffix() {
local fname="$1"
local suffix="$2"
local base="${fname%.*}"
local ext="${fname##*.}"
echo "${base}${suffix}.${ext}"
}
rename_and_checksum_images() {
local config="$1"
target_dir="output/images"
# If the defconfig contains the string `lite`, i.e a reduced size
# so it will boot on systems with only 512MB of RAM then insert
# into the .iso or .img filename the string _lite prior to the extension.
if [[ "$config" == *"lite"* ]]; then
shopt -s nullglob
for file in "$target_dir"/shredos*.{iso,img}; do
filename=$(basename "$file")
if [[ "$filename" != *"_lite"* ]]; then
new_name=$(insert_suffix "$filename" "_lite")
mv -v "$file" "$target_dir/$new_name"
fi
done
shopt -u nullglob
else
echo "Condition not met: 'lite' not in $config, rename not necessary."
fi
# If the defconfig contains the string `extra`, i.e an extra partition
# then insert into the .iso or .img filename the string _plus-partition
if [[ "$config" == *"extra"* ]]; then
shopt -s nullglob
for file in "$target_dir"/shredos*.{iso,img}; do
filename=$(basename "$file")
if [[ "$filename" != *"_plus-partition"* ]]; then
new_name=$(insert_suffix "$filename" "_plus-partition")
mv -v "$file" "$target_dir/$new_name"
fi
done
shopt -u nullglob
else
echo "Condition not met: 'extra' not in $config, rename not necessary."
fi
# Clean up orphaned .sha1 files (that don't match any existing image)
echo "Cleaning up orphaned .sha1 files..."
shopt -s nullglob
for sha_file in "$target_dir"/shredos*.sha1; do
# Strip .sha1 to find the base image name
corresponding_image="${sha_file%.sha1}"
if [[ ! -f "$corresponding_image" ]]; then
rm -v "$sha_file"
fi
done
shopt -u nullglob
# Calculate SHA1 for all final files
echo "Calculating SHA1 checksums..."
current_dir=$(pwd)
cd "$target_dir" || exit
shopt -s nullglob
for file in shredos*.{iso,img}; do
sha1sum "$file" > "$file.sha1"
done
shopt -u nullglob
cd $current_dir || exit
echo "[DONE]"
}
################################################################################
if [ -f "build_all_shredos.log" ]; then
rm build_all_shredos.log
fi
parse_arguments "$@"
prompt_version
display_build_plan
if [ "$DRY_RUN" -eq 1 ]; then
printf "%b" "$YELLOW"
echo
echo "==============================================="
echo "DRY RUN - NO ACTUAL CHANGES WILL BE MADE"
echo "DISREGARD WARNINGS ABOUT 'MAKE CLEAN' ETC..."
echo "==============================================="
echo
printf "%b" "$RESET"
fi
if [ "$PRE_CLEAN" -eq 1 ]; then
printf "%b" "$RED"
echo
echo "==============================================="
echo "Beware - WILL run a MAKE CLEAN before starting building!"
echo "Press ENTER in the next 10 seconds to skip this step..."
echo "or otherwise (if you want to MAKE CLEAN) - just wait..."
echo "==============================================="
echo
printf "%b" "$RESET"
if read -rt 10; then
PRE_CLEAN=0
echo "Skipped cleaning the building stage (no 'make clean')..."
fi
fi
printf "%b" "$YELLOW"
echo
echo "==============================================="
echo "Starting build in 10 seconds... (press CTRL+C to cancel)"
if [ "$PRE_CLEAN" -eq 1 ]; then
printf "%b" "$RESET"
printf "%b" "$RED"
echo "Beware - WILL run a MAKE CLEAN before starting building!"
printf "%b" "$RESET"
printf "%b" "$YELLOW"
fi
echo "==============================================="
echo
printf "%b" "$RESET"
sleep 10
if [ "$PRE_CLEAN" -eq 1 ]; then
echo "Running 'make clean' on the building environment..."
run_cmd make clean
fi
echo "Removing and recreating 'dist/' folder (if it exists)..."
run_cmd rm -r dist || true
run_cmd mkdir -p dist
echo "Starting to build..."
trap 'print_summary_and_exit $?' EXIT INT TERM
if [ ${#X64_CONFIGS[@]} -gt 0 ]; then
echo
echo "==============================================="
echo "Starting 64-bit builds..."
echo "==============================================="
echo
replace_version "i686" "x86-64"
CFG_INDEX=0
for config in "${X64_CONFIGS[@]}"; do
build_config "$CFG_INDEX" "$config" "x64" || true
((++CFG_INDEX))
done
fi
if [ ${#X32_CONFIGS[@]} -gt 0 ]; then
if [ ${#X64_CONFIGS[@]} -gt 0 ]; then
run_cmd make clean
FORCE_CLEAN=1 # Need this for architecture change
fi
echo
echo "==============================================="
echo "Starting 32-bit builds..."
echo "==============================================="
echo
replace_version "x86-64" "i686"
CFG_INDEX=0
for config in "${X32_CONFIGS[@]}"; do
build_config "$CFG_INDEX" "$config" "x32" || true
((++CFG_INDEX))
done
fi