#!/bin/bash # Add specified OpenWRT packages (from a text file) to .config without removing existing ones # Author: Zhe Yuan # Usage: # ./add-openwrt-packages.sh packages.txt # Description: # - Reads package names from a text file (supports both newline or space separation) # - Supports ##built-in and ##module sections to control build mode (=y or =m) # - Packages default to built-in (=y) if no section header is specified # - Adds missing CONFIG_PACKAGE_xxx entries to .config # - Keeps existing settings intact # - Reports missing packages # - Runs make defconfig at the end to sync dependencies set -e umask 022 # Check argument if [ "$#" -ne 1 ]; then echo "❌ Usage: $0 " exit 1 fi PKG_FILE="$1" # Verify file exists if [ ! -f "$PKG_FILE" ]; then echo "❌ Error: File not found: $PKG_FILE" exit 1 fi # Verify we are in OpenWRT source root if [ ! -d "package" ] || [ ! -f "Makefile" ]; then echo "❌ Error: Please run this script in the OpenWRT source root directory." exit 1 fi # Ensure .config exists if [ ! -f ".config" ]; then echo "⚙️ Generating initial .config..." make defconfig fi PACKAGE_INDEX="tmp/.config-package.in" PACKAGE_INFO="tmp/.packageinfo" # Ensure package metadata exists for reliable package name lookups. if [ ! -f "$PACKAGE_INDEX" ] && [ ! -f "$PACKAGE_INFO" ]; then echo "⚙️ Generating package metadata..." make defconfig >/dev/null fi is_already_builtin() { local pkg="$1" awk -v package_y="CONFIG_PACKAGE_${pkg}=y" \ -v default_y="CONFIG_DEFAULT_${pkg}=y" \ '$0 == package_y || $0 == default_y { found=1; exit } END { exit !found }' .config } is_module() { local pkg="$1" grep -qx "CONFIG_PACKAGE_${pkg}=m" .config } package_exists() { local pkg="$1" if [ -f "$PACKAGE_INDEX" ] && awk -v key="PACKAGE_${pkg}" '$1 == "config" && $2 == key { found=1; exit } END { exit !found }' "$PACKAGE_INDEX"; then return 0 fi if [ -f "$PACKAGE_INFO" ] && grep -Fqx "Package: $pkg" "$PACKAGE_INFO"; then return 0 fi return 1 } echo "📦 Reading packages from $PKG_FILE ..." # Parse the file into "package:mode" pairs, respecting ##built-in / ##module sections. # Default mode is "y" (built-in). Inline comments (#xxx but not ##) are stripped. ENTRIES=$(awk ' BEGIN { mode = "y" } /^##built-in/ { mode = "y"; next } /^##module/ { mode = "m"; next } { sub(/#[^#].*/, "") # strip inline comments (single #), preserve ## headers for (i = 1; i <= NF; i++) print $i ":" mode } ' "$PKG_FILE") ADDED=() UPGRADED=() MISSING=() for entry in $ENTRIES; do pkg="${entry%:*}" mode="${entry##*:}" CONFIG_NAME="CONFIG_PACKAGE_${pkg}" if [ "$mode" = "y" ]; then # --- built-in mode --- if is_already_builtin "$pkg"; then echo "✅ Already built-in: $pkg" continue fi if is_module "$pkg"; then sed -i "s/^CONFIG_PACKAGE_${pkg}=m$/CONFIG_PACKAGE_${pkg}=y/" .config UPGRADED+=("$pkg") echo "⬆️ Module → built-in: $pkg" continue fi else # --- module mode --- if is_module "$pkg"; then echo "✅ Already module: $pkg" continue fi if is_already_builtin "$pkg"; then echo "✅ Already built-in (keeping): $pkg" continue fi fi # Check if package exists in OpenWrt package metadata. if ! package_exists "$pkg"; then echo "⚠️ Package not found: $pkg" MISSING+=("$pkg") continue fi # Append package config echo "${CONFIG_NAME}=${mode}" >> .config ADDED+=("$pkg (=${mode})") echo "➕ Added: $pkg (=${mode})" done # Run defconfig to sync dependencies echo echo "⚙️ Running make defconfig..." make defconfig >/dev/null echo echo "✅ Done!" echo "📋 Packages newly added: ${#ADDED[@]}" [ ${#ADDED[@]} -gt 0 ] && echo " → ${ADDED[*]}" echo "📋 Packages upgraded to built-in: ${#UPGRADED[@]}" [ ${#UPGRADED[@]} -gt 0 ] && echo " → ${UPGRADED[*]}" if [ ${#MISSING[@]} -gt 0 ]; then echo "⚠️ Packages not found (check feeds or spelling):" for m in "${MISSING[@]}"; do echo " - $m" done fi