Compare commits

..

1 Commits

Author SHA1 Message Date
251b54937b Use --detached worktrees 2025-08-05 14:13:27 -04:00
3 changed files with 177 additions and 316 deletions

View File

@@ -12,12 +12,10 @@ Build and deploy OpenWRT images using shell-style device profiles, via source co
--profile,-p PROFILE --profile,-p PROFILE
--release,-r,--version,-v RELEASE ("snapshot", "22.03.3") --release,-r,--version,-v RELEASE ("snapshot", "22.03.3")
--buildroot,-b PATH (Default: script directory) --buildroot,-b PATH (Default: script directory)
--cpus,-c NUM --source
Default: # of host CPUS minus 1 Build image from source code, not from Image Builder
--mode,-m imagebuilder|source Allows make config options to be passed in profile
Default: imagebuilder Uses git worktree for multi-profile deduplication
--clean clean|targetclean|dirclean|distclean
Optional clean step for source mode
--ssh-upgrade HOST --ssh-upgrade HOST
Example: root@192.168.1.1 Example: root@192.168.1.1
--ssh-backup SSH_PATH --ssh-backup SSH_PATH
@@ -39,13 +37,13 @@ Build and deploy OpenWRT images using shell-style device profiles, via source co
See `profiles` for example device profile definitions. Multiple `--profile` can be passed at once. See `profiles` for example device profile definitions. Multiple `--profile` can be passed at once.
The default build mode is `imagebuilder` unless `--mode=source` is passed. Default profile modes can be set individually in `profiles`. The default build mode is `imagebuilder` unless `--source` is passed. Default profile modes can be set individually in `profiles`.
## Examples ## Examples
* `openwrtbuilder -p r4s -p ax6000` * `openwrtbuilder -p r4s -p ax6000`
* `openwrtbuilder -p r4s -r snapshot --debug` * `openwrtbuilder -p r4s -r snapshot --debug`
* `openwrtbuilder -p ax6000 -r 23.05.5 --mode source --debug` * `openwrtbuilder -p ax6000 -r 23.05.5 --source --debug`
* `openwrtbuilder -p rpi4 -r 23.05.5 --flash /dev/sdX` * `openwrtbuilder -p rpi4 -r 23.05.5 --flash /dev/sdX`
* `openwrtbuilder -p linksys -r snapshot --ssh-upgrade root@192.168.1.1` * `openwrtbuilder -p linksys -r snapshot --ssh-upgrade root@192.168.1.1`

View File

