developer | 782bc7f | 2024-08-23 15:39:22 +0800 | [diff] [blame] | 1 | #!/usr/bin/env bash |
| 2 | |
| 3 | # Copyright (C) 2024 MediaTek Inc. All rights reserved. |
| 4 | # Author: Weijie Gao <weijie.gao@mediatek.com> |
| 5 | # Autobuild framework for OpenWrt |
| 6 | |
| 7 | # Autobuild script base directory |
| 8 | ab_root="$(dirname "$(readlink -f "$0")")" |
| 9 | |
| 10 | . ${ab_root}/scripts/log.sh |
| 11 | . ${ab_root}/scripts/list.sh |
| 12 | . ${ab_root}/scripts/kconfig.sh |
| 13 | . ${ab_root}/scripts/openwrt_helpers.sh |
| 14 | . ${ab_root}/scripts/ab-common.sh |
| 15 | |
| 16 | # Command line processing |
| 17 | |
| 18 | ## Parse autobuild branch name |
| 19 | ab_branch= |
| 20 | ab_branch_names= |
| 21 | ab_branch_level=0 |
| 22 | |
| 23 | if autobuild_branch_name_check "${1}"; then |
| 24 | canonicalize_autobuild_branch_name "${1}" ab_branch_names ab_branch |
| 25 | shift |
| 26 | fi |
| 27 | |
| 28 | ## Stages |
| 29 | ab_stages="prepare build release" |
| 30 | do_menuconfig= |
| 31 | do_help= |
| 32 | do_list= |
| 33 | do_clean= |
| 34 | |
| 35 | if list_find ab_stages "${1}"; then |
| 36 | ab_stages="${1}" |
| 37 | shift |
| 38 | elif test x"${1}" = x"sdk_release"; then |
| 39 | ab_stages="prepare sdk_release" |
| 40 | shift |
| 41 | elif test x"${1}" = x"menuconfig"; then |
| 42 | ab_stages="prepare menuconfig" |
| 43 | do_menuconfig=1 |
| 44 | shift |
| 45 | elif test x"${1}" = x"help"; then |
| 46 | ab_stages="help" |
| 47 | do_help=1 |
| 48 | shift |
| 49 | elif test x"${1}" = x"list"; then |
| 50 | do_list=1 |
| 51 | shift |
| 52 | elif test x"${1}" = x"clean"; then |
| 53 | do_clean=1 |
| 54 | shift |
| 55 | fi |
| 56 | |
| 57 | ## Options |
| 58 | __logged_args=() |
| 59 | for arg in "$@"; do |
| 60 | if expr index ${arg} '=' 2>&1 >/dev/null; then |
| 61 | name=${arg%%=*} |
| 62 | value=${arg#*=} |
| 63 | |
| 64 | eval ${name}=\"\${value}\" |
| 65 | eval ${name}_set=yes |
| 66 | |
| 67 | __logged_args[${#__logged_args[@]}]="${name}=\"${value}\"" |
| 68 | else |
| 69 | eval ${arg}_set=yes |
| 70 | |
| 71 | __logged_args[${#__logged_args[@]}]="${arg}" |
| 72 | fi |
| 73 | done |
| 74 | |
| 75 | IFS=$'\n' __sorted_args=($(sort <<< "${__logged_args[*]}")); unset IFS |
| 76 | IFS=' ' ab_cmdline="${__logged_args[@]}"; unset IFS |
| 77 | |
| 78 | # Enable debugging log? |
| 79 | if test x"${debug_set}" = x"yes"; then |
| 80 | enable_log_debug |
| 81 | fi |
| 82 | |
| 83 | # Enable logging to file? |
| 84 | if test x"${log_file_set}" = x"yes"; then |
| 85 | log_file_merge= |
| 86 | |
| 87 | [ x"${log_file_merge_set}" = x"yes" ] && log_file_merge=1 |
| 88 | |
| 89 | set_log_file_prefix "${log_file}" ${log_file_merge} |
| 90 | fi |
| 91 | |
| 92 | # OK, do list here if required |
| 93 | if test x"${do_list}" = x"1"; then |
| 94 | list_all_autobuild_branches |
| 95 | exit 0 |
| 96 | fi |
| 97 | |
| 98 | openwrt_root="$(pwd)" |
| 99 | |
| 100 | if ! is_openwrt_build_root "${openwrt_root}"; then |
| 101 | log_err "${openwrt_root} is not a OpenWrt root directory." |
| 102 | log_err "The autobuild script must be called from within the OpenWrt root directory." |
| 103 | exit 1 |
| 104 | fi |
| 105 | |
| 106 | # OpenWrt branch (master, 21.02, ...) |
| 107 | openwrt_branch=$(openwrt_get_branch) |
| 108 | |
| 109 | if test -z "${openwrt_branch}"; then |
| 110 | log_err "Failed to get OpenWrt's branch" |
| 111 | exit 1 |
| 112 | else |
| 113 | log_info "OpenWrt's branch is ${openwrt_branch}" |
| 114 | fi |
| 115 | |
| 116 | # Temporary directory for storing configs and intermediate files |
| 117 | ab_tmp="${openwrt_root}/.ab" |
| 118 | |
| 119 | # Default release directory |
| 120 | ab_bin_release="${openwrt_root}/autobuild_release" |
| 121 | |
| 122 | # OK, do clean here if required |
| 123 | if test x"${do_clean}" = x"1"; then |
| 124 | if ! git status >/dev/null; then |
| 125 | log_warn "The clean stage can only be applied if the OpenWrt source is managed by Git." |
| 126 | exit 1 |
| 127 | fi |
| 128 | |
| 129 | exec_log "git -C \"${openwrt_root}\" checkout ." |
| 130 | exec_log "git -C \"${openwrt_root}\" clean -f -d -e autobuild" |
developer | 521bb95 | 2024-09-26 17:06:50 +0800 | [diff] [blame] | 131 | if test x"${reserve_feeds_set}" != x"yes"; then |
| 132 | exec_log "rm -rf \"${openwrt_root}/feeds\"" |
| 133 | exec_log "rm -rf \"${openwrt_root}/package/feeds\"" |
| 134 | fi |
developer | 782bc7f | 2024-08-23 15:39:22 +0800 | [diff] [blame] | 135 | exec_log "rm -rf \"${openwrt_root}/.ab\"" |
| 136 | |
| 137 | exit 0 |
| 138 | fi |
| 139 | |
| 140 | # Check if we need prepare for build stage |
| 141 | if list_find ab_stages build; then |
| 142 | if test \( ! -f "${ab_tmp}/branch_name" \) -o -f "${ab_tmp}/.stamp.menuconfig"; then |
| 143 | list_add_before_unique ab_stages build prepare |
| 144 | fi |
| 145 | fi |
| 146 | |
| 147 | # Check for prepare stage |
| 148 | if list_find ab_stages prepare; then |
| 149 | if test -f "${ab_tmp}/branch_name"; then |
| 150 | # If prepare stage has been done before, check whether clean is required |
| 151 | |
| 152 | if test -z "${do_menuconfig}" -a -f "${ab_tmp}/.stamp.menuconfig"; then |
| 153 | log_warn "This OpenWrt source code has already been prepared for menuconfig." |
| 154 | log_warn "Please call \`${0} clean' first." |
| 155 | exit 1 |
| 156 | fi |
| 157 | |
| 158 | if test -n "${do_menuconfig}" -a ! -f "${ab_tmp}/.stamp.menuconfig"; then |
| 159 | log_warn "This OpenWrt source code has already been prepared, but not for menuconfig." |
| 160 | log_warn "Please call \`${0} clean' first." |
| 161 | exit 1 |
| 162 | fi |
| 163 | |
| 164 | last_ab_branch=$(cat "${ab_tmp}/branch_name") |
| 165 | |
| 166 | if test -n "${ab_branch}"; then |
| 167 | if test x"${ab_branch}" != x"${last_ab_branch}"; then |
| 168 | log_warn "Autobuild branch name has changed." |
| 169 | log_warn "Please call \`${0} clean' first." |
| 170 | exit 1 |
| 171 | fi |
| 172 | |
| 173 | if test -z "${do_menuconfig}"; then |
| 174 | last_ab_cmdline=$(cat "${ab_tmp}/cmdline") |
| 175 | |
| 176 | if test x"${ab_cmdline}" != x"${last_ab_cmdline}"; then |
| 177 | log_warn "Autobuild configuration has changed." |
| 178 | log_warn "Please call \`${0} clean' first." |
| 179 | exit 1 |
| 180 | fi |
| 181 | fi |
| 182 | |
| 183 | # Configuration unchanged |
| 184 | else |
| 185 | # Read previous configuration |
| 186 | canonicalize_autobuild_branch_name "${last_ab_branch}" ab_branch_names ab_branch |
| 187 | fi |
| 188 | |
| 189 | # prepare stage is not needed |
| 190 | list_del ab_stages prepare |
| 191 | else |
| 192 | if test -z "${ab_branch}" -a x"${do_help}" != x"1"; then |
| 193 | log_err "Autobuild branch name is invalid or not specified." |
| 194 | print_text "Quick start:" |
| 195 | print_text "- To show detailed help:" |
| 196 | log_info_raw " ${0} help" |
| 197 | print_text "- To start full build for a branch (<branch-name> example: mtxxxx-mtxxxx-xxx):" |
| 198 | log_info_raw " ${0} <branch-name>" |
| 199 | print_text "- To continue current build:" |
| 200 | log_info_raw " ${0} build" |
| 201 | print_text "- To clean everything under OpenWrt source tree:" |
| 202 | log_info_raw " ${0} clean" |
| 203 | print_text "- To start menuconfig and update defconfig for specified branch:" |
| 204 | log_info_raw " ${0} <branch-name> menuconfig" |
| 205 | print_text "- To list all available branch names:" |
| 206 | log_info_raw " ${0} <branch-name> list" |
| 207 | exit 1 |
| 208 | fi |
| 209 | fi |
| 210 | else |
| 211 | if test -z "${ab_branch}" -a -f "${ab_tmp}/branch_name"; then |
| 212 | last_ab_branch=$(cat "${ab_tmp}/branch_name") |
| 213 | |
| 214 | # Read previous configuration |
| 215 | canonicalize_autobuild_branch_name "${last_ab_branch}" ab_branch_names ab_branch |
| 216 | fi |
| 217 | fi |
| 218 | |
| 219 | ## Fill branch names |
| 220 | ab_branch_level=${#ab_branch_names[@]} |
| 221 | ab_branch_platform=${ab_branch_names[0]} |
| 222 | ab_branch_wifi=${ab_branch_names[1]} |
| 223 | ab_branch_sku=${ab_branch_names[2]} |
| 224 | ab_branch_variant=${ab_branch_names[3]} |
| 225 | |
| 226 | ## Set and print branch configuration |
| 227 | [ -n "${ab_branch}" ] && log_info "Autobuild branch: ${ab_branch}" |
| 228 | |
| 229 | if test -n "${ab_branch_platform}"; then |
| 230 | ab_branch_level=1 |
| 231 | ab_platform_dir=${ab_root}/${ab_branch_platform} |
| 232 | print_conf "Platform" "${ab_branch_platform}" |
| 233 | fi |
| 234 | |
| 235 | if test -n "${ab_branch_wifi}"; then |
| 236 | ab_branch_level=2 |
| 237 | ab_wifi_dir=${ab_platform_dir}/${ab_branch_wifi} |
| 238 | print_conf "WiFi" "${ab_branch_wifi}" |
| 239 | fi |
| 240 | |
| 241 | if test -n "${ab_branch_sku}"; then |
| 242 | ab_branch_level=3 |
| 243 | ab_sku_dir=${ab_wifi_dir}/${ab_branch_sku} |
| 244 | print_conf "SKU" "${ab_branch_sku}" |
| 245 | fi |
| 246 | |
| 247 | if test -n "${ab_branch_variant}"; then |
| 248 | ab_branch_level=4 |
| 249 | ab_variant_dir=${ab_sku_dir}/${ab_branch_variant} |
| 250 | print_conf "Variant" "${ab_branch_variant}" |
| 251 | fi |
| 252 | |
| 253 | # Setup global settings |
| 254 | |
| 255 | ## Set new binary release directory |
| 256 | if test x"${release_dir_set}" = x"yes"; then |
| 257 | ab_bin_release="${openwrt_root}/${release_dir}" |
| 258 | fi |
| 259 | |
| 260 | ab_bin_release="${ab_bin_release}/${ab_branch}" |
| 261 | |
| 262 | ## Set global directories |
| 263 | ab_global=${ab_root}/global |
| 264 | |
| 265 | # Setup help text |
| 266 | help_add_line "" |
| 267 | help_add_line "Autobuild script for OpenWrt" |
| 268 | help_add_line "" |
| 269 | help_add_line "Usage: autobuild.sh [branch] [stage] [options...]" |
| 270 | help_add_line "" |
| 271 | help_add_line "Branch: <platform>[-<wifi>[-<sku>[-<variant>]]]" |
| 272 | help_add_line " Branch is only required for prepare. It can be omitted for build/release" |
| 273 | help_add_line " after a successful prepare." |
| 274 | help_add_line "" |
| 275 | help_add_line "Stages:" |
| 276 | help_add_line " (If stage is not specified, default will be \"prepare/build/release\")" |
| 277 | help_add_line " prepare - Prepare the OpenWrt source code." |
| 278 | help_add_line " Do patching, copying/deleting files." |
| 279 | help_add_line " Once prepared, clean must be done before another prepare." |
| 280 | help_add_line " build - Do actual build." |
| 281 | help_add_line " release - Collect built binary files only." |
| 282 | help_add_line " sdk_release - Do source code release. MediaTek internal use only." |
| 283 | help_add_line " menuconfig - Do menuconfig for specified branch. defconfig of this branch" |
| 284 | help_add_line " will be updated." |
| 285 | help_add_line " clean - Clean all modified/untraced files/directories from OpenWrt" |
| 286 | help_add_line " source code." |
| 287 | help_add_line " list - List all available branch names." |
| 288 | help_add_line " help - Show this help." |
| 289 | help_add_line "" |
| 290 | help_add_line "Options:" |
| 291 | help_add_line " The options can be <key>=<value>, or just simple <key>." |
| 292 | help_add_line " log_file=<file> - Enable log output to file." |
| 293 | help_add_line " log_file_merge - Log stdout and stderr to one file." |
| 294 | help_add_line " debug - Enable debug log output." |
| 295 | help_add_line " release_dir=<dir> - Override default release directory." |
| 296 | help_add_line " Default directory is 'autobuild_release' under OpenWrt's source directory." |
developer | 561475a | 2024-09-27 11:07:06 +0800 | [diff] [blame] | 297 | help_add_line " sync_config - When used with menuconfig, .config will be updated with" |
| 298 | help_add_line " current branch defconfigs before starting menuconfig" |
developer | 782bc7f | 2024-08-23 15:39:22 +0800 | [diff] [blame] | 299 | |
| 300 | # Include branch rules (the rule is child level overriding parent level) |
| 301 | . "${ab_root}/rules" |
| 302 | [ -f "${ab_global}/${openwrt_branch}/rules" ] && . "${ab_global}/${openwrt_branch}/rules" |
| 303 | [ -n "${ab_platform_dir}" ] && . "${ab_platform_dir}/rules" |
| 304 | [ -n "${ab_wifi_dir}" ] && . "${ab_wifi_dir}/rules" |
| 305 | [ -n "${ab_sku_dir}" ] && . "${ab_sku_dir}/rules" |
| 306 | [ -n "${ab_variant_dir}" ] && . "${ab_variant_dir}/rules" |
| 307 | |
| 308 | # Show help? |
| 309 | if test x"${do_help}" = x"1"; then |
| 310 | help_print |
| 311 | exit 0 |
| 312 | fi |
| 313 | |
| 314 | # Run stages |
| 315 | log_dbg "All stages: ${ab_stages}" |
| 316 | |
| 317 | for stage in ${ab_stages}; do |
| 318 | substages=$(get_substages "${stage}") |
| 319 | |
| 320 | prompt_stage "Current stage: \"${stage}\"" |
| 321 | log_dbg "Substages of ${stage}: ${substages}" |
| 322 | |
| 323 | for substage in ${substages}; do |
| 324 | hooks=$(get_hooks "${substage}") |
| 325 | |
| 326 | prompt_stage "Current substage: \"${substage}\"" |
| 327 | |
| 328 | [ -z "${hooks}" ] && hooks="${substage}" |
| 329 | clean_hooks hooks |
| 330 | |
| 331 | if test -z "${hooks}"; then |
| 332 | log_info "Nothing to do with substage ${substage}" |
| 333 | continue |
| 334 | fi |
| 335 | |
| 336 | log_dbg "Hooks of substage \"${substage}\": ${hooks}" |
| 337 | |
| 338 | for hook in ${hooks}; do |
| 339 | prompt_stage "Executing hook \"${hook}\"" |
| 340 | |
| 341 | eval "${hook}" |
| 342 | |
| 343 | ret=$? |
| 344 | |
| 345 | if test ${ret} != 0; then |
| 346 | log_err "${stage}/${substage}/${hook} exited with error code ${ret}" |
| 347 | exit 1 |
| 348 | fi |
| 349 | done |
| 350 | done |
| 351 | done |
| 352 | |
| 353 | # All done |
| 354 | if list_find ab_stages build; then |
| 355 | log_info "Autobuild finished" |
| 356 | fi |
| 357 | |
| 358 | exit 0 |