@@ -1,11 +1,10 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Build and deploy OpenWRT images using shell-style device profiles, via source code or the official Image Builder. # Build and deploy OpenWRT images using shell-style device profiles, via source code or the official Image Builder.# Copyright 2022-25 Bryan C. Roessler
# Copyright 2022-25 Bryan C. Roessler
# Apache 2.0 License # Apache 2.0 License
# See README and ./profiles for device configuration # See README and profiles for device configuration
# Set default release # Set default release
: "${DEFAULT_RELEASE:=${RELEASE:="24.10.5"}}" : "${RELEASE:="24.10.2"}"
# @internal # @internal
print_help() { print_help() {
@@ -19,26 +18,25 @@ print_help() {
OPTIONS OPTIONS
--profile,-p PROFILE --profile,-p PROFILE
--release,-r,--version,-v RELEASE ("snapshot", "24.10.5") --release,-r,--version,-v RELEASE ("snapshot", "22.03.5")
Default: From profile or hardcoded RELEASE
--buildroot,-b PATH --buildroot,-b PATH
Default: location of openwrtbuilder script Default: location of openwrtbuilder script
--cpus,-c NUM --source
Default: # of host CPUS minus 1 Build image from source, not from Image Builder
--mode,-m imagebuilder|source Allows make config options to be passed in profile
Default: imagebuilder Uses git worktree for multi-profile deduplication
--clean clean|targetclean|dirclean|distclean
Optional clean step for source mode
--ssh-upgrade HOST --ssh-upgrade HOST
Examples: root@192.168.1.1, root@router.lan Examples: root@192.168.1.1, root@router.lan
--ssh-backup SSH_PATH --ssh-backup SSH_PATH
Enabled by default for --ssh-upgrade Enabled by default for --ssh-upgrade
--flash,-f DEVICE --flash,-f DEVICE
Example: /dev/sdX Example: /dev/sdX
--reset
Cleanup all source and output files
--depends --depends
Force dependency installation Force dependency installation
--yes,-y --yes,-y
Assume yes for all questions (non-interactive) Assume yes for all questions (automatic mode)
--debug,-d --debug,-d
--help,-h --help,-h
@@ -59,7 +57,7 @@ init() {
# Save the script directory # Save the script directory
# https://stackoverflow.com/a/4774063 # https://stackoverflow.com/a/4774063
SCRIPT_DIR=$(readlink -f "$(dirname "${BASH_SOURCE[0]}")") SCRIPT_DIR="$(cd -- "$(dirname "$0")" >/dev/null 2>&1 || exit $? ; pwd -P)"
if [[ -e "/etc/os-release" ]]; then if [[ -e "/etc/os-release" ]]; then
source "/etc/os-release" source "/etc/os-release"
@@ -127,21 +125,19 @@ init() {
parse_input() { parse_input() {
debug "${FUNCNAME[0]}" "$*" debug "${FUNCNAME[0]}" "$*"
declare -ga PROFILES declare -ga PROFILES
declare -gi RESET=0 YES=0 DEBUG=0 FORCE_DEPENDS=0 CPUS=0 declare -gi RESET=0 FROM_SOURCE=0 YES=0 DEBUG=0 FORCE_DEPENDS=0
declare -g USER_RELEASE SSH_UPGRADE_PATH SSH_BACKUP_PATH FLASH_DEV USER_MODE USER_CLEAN declare -g USER_RELEASE SSH_UPGRADE_PATH SSH_BACKUP_PATH FLASH_DEV
local long_opts='release:,version:,profile:,buildroot:,cpus:,mode:,clean:' local long_opts='release:,version:,profile:,buildroot:,source,'
long_opts+='ssh-upgrade:,ssh-backup:,flash:,reset,depends,yes,debug,help' long_opts+='ssh-upgrade:,ssh-backup:,flash:,reset,depends,yes,debug,help'
if _input=$(getopt -o +r:v:p:b:m:c:f:ydh -l $long_opts -- "$@"); then if _input=$(getopt -o +r:v:p:b:sf:ydh -l $long_opts -- "$@"); then
eval set -- "$_input" eval set -- "$_input"
while true; do while true; do
case "$1" in case "$1" in
--release|-r|--version|-v) shift; USER_RELEASE="$1" ;; --release|-r|--version|-v) shift; USER_RELEASE="$1" ;;
--profile|-p) shift; PROFILES+=("$1") ;; --profile|-p) shift; PROFILES+=("$1") ;;
--buildroot|-b) shift; BUILD_ROOT="$1" ;; --buildroot|-b) shift; BUILD_ROOT="$1" ;;
--mode|-m) shift; USER_MODE="$1" ;; --source|-s) FROM_SOURCE=1 ;;
--clean) shift; USER_CLEAN="$1" ;;
--cpus|-c) shift; CPUS="$1" ;;
--ssh-upgrade) shift; SSH_UPGRADE_PATH="$1" ;; --ssh-upgrade) shift; SSH_UPGRADE_PATH="$1" ;;
--ssh-backup) shift; SSH_BACKUP_PATH="$1" ;; --ssh-backup) shift; SSH_BACKUP_PATH="$1" ;;
--flash|-f) shift; FLASH_DEV="$1" ;; --flash|-f) shift; FLASH_DEV="$1" ;;
@@ -172,10 +168,10 @@ install_dependencies() {
if [[ "$mode" == "source" ]]; then if [[ "$mode" == "source" ]]; then
lock_file="$BUILD_ROOT/.dependencies_source.lock" lock_file="$BUILD_ROOT/.dependencies_source.lock"
elif [[ "$mode" == "imagebuilder" ]]; then elif [[ "$mode" == "imagebuilder" ]]; then
lock_file="$BUILD_ROOT/.dependencies_imagebuilder.lock" lock_file="$BUILD_ROOT/.dependencies_ib.lock"
fi fi
[[ -f $lock_file ]] && debug "$lock_file lock file exists but skipping for --debug" && return 0 [[ -f $lock_file ]] && debug "$lock_file lock file exists" && return 0
if [[ "$mode" == "source" ]]; then if [[ "$mode" == "source" ]]; then
# For building from source code see: # For building from source code see:
@@ -189,7 +185,6 @@ install_dependencies() {
gcc gcc
gcc-c++ gcc-c++
git git
golang
llvm15-libs # for qosify llvm15-libs # for qosify
make make
ncurses-devel ncurses-devel
@@ -208,7 +203,6 @@ install_dependencies() {
python3-devel python3-devel
python3-pyelftools python3-pyelftools
python3-setuptools python3-setuptools
quilt
rsync rsync
swig swig
tar tar
@@ -227,12 +221,10 @@ install_dependencies() {
gcc-multilib gcc-multilib
gettext gettext
git git
golang
liblzma-dev liblzma-dev
libncurses5-dev libncurses5-dev
libssl-dev libssl-dev
python3-distutils python3-distutils
quilt
rsync rsync
patch patch
unzip unzip
@@ -257,7 +249,6 @@ install_dependencies() {
gcc gcc
gettext gettext
git git
golang
grep grep
groff groff
gzip gzip
@@ -272,7 +263,6 @@ install_dependencies() {
patch patch
pkgconf pkgconf
python python
quilt
rsync rsync
sed sed
texinfo texinfo
@@ -441,7 +431,7 @@ make_images() {
debug make "${make_opts[@]}" image BIN_DIR="$BIN_DIR" \ debug make "${make_opts[@]}" image BIN_DIR="$BIN_DIR" \
PROFILE="$DEVICE" PACKAGES="$PACKAGES" \ PROFILE="$DEVICE" PACKAGES="$PACKAGES" \
FILES="$FILES_DIR" --directory="$BUILD_DIR" \ FILES="$FILES_DIR" --directory="$BUILD_DIR" \
--jobs="$JOBS" --jobs="$(($(nproc) - 1))"
make "${make_opts[@]}" image \ make "${make_opts[@]}" image \
BIN_DIR="$BIN_DIR" \ BIN_DIR="$BIN_DIR" \
@@ -449,7 +439,7 @@ make_images() {
PACKAGES="$PACKAGES" \ PACKAGES="$PACKAGES" \
FILES="$FILES_DIR" \ FILES="$FILES_DIR" \
--directory="$BUILD_DIR" \ --directory="$BUILD_DIR" \
--jobs="$JOBS" \ --jobs="$(($(nproc) - 1))" \
> "$BUILD_DIR/make.log" > "$BUILD_DIR/make.log"
} }
@@ -505,35 +495,23 @@ ssh_upgrade() {
# @description Builds OpenWRT from source code using the the default buildbot as base # @description Builds OpenWRT from source code using the the default buildbot as base
# This enables the use of kernel config options in profiles # This enables the use of kernel config options in profiles
# @arg $1 string .config seed URL
# @arg $2 string Profile name
# @arg $3 string Worktree ref (commit-ish or branch name)
from_source() { from_source() {
debug "${FUNCNAME[0]}" debug "${FUNCNAME[0]}" "$*"
local seed_url="$1"
local profile="$2"
local ref="$3"
local src_url="https://github.com/openwrt/openwrt.git" local src_url="https://github.com/openwrt/openwrt.git"
local seed_file="$BUILD_DIR/.config" local seed_file="$BUILD_DIR/.config"
local worktree_meta="$SRC_DIR/.git/worktrees/source-$REF" local worktree_meta="$SRC_DIR/.git/worktrees/source-$ref"
local pkg config commit description local pkg config commit seed_file description
local -a make_opts local -a make_opts config_opts
local -a config_opts=(
"CONFIG_TARGET_${TARGET%%/*}=y"
"CONFIG_TARGET_${TARGET//\//_}=y"
"CONFIG_TARGET_PROFILE=DEVICE_$DEVICE"
"CONFIG_TARGET_${TARGET//\//_}_DEVICE_$DEVICE=y"
"CONFIG_TARGET_ROOTFS_${FILESYSTEM^^}=y"
"CONFIG_TARGET_MULTI_PROFILE=n"
"CONFIG_BUILDBOT=n"
"CONFIG_ALL_KMODS=n"
"CONFIG_ALL_NONSHARED=n"
"CONFIG_DEVEL=n"
"CONFIG_COLLECT_KERNEL_DEBUG=n"
"CONFIG_SDK=n"
"CONFIG_SDK_LLVM_BPF=n"
"CONFIG_IB=n"
"CONFIG_MAKE_TOOLCHAIN=n"
"CONFIG_TARGET_PER_DEVICE_ROOTFS=n"
)
echo "Building from source is under development" echo "Building from source is under development"
# Remove all build directories and worktrees if --reset # Remove all build directories and worktrees
if ((RESET)); then if ((RESET)); then
if [[ -d "$BUILD_DIR" || -d "$worktree_meta" ]]; then if [[ -d "$BUILD_DIR" || -d "$worktree_meta" ]]; then
execute git -C "$SRC_DIR" worktree remove --force --force "$BUILD_DIR" execute git -C "$SRC_DIR" worktree remove --force --force "$BUILD_DIR"
@@ -543,101 +521,24 @@ from_source() {
[[ -d "$BUILD_DIR" ]] && execute rm -rf "$BUILD_DIR" [[ -d "$BUILD_DIR" ]] && execute rm -rf "$BUILD_DIR"
fi fi
# Fetch or clone source repo (no local merges) # Pull or clone source repo
if [[ -d "$SRC_DIR" ]]; then if [[ -d "$SRC_DIR" ]]; then
execute git -C "$SRC_DIR" fetch origin --tags --prune execute git -C "$SRC_DIR" pull
else else
execute mkdir -p "$SRC_DIR" execute mkdir -p "$SRC_DIR"
execute git clone "$src_url" "$SRC_DIR" execute git clone "$src_url" "$SRC_DIR"
fi fi
# Reuse worktree if present; otherwise create it (support branches and tags) # Remove existing build dir and add new worktree
if git -C "$BUILD_DIR" rev-parse --is-inside-work-tree >/dev/null 2>&1; then if [[ -d "$BUILD_DIR" ]]; then
execute git -C "$BUILD_DIR" fetch origin --tags --prune execute rm -rf "$BUILD_DIR"
execute git -C "$BUILD_DIR" reset --hard "origin/$REF" || \ fi
execute git -C "$BUILD_DIR" reset --hard "$REF" || \
execute git -C "$BUILD_DIR" checkout --detach "$REF"
else
execute git -C "$SRC_DIR" worktree prune --verbose execute git -C "$SRC_DIR" worktree prune --verbose
# Prefer local tag/branch if present, otherwise use remote-tracking branch execute git -C "$SRC_DIR" worktree add --detached "$BUILD_DIR" "$ref"
if ! execute git -C "$SRC_DIR" worktree add --detach "$BUILD_DIR" "$REF"; then
execute git -C "$SRC_DIR" worktree add --detach "$BUILD_DIR" "origin/$REF"
fi
fi
# Add cherrypicks
for cherrypick in $CHERRYPICKS; do
url_branch="${cherrypick%:*}"
commit="${cherrypick##*:}"
branch=""
url="$url_branch"
if [[ "$url_branch" == *"@"* ]]; then
url="${url_branch%@*}"
branch="${url_branch#*@}"
fi
remote="${url%.git}"
remote="${remote##*/}"
remote=${remote//[^A-Za-z0-9._-]/_}
[[ -z $remote ]] && remote="cherry"
if ! git -C "$BUILD_DIR" remote | grep -q "^$remote$"; then
execute git -C "$BUILD_DIR" remote add "$remote" "$url"
else
execute git -C "$BUILD_DIR" remote set-url "$remote" "$url"
fi
if [[ -n $branch ]]; then
execute git -C "$BUILD_DIR" fetch "$remote" "$branch"
else
execute git -C "$BUILD_DIR" fetch "$remote"
fi
# Verify commit exists before attempting cherry-pick
if ! git -C "$BUILD_DIR" cat-file -e "$commit^{commit}" 2>/dev/null; then
debug "Commit $commit not found after fetching from $remote; skipping"
continue
fi
execute git -C "$BUILD_DIR" merge-base --is-ancestor "$commit" HEAD ||
execute git -C "$BUILD_DIR" cherry-pick "$commit"
done
# Merge entire branches
for branch in $BRANCHES; do
url_branch="$branch"
branch=""
url="$url_branch"
if [[ "$url_branch" == *"@"* ]]; then
url="${url_branch%@*}"
branch="${url_branch#*@}"
fi
remote="${url%.git}"
remote="${remote##*/}"
remote=${remote//[^A-Za-z0-9._-]/_}
[[ -z $remote ]] && remote="merge"
if ! git -C "$BUILD_DIR" remote | grep -q "^$remote$"; then
execute git -C "$BUILD_DIR" remote add "$remote" "$url"
else
execute git -C "$BUILD_DIR" remote set-url "$remote" "$url"
fi
if [[ -n $branch ]]; then
execute git -C "$BUILD_DIR" fetch "$remote" "$branch"
echo "Merging $remote/$branch into $(git -C "$BUILD_DIR" rev-parse --abbrev-ref HEAD)"
execute git -C "$BUILD_DIR" merge --allow-unrelated-histories -m "Merge $remote/$branch" "$remote/$branch" || \
{ debug "Merge conflict or failed for $remote/$branch"; return 1; }
else
debug "Cannot merge: no branch specified in entry '$branch'"
continue
fi
done
# Print commit info # Print commit info
commit=$(git -C "$BUILD_DIR" rev-parse HEAD) commit=$(git -C "$BUILD_DIR" rev-parse HEAD)
description=$(git -C "$BUILD_DIR" describe --always --dirty) description=$(git -C "$BUILD_DIR" describe)
echo "Current commit hash: $commit" echo "Current commit hash: $commit"
echo "Git worktree description: $description" echo "Git worktree description: $description"
@@ -649,24 +550,29 @@ from_source() {
# Begin OpenWRT build process # Begin OpenWRT build process
((DEBUG)) && make_opts+=("V=sc") ((DEBUG)) && make_opts+=("V=sc")
# Cleanup build environment: heavy clean only when --reset was used earlier # Cleanup build environment
execute make "${make_opts[@]}" "-j1" distclean
# make clean # compiled output # make clean # compiled output
# make targetclean # compiled output, toolchain # make targetclean # compiled output, toolchain
# make dirclean # compiled output, toolchain, build tools # make dirclean # compiled output, toolchain, build tools
# make distclean # compiled output, toolchain, build tools, .config, feeds, .ccache # make distclean # compiled output, toolchain, build tools, .config, feeds, .ccache
if [[ -n $CLEAN ]]; then
execute make "${make_opts[@]}" "-j1" "$CLEAN"
else
debug "Skipping cleanup step"
fi
# Use a custom (faster) mirror # Use a custom (faster) mirror
execute sed -i -E 's;git.openwrt.org/(feed|project);github.com/openwrt;' feeds.conf.default # execute sed -i -E 's;git.openwrt.org/(feed|project);github.com/openwrt;' feeds.conf.default
# Update package feed # Update package feed
./scripts/feeds update -a -f && ./scripts/feeds update -a -f &&
./scripts/feeds install -a -f ./scripts/feeds install -a -f
# Grab the release seed config
if ! execute "$DL_TOOL" "-o" "$seed_file" "$seed_url"; then
echo "Could not obtain $seed_file from $seed_url"
return 1
fi
# Set compilation output dir
config_opts+=("CONFIG_BINARY_FOLDER=\"$BIN_DIR\"")
# Add custom packages # Add custom packages
for pkg in $PACKAGES; do for pkg in $PACKAGES; do
if [[ $pkg == -* ]]; then if [[ $pkg == -* ]]; then
@@ -676,37 +582,54 @@ from_source() {
fi fi
done done
# Add profile config options # Add config options from profile
for config in $CONFIGS; do for config in ${P_ARR[config]}; do
config_opts+=("$config") config_opts+=("$config")
done done
# Reset and write options to config seed file # Only compile selected fs
[[ -f $seed_file ]] && execute rm -f "$seed_file" execute sed -i '/CONFIG_TARGET_ROOTFS_/d' "$seed_file"
config_opts+=("CONFIG_TARGET_PER_DEVICE_ROOTFS=n")
if [[ $FILESYSTEM == "squashfs" ]]; then
config_opts+=("CONFIG_TARGET_ROOTFS_EXT4FS=n")
config_opts+=("CONFIG_TARGET_ROOTFS_SQUASHFS=y")
elif [[ $FILESYSTEM == "ext4" ]]; then
config_opts+=("CONFIG_TARGET_ROOTFS_SQUASHFS=n")
config_opts+=("CONFIG_TARGET_ROOTFS_EXT4FS=y")
fi
# Only compile selected target image
execute sed -i '/CONFIG_TARGET_DEVICE_/d' "$seed_file"
config_opts+=("CONFIG_TARGET_MULTI_PROFILE=n")
config_opts+=("CONFIG_TARGET_PROFILE=DEVICE_$DEVICE")
config_opts+=("CONFIG_TARGET_${TARGET//\//_}_DEVICE_$DEVICE=y")
config_opts+=("CONFIG_SDK=n")
config_opts+=("CONFIG_SDK_LLVM_BPF=n")
config_opts+=("CONFIG_IB=n")
config_opts+=("CONFIG_MAKE_TOOLCHAIN=n")
# Write options to config seed file
for config in "${config_opts[@]}"; do for config in "${config_opts[@]}"; do
debug "Writing $config to $seed_file" debug "Writing $config to $seed_file"
echo "$config" >> "$seed_file" echo "$config" >> "$seed_file"
done done
# Expand seed into full config # Serial make prep is more reliable
execute make "${make_opts[@]}" "-j1" defconfig execute make "${make_opts[@]}" "-j1" defconfig
# Run serial make download for better reliability
execute make "${make_opts[@]}" "-j1" download execute make "${make_opts[@]}" "-j1" download
# (Optional) Disable multicore make world # make_opts+=("-j$(($(nproc)-1))")
# ((DEBUG)) && make_opts+=("-j1") || make_opts+=("-j$JOBS)") ((DEBUG)) && make_opts+=("-j1") || make_opts+=("-j$(($(nproc)-1))")
make_opts+=("-j$JOBS")
# Make image # Make image
if ! execute ionice -c2 -n7 nice -n19 make "${make_opts[@]}" BIN_DIR="$BIN_DIR" world; then if ! execute ionice -c 3 chrt --idle 0 nice -n19 make "${make_opts[@]}" world; then
echo "Error: make failed" echo "Error: make failed"
return 1 return 1
fi fi
execute popd || return 1 execute popd || return 1
# Symlink output images to root of BIN_DIR (match Image Builder behavior) # Symlink output images to root of BIN_DIR (match Image Builder)
shopt -s nullglob shopt -s nullglob
for image in "$BIN_DIR/targets/${TARGET}/"*.{img,img.gz,ubi}; do for image in "$BIN_DIR/targets/${TARGET}/"*.{img,img.gz,ubi}; do
execute ln -fs "$image" "$BIN_DIR/${image##*/}" execute ln -fs "$image" "$BIN_DIR/${image##*/}"
@@ -716,6 +639,32 @@ from_source() {
return 0 return 0
} }
# @description Backs up a file to a chosen directory using its timestamp
# @arg $1 string File to backup
# @arg $2 string Directory to backup to
backup() {
debug "${FUNCNAME[0]}" "$*"
local file="$1" dir="$2"
local creation_date base_name backup_file
[[ -f $file ]] || return 1
[[ -d $dir ]] || execute mkdir -p "$dir" || { debug "Failed to create directory: $dir"; return 1; }
if creation_date=$(stat -c %w "$file" 2>/dev/null || stat -c %y "$file" 2>/dev/null) && \
[[ $creation_date != "-" && -n $creation_date ]] && \
creation_date=$(date -d "$creation_date" +%y%m%d%H%M 2>/dev/null); then
debug "Creation date: $creation_date"
else
creation_date="unknown"
debug "Unable to determine creation date, using 'unknown'"
fi
base_name="${file##*/}"
backup_file="$dir/$creation_date-$base_name"
[[ -f $backup_file ]] || execute cp --archive "$file" "$backup_file"
}
# @section Helper functions # @section Helper functions
# @internal # @internal
debug() { ((DEBUG)) && echo "Debug: $*"; } debug() { ((DEBUG)) && echo "Debug: $*"; }
@@ -790,92 +739,73 @@ main() {
# Remove dependency lock files for --depends # Remove dependency lock files for --depends
if ((FORCE_DEPENDS)); then if ((FORCE_DEPENDS)); then
[[ -f "$BUILD_ROOT/.dependencies_source.lock" ]] && rm -f "$BUILD_ROOT/.dependencies_source.lock" [[ -f "$BUILD_ROOT/.dependencies_source.lock" ]] && rm -f "$BUILD_ROOT/.dependencies_source.lock"
[[ -f "$BUILD_ROOT/.dependencies_imagebuilder.lock" ]] && rm -f "$BUILD_ROOT/.dependencies_imagebuilder.lock" [[ -f "$BUILD_ROOT/.dependencies_ib.lock" ]] && rm -f "$BUILD_ROOT/.dependencies_ib.lock"
fi fi
# Run selected profiles # Run selected profiles
for PROFILE in "${PROFILES[@]}"; do for profile in "${PROFILES[@]}"; do
debug "Running profile: $PROFILE" debug "Running profile: $profile"
if [[ ! ${!PROFILE@a} = A ]]; then if [[ ! ${!profile@a} = A ]]; then
echo "Profile '$PROFILE' does not exist" echo "Profile '$profile' does not exist"
return 1 return 1
fi fi
# Store profile in P_ARR nameref and set global profile vars # Store profile in P_ARR nameref
local -n P_ARR="$PROFILE" local -n P_ARR="$profile"
declare -g REPO="${P_ARR[repo]:-}" local mode="${P_ARR[mode]:="imagebuilder"}"
((FROM_SOURCE)) && mode="source" # allow cli override
install_dependencies "$mode"
local repo="${P_ARR[repo]:-}"
declare -g FILESYSTEM="${P_ARR[filesystem]:="squashfs"}" declare -g FILESYSTEM="${P_ARR[filesystem]:="squashfs"}"
declare -g TARGET="${P_ARR[target]}" declare -g TARGET="${P_ARR[target]}"
declare -g DEVICE="${P_ARR[device]}" declare -g DEVICE="${P_ARR[device]}"
declare -g MODE="${USER_MODE:-${P_ARR[mode]:-imagebuilder}}" declare -g PACKAGES="${P_ARR[packages]:-}"
declare -g CLEAN="${USER_CLEAN:-${P_ARR[clean]:-}}"
declare -g PACKAGES="${P_ARR[packages]:-}" # scalar
declare -g CHERRYPICKS="${P_ARR[cherrypicks]:-}" # scalar
declare -g BRANCHES="${P_ARR[branches]:-}" # scalar
declare -g CONFIGS="${P_ARR[configs]:-}" # scalar
install_dependencies "$MODE" # pull in USER_RELEASE from args or profile default
local raw_release="${USER_RELEASE:=${P_ARR[release]:=$RELEASE}}"
# Set number of parallel jobs for make and imagebuilder # single call to normalize+ref
declare -gi JOBS read -r release ref < <(normalize_and_ref "$raw_release" "$mode")
if ((CPUS)); then
JOBS="$CPUS" # user overide (--cpus)
else
JOBS=$(nproc || echo 4) # fallback to quad-core if nproc fails
((JOBS > 1)) && JOBS=$((JOBS - 1)) # leave one CPU free
fi
# Normalize RELEASE and set REF committish
local raw_release="${USER_RELEASE:=${P_ARR[release]:=$DEFAULT_RELEASE}}"
declare -g RELEASE REF
read -r RELEASE REF < <(normalize_and_ref "$raw_release" "$MODE")
declare -g SRC_DIR="$BUILD_ROOT/src/.openwrt" declare -g SRC_DIR="$BUILD_ROOT/src/.openwrt"
declare -g BUILD_DIR="$BUILD_ROOT/src/$PROFILE/$REF-$MODE" declare -g BUILD_DIR="$BUILD_ROOT/src/$profile/$mode-$ref"
declare -g BIN_DIR="$BUILD_ROOT/bin/$PROFILE/$REF-$MODE" declare -g BIN_DIR="$BUILD_ROOT/bin/$profile/$mode-$ref"
if [[ "$RELEASE" == "snapshot" ]]; then if [[ "$release" == "snapshot" ]]; then
local url_prefix="https://downloads.openwrt.org/snapshots/targets/$TARGET" local url_prefix="https://downloads.openwrt.org/snapshots/targets/$TARGET"
local url_filename="openwrt-imagebuilder-${TARGET//\//-}.Linux-x86_64.tar.zst" local url_filename="openwrt-imagebuilder-${TARGET//\//-}.Linux-x86_64.tar.zst"
local img_fname="openwrt-${TARGET//\//-}-$DEVICE-$FILESYSTEM" local img_fname="openwrt-${TARGET//\//-}-$DEVICE-$FILESYSTEM"
else else
local url_prefix="https://downloads.openwrt.org/releases/$RELEASE/targets/$TARGET" local url_prefix="https://downloads.openwrt.org/releases/$release/targets/$TARGET"
local url_filename="openwrt-imagebuilder-$RELEASE-${TARGET//\//-}.Linux-x86_64.tar.zst" local url_filename="openwrt-imagebuilder-$release-${TARGET//\//-}.Linux-x86_64.tar.zst"
local img_fname="openwrt-$RELEASE-${TARGET//\//-}-$DEVICE-$FILESYSTEM" local img_fname="openwrt-$release-${TARGET//\//-}-$DEVICE-$FILESYSTEM"
fi fi
local imagebuilder_url="$url_prefix/$url_filename" local ib_url="$url_prefix/$url_filename"
local imagebuilder_file="$BUILD_DIR/$url_filename" local ib_file="$BUILD_DIR/$url_filename"
local imagebuilder_sha256_url="$url_prefix/sha256sums" local ib_sha256_url="$url_prefix/sha256sums"
local imagebuilder_sha256_file="$BUILD_DIR/sha256sums" local ib_sha256_file="$BUILD_DIR/sha256sums"
local seed_url="$url_prefix/config.buildinfo"
if [[ "$MODE" == "source" ]]; then if [[ "$mode" == "source" ]]; then
declare -g SYSUPGRADEIMGGZ="$BIN_DIR/targets/$TARGET/$img_fname-sysupgrade.img.gz" declare -g SYSUPGRADEIMGGZ="$BIN_DIR/targets/$TARGET/$img_fname-sysupgrade.img.gz"
else else
declare -g SYSUPGRADEIMGGZ="$BUILD_DIR/$img_fname-sysupgrade.img.gz" declare -g SYSUPGRADEIMGGZ="$BUILD_DIR/$img_fname-sysupgrade.img.gz"
fi fi
# Backup existing output directory backup "$SYSUPGRADEIMGGZ" "$BACKUP_DIR/$profile/$mode-$ref"
if [[ -d "$BIN_DIR" ]]; then
local timestamp
timestamp=$(date +%y%m%d%H%M)
execute mkdir -p "$BACKUP_DIR/$PROFILE/$REF-$MODE-$timestamp"
execute rsync -a --delete --exclude 'packages/' "$BIN_DIR/" "$BACKUP_DIR/$PROFILE/$REF-$MODE-$timestamp/"
fi
if [[ "$MODE" == "source" ]]; then if [[ "$mode" == "source" ]]; then
from_source || return $? from_source "$seed_url" "$profile" "$ref" || return $?
elif [[ "$MODE" == "imagebuilder" ]]; then elif [[ "$mode" == "imagebuilder" ]]; then
[[ -d $BUILD_DIR ]] || mkdir -p "$BUILD_DIR" [[ -d $BUILD_DIR ]] || mkdir -p "$BUILD_DIR"
get_imagebuilder "$imagebuilder_url" "$imagebuilder_file" "$imagebuilder_sha256_url" "$imagebuilder_sha256_file" && get_imagebuilder "$ib_url" "$ib_file" "$ib_sha256_url" "$ib_sha256_file" &&
verify "$imagebuilder_file" "$imagebuilder_sha256_file" && verify "$ib_file" "$ib_sha256_file" &&
extract "$imagebuilder_file" "$BUILD_DIR" || return $? extract "$ib_file" "$BUILD_DIR" || return $?
if [[ -v $repo ]]; then
# Add external repositories for the Image Builder build if ! grep -q "$repo" "$BUILD_DIR/repositories.conf"; then
if [[ -n $REPO ]]; then echo "$repo" >> "$BUILD_DIR/repositories.conf"
if ! grep -q "$REPO" "$BUILD_DIR/repositories.conf"; then
echo "$REPO" >> "$BUILD_DIR/repositories.conf"
fi fi
sed -i '/option check_signature/d' "$BUILD_DIR/repositories.conf" sed -i '/option check_signature/d' "$BUILD_DIR/repositories.conf"
fi fi
@@ -886,7 +816,7 @@ main() {
local -a outfiles=("$BIN_DIR"/*.img.gz "$BIN_DIR"/*.img) local -a outfiles=("$BIN_DIR"/*.img.gz "$BIN_DIR"/*.img)
shopt -u nullglob shopt -u nullglob
for outfile in "${outfiles[@]}"; do for outfile in "${outfiles[@]}"; do
verify "$outfile" "$imagebuilder_sha256_file" || return 1 verify "$outfile" "$ib_sha256_file" || return 1
done done
fi fi
#copyFiles #copyFiles
@@ -898,9 +828,5 @@ main() {
done done
} }
# Roughly turn debugging on for pre-init
# Reset and reparse in parse_input() with getopt
[[ " $* " =~ ( --debug | -d ) ]] && DEBUG=1
main "$@" main "$@"
exit exit

111
profiles
View File

@@ -1,20 +1,12 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Device profiles for openwrtbuilder
# shellcheck disable=SC2034 # shellcheck disable=SC2034
# Device profiles for openwrtbuilder
DEFAULT_RELEASE="25.12.0-rc4" # overrides default release in openwrtbuilder # Default packages
default_packages="luci luci-ssl luci-proto-wireguard luci-app-statistics \
# Default packages (precede with "-" to exclude) collectd-mod-sensors collectd-mod-thermal collectd-mod-conntrack \
default_packages=( collectd-mod-cpu nano htop diffutils tar iperf3 zsh rsync \
ca-bundle nano vim htop diffutils tar iperf3 zsh rsync tcpdump ethtool openssh-sftp-server"
openssh-sftp-server
luci luci-ssl luci-proto-wireguard luci-app-statistics luci-app-filemanager
collectd-mod-sensors collectd-mod-thermal collectd-mod-conntrack collectd-mod-cpu
)
# Default kernel configs
default_configs=(
)
# Current devices # Current devices
declare -Ag r4s=( declare -Ag r4s=(
@@ -22,28 +14,23 @@ declare -Ag r4s=(
[device]="friendlyarm_nanopi-r4s" [device]="friendlyarm_nanopi-r4s"
[target]="rockchip/armv8" [target]="rockchip/armv8"
[filesystem]="ext4" [filesystem]="ext4"
[packages]="${default_packages[*]} \ [packages]="$default_packages luci-app-ddns luci-app-sqm irqbalance \
adblock luci-app-adblock \
irqbalance luci-app-irqbalance \
collectd-mod-df usbutils kmod-usb-storage kmod-usb-storage-uas \ collectd-mod-df usbutils kmod-usb-storage kmod-usb-storage-uas \
kmod-fs-btrfs btrfs-progs block-mount smcroute avahi-daemon \ kmod-fs-btrfs btrfs-progs block-mount smcroute avahi-daemon \
ethtool ca-bundle tailscale" curl ethtool ca-bundle tailscale"
[configs]="${default_configs[*]} \ [config]="CONFIG_KERNEL_BTRFS_FS_POSIX_ACL=y CONFIG_BTRFS_PROGS_ZSTD=y \
CONFIG_KERNEL_BTRFS_FS_POSIX_ACL=y CONFIG_BTRFS_PROGS_ZSTD=y \ CONFIG_TARGET_ROOTFS_PARTSIZE=512 CONFIG_TARGET_KERNEL_PARTSIZE=32 \
CONFIG_TARGET_ROOTFS_PARTSIZE=512 CONFIG_TARGET_KERNEL_PARTSIZE=32" CONFIG_BUILDBOT=n"
[files]="/mnt/backup" [files]="/mnt/backup"
# For 24.10 branch (Linux 6.6)
# [cherrypicks]="https://github.com/wurzerj/openwrt.git:59d6e31 \
# https://github.com/wurzerj/openwrt.git:bb251b8" # fix inconsistent reboot
) )
declare -Ag ax6000=( declare -Ag ax6000=(
[mode]="imagebuilder" [mode]="imagebuilder"
[device]="xiaomi_redmi-router-ax6000-stock" [device]="xiaomi_redmi-router-ax6000-stock"
[target]="mediatek/filogic" [target]="mediatek/filogic"
[release]="snapshot"
[filesystem]="squashfs" [filesystem]="squashfs"
[packages]="${default_packages[*]} \ [packages]="$default_packages -dnsmasq -odhcpd-ipv6only -nftables -firewall4 tailscale"
tailscale"
) )
declare -Ag ax6000_uboot=( declare -Ag ax6000_uboot=(
@@ -52,75 +39,29 @@ declare -Ag ax6000_uboot=(
[target]="mediatek/filogic" [target]="mediatek/filogic"
[release]="snapshot" [release]="snapshot"
[filesystem]="squashfs" [filesystem]="squashfs"
[packages]="${default_packages[*]} \ [packages]="$default_packages -dnsmasq -odhcpd-ipv6only -nftables -firewall4"
-dnsmasq -odhcpd-ipv6only -nftables -firewall4"
) )
declare -Ag n5100=( declare -Ag n5100=(
[device]="generic" [device]="generic"
[target]="x86/64" [target]="x86/64"
[filesystem]="squashfs" [filesystem]="squashfs"
[packages]="${default_packages[*]} \ [packages]="$default_packages luci-app-ddns irqbalance collectd-mod-df \
luci-app-ddns irqbalance collectd-mod-df \
usbutils kmod-usb-storage kmod-usb-storage-uas kmod-fs-btrfs \ usbutils kmod-usb-storage kmod-usb-storage-uas kmod-fs-btrfs \
btrfs-progs block-mount cryptsetup kmod-crypto-xts smcroute \ btrfs-progs block-mount cryptsetup kmod-crypto-xts smcroute \
avahi-daemon ethtool ca-bundle smartmontools intel-microcode \ avahi-daemon curl ethtool ca-bundle smartmontools intel-microcode \
lm-sensors samba4-server luci-app-samba4 tailscale shadow-useradd" lm-sensors samba4-server luci-app-samba4 tailscale shadow-useradd"
[configs]="${default_configs[*]} \ [config]="CONFIG_KERNEL_BTRFS_FS_POSIX_ACL=y CONFIG_BTRFS_PROGS_ZSTD=y \
CONFIG_KERNEL_BTRFS_FS_POSIX_ACL=y CONFIG_BTRFS_PROGS_ZSTD=y \
CONFIG_TARGET_ROOTFS_PARTSIZE=512 CONFIG_TARGET_KERNEL_PARTSIZE=32" CONFIG_TARGET_ROOTFS_PARTSIZE=512 CONFIG_TARGET_KERNEL_PARTSIZE=32"
# [files]="/mnt/backup" # [files]="/mnt/backup"
) )
declare -Ag w1700k=(
[mode]="source"
[device]="gemtek_w1700k"
[target]="airoha/an7581"
[filesystem]="squashfs"
[release]="snapshot"
[packages]="${default_packages[*]} \
luci-app-sqm \
smcroute avahi-daemon \
lm-sensors samba4-server luci-app-samba4 shadow-useradd \
ca-bundle tailscale"
# [cherrypicks]="\
# https://github.com/OpenWRT-fanboy/OpenW1700k.git@lumos:8d449e968cfaa774ab7a219b3a5ab4251b2f9352 \
# https://github.com/OpenWRT-fanboy/OpenW1700k.git@lumos:3033241393ef6eb562539c6a3ccb9d3cf1a25d05 \
# https://github.com/OpenWRT-fanboy/OpenW1700k.git@lumos:79a21e0986a9efe6de3a07394a71ac15a2107b16 \
# https://github.com/OpenWRT-fanboy/OpenW1700k.git@lumos:2f8a1cbf901df0d325dfe112fdfe8013a72c8305 \
# https://github.com/OpenWRT-fanboy/OpenW1700k.git@lumos:71b09bc5852797cdbf7cb3b56a7d8fcd9d4ca9db \
# https://github.com/OpenWRT-fanboy/OpenW1700k.git@lumos:fe0135f0b7037a9cc1985d5937dd24cb99bfccb1 \
# https://github.com/OpenWRT-fanboy/OpenW1700k.git@lumos:cdb937180fb971fe702078f0e0fef63f2fcce337 \
# https://github.com/OpenWRT-fanboy/OpenW1700k.git@lumos:6dc847c802b9dc597fc2c64711ca85499f128d1d \
# https://github.com/OpenWRT-fanboy/OpenW1700k.git@lumos:b6e6cf911915dd987eecde908a2013419565cff4 \
# https://github.com/OpenWRT-fanboy/OpenW1700k.git@lumos:708089948949e66f5234249fc631e0453b58942e \
# https://github.com/OpenWRT-fanboy/OpenW1700k.git@lumos:9841a707a577385498591bcfb56b836176325c2f \
# https://github.com/OpenWRT-fanboy/OpenW1700k.git@lumos:8446ec6431a3247683a27070d3c69f2789b52c70 \
# https://github.com/OpenWRT-fanboy/OpenW1700k.git@lumos:05380e2ef5fb96c171da23453ba32aa349a4b126"
[branches]="https://github.com/OpenWRT-fanboy/OpenW1700k.git@minimal"
)
declare -Ag w1700k_ap=(
[mode]="source"
[device]="gemtek_w1700k"
[target]="airoha/an7581"
[filesystem]="squashfs"
[release]="snapshot"
[packages]="${default_packages[*]} \
-dnsmasq -odhcpd-ipv6only -nftables -firewall4 \
irqblance luci-app-irqbalance \
wpad-openssl libiwinfo-data tailscale bridger switch smp_util \
kmod-crypto-hw-eip93"
[branches]="https://github.com/OpenWRT-fanboy/OpenW1700k.git@minimal"
)
declare -Ag rpi4=( declare -Ag rpi4=(
[device]="rpi-4" [device]="rpi-4"
[target]="bcm27xx/bcm2711" [target]="bcm27xx/bcm2711"
[filesystem]="ext4" [filesystem]="ext4"
[packages]="${default_packages[*]} \ [packages]="$default_packages kmod-usb-net-asix-ax88179 kmod-usb-net-rtl8152 \
luci-app-upnp luci-app-pbr -dnsmasq dnsmasq-full luci-app-ddns luci-app-sqm \ luci-app-upnp luci-app-pbr -dnsmasq dnsmasq-full luci-app-ddns luci-app-sqm"
kmod-usb-net-asix-ax88179 kmod-usb-net-rtl8152"
) )
declare -Ag r4s_stock=( declare -Ag r4s_stock=(
@@ -134,8 +75,7 @@ declare -Ag totolink=(
[device]="totolink_x5000r" [device]="totolink_x5000r"
[target]="ramips/mt7621" [target]="ramips/mt7621"
[filesystem]="squashfs" [filesystem]="squashfs"
[packages]="${default_packages[*]} \ [packages]="$default_packages -dnsmasq -odhcpd-ipv6only -nftables -firewall4 \
-dnsmasq -odhcpd-ipv6only -nftables -firewall4 \
-kmod-nft-offload collectd-mod-iwinfo" -kmod-nft-offload collectd-mod-iwinfo"
) )
@@ -143,7 +83,7 @@ declare -Ag archer=(
[device]="tplink_archer-c7-v2" [device]="tplink_archer-c7-v2"
[target]="ath79/generic" [target]="ath79/generic"
[filesystem]="squashfs" [filesystem]="squashfs"
[packages]="${default_packages[*]} -dnsmasq -odhcpd -iptables \ [packages]="$default_packages -dnsmasq -odhcpd -iptables \
-ath10k-firmware-qca988x-ct ath10k-firmware-qca988x-ct-full-htt" -ath10k-firmware-qca988x-ct ath10k-firmware-qca988x-ct-full-htt"
) )
@@ -151,16 +91,14 @@ declare -Ag linksys=(
[device]="linksys_ea8300" [device]="linksys_ea8300"
[target]="ipq40xx/generic" [target]="ipq40xx/generic"
[filesystem]="squashfs" [filesystem]="squashfs"
[packages]="${default_packages[*]} \ [packages]="$default_packages -dnsmasq -odhcpd -iptables"
-dnsmasq -odhcpd -iptables"
) )
declare -Ag r2s=( declare -Ag r2s=(
[device]="friendlyarm_nanopi-r2s" [device]="friendlyarm_nanopi-r2s"
[target]="rockchip/armv8" [target]="rockchip/armv8"
[filesystem]="ext4" [filesystem]="ext4"
[packages]="${default_packages[*]} \ [packages]="$default_packages luci-app-upnp luci-app-pbr -dnsmasq dnsmasq-full \
luci-app-upnp luci-app-pbr -dnsmasq dnsmasq-full \
luci-app-ddns luci-app-sqm luci-app-statistics collectd-mod-sensors \ luci-app-ddns luci-app-sqm luci-app-statistics collectd-mod-sensors \
collectd-mod-thermal collectd-mod-conntrack smcroute curl ethtool" collectd-mod-thermal collectd-mod-conntrack smcroute curl ethtool"
) )
@@ -169,8 +107,7 @@ declare -Ag r2s_tr=(
[device]="friendlyarm_nanopi-r2s" [device]="friendlyarm_nanopi-r2s"
[target]="rockchip/armv8" [target]="rockchip/armv8"
[filesystem]="ext4" [filesystem]="ext4"
[packages]="${default_packages[*]} \ [packages]="$default_packages luci-app-upnp luci-app-pbr luci-app-ddns \
luci-app-upnp luci-app-pbr luci-app-ddns \
luci-app-statistics collectd-mod-sensors collectd-mod-thermal \ luci-app-statistics collectd-mod-sensors collectd-mod-thermal \
collectd-mod-conntrack curl ethtool travelmate" collectd-mod-conntrack curl ethtool travelmate"
) )