| Joe Onorato | 344e404 | 2022-12-05 15:15:36 -0800 | [diff] [blame] | 1 | # Copyright (C) 2022 The Android Open Source Project |
| 2 | # |
| 3 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | # you may not use this file except in compliance with the License. |
| 5 | # You may obtain a copy of the License at |
| 6 | # |
| 7 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | # |
| 9 | # Unless required by applicable law or agreed to in writing, software |
| 10 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | # See the License for the specific language governing permissions and |
| 13 | # limitations under the License. |
| 14 | |
| 15 | function gettop |
| 16 | { |
| 17 | local TOPFILE=build/make/core/envsetup.mk |
| 18 | # The ${TOP-} expansion allows this to work even with set -u |
| 19 | if [ -n "${TOP:-}" -a -f "${TOP:-}/$TOPFILE" ] ; then |
| 20 | # The following circumlocution ensures we remove symlinks from TOP. |
| 21 | (cd "$TOP"; PWD= /bin/pwd) |
| 22 | else |
| 23 | if [ -f $TOPFILE ] ; then |
| 24 | # The following circumlocution (repeated below as well) ensures |
| 25 | # that we record the true directory name and not one that is |
| 26 | # faked up with symlink names. |
| 27 | PWD= /bin/pwd |
| 28 | else |
| 29 | local HERE=$PWD |
| 30 | local T= |
| 31 | while [ \( ! \( -f $TOPFILE \) \) -a \( "$PWD" != "/" \) ]; do |
| 32 | \cd .. |
| 33 | T=`PWD= /bin/pwd -P` |
| 34 | done |
| 35 | \cd "$HERE" |
| 36 | if [ -f "$T/$TOPFILE" ]; then |
| 37 | echo "$T" |
| 38 | fi |
| 39 | fi |
| 40 | fi |
| 41 | } |
| 42 | |
| Joe Onorato | 2312475 | 2024-05-14 15:06:48 -0700 | [diff] [blame] | 43 | # Asserts that the root of the tree can be found. |
| Joe Onorato | 344e404 | 2022-12-05 15:15:36 -0800 | [diff] [blame] | 44 | if [ -z "${IMPORTING_ENVSETUP:-}" ] ; then |
| 45 | function require_top |
| 46 | { |
| 47 | TOP=$(gettop) |
| 48 | if [[ ! $TOP ]] ; then |
| Joe Onorato | 1b9ab29 | 2024-05-17 12:16:43 -0700 | [diff] [blame] | 49 | echo "Can not locate root of source tree. $(basename $0) must be run from within the Android source tree or TOP must be set." >&2 |
| Joe Onorato | 344e404 | 2022-12-05 15:15:36 -0800 | [diff] [blame] | 50 | exit 1 |
| 51 | fi |
| 52 | } |
| 53 | fi |
| 54 | |
| Joe Onorato | 2312475 | 2024-05-14 15:06:48 -0700 | [diff] [blame] | 55 | # Asserts that the lunch variables have been set |
| 56 | if [ -z "${IMPORTING_ENVSETUP:-}" ] ; then |
| 57 | function require_lunch |
| 58 | { |
| 59 | if [[ ! $TARGET_PRODUCT || ! $TARGET_RELEASE || ! $TARGET_BUILD_VARIANT ]] ; then |
| 60 | echo "Please run lunch and try again." >&2 |
| 61 | exit 1 |
| 62 | fi |
| 63 | } |
| 64 | fi |
| 65 | |
| Sam Lewis | 5119330 | 2025-08-22 11:37:33 -0700 | [diff] [blame] | 66 | function set_network_file_system_type_env_var() { |
| 67 | local top=$(gettop) |
| 68 | local out_dir=$(getoutdir) |
| 69 | local cartfs_mount_point=$(cartfs_mount_point) |
| 70 | |
| 71 | local nfs_type=local |
| 72 | |
| Sam Lewis | 54ee0cc | 2025-08-25 12:46:35 -0700 | [diff] [blame] | 73 | # The options are: |
| Sam Lewis | 15aeee2 | 2025-09-04 10:51:01 -0700 | [diff] [blame] | 74 | # - cog-cartfs-symlink: out is a symlink to a CartFS path in a Cog workspace. |
| 75 | # - local-cartfs-symlink: out is a symlink to a CartFS path in a local workspace. |
| Sam Lewis | 54ee0cc | 2025-08-25 12:46:35 -0700 | [diff] [blame] | 76 | # - cog-symlink: $top starts with /google/cog. |
| 77 | # - abfs: .abfs.sock exists in the workspace. |
| Sam Lewis | 5119330 | 2025-08-22 11:37:33 -0700 | [diff] [blame] | 78 | if [[ -n "$cartfs_mount_point" && -L "$out_dir" && "$(readlink "$out_dir")" =~ ^/google/cartfs/mount ]]; then |
| Sam Lewis | 15aeee2 | 2025-09-04 10:51:01 -0700 | [diff] [blame] | 79 | if [[ "$top" =~ ^/google/cog ]]; then |
| 80 | nfs_type=cog-cartfs-symlink |
| 81 | else |
| 82 | nfs_type=local-cartfs-symlink |
| 83 | fi |
| Sam Lewis | 54ee0cc | 2025-08-25 12:46:35 -0700 | [diff] [blame] | 84 | elif [[ "$top" =~ ^/google/cog ]]; then |
| 85 | nfs_type=cog-symlink |
| 86 | elif [[ -f "$top/.abfs.sock" ]]; then |
| 87 | nfs_type=abfs |
| Sam Lewis | 5119330 | 2025-08-22 11:37:33 -0700 | [diff] [blame] | 88 | fi |
| 89 | |
| 90 | export NETWORK_FILE_SYSTEM_TYPE=$nfs_type |
| 91 | } |
| 92 | |
| Sam Lewis | 2404c4a | 2024-09-23 20:06:02 +0000 | [diff] [blame] | 93 | # This function sets up the build environment to be appropriate for Cog. |
| 94 | function setup_cog_env_if_needed() { |
| 95 | local top=$(gettop) |
| 96 | |
| 97 | # return early if not in a cog workspace |
| 98 | if [[ ! "$top" =~ ^/google/cog ]]; then |
| 99 | return 0 |
| 100 | fi |
| 101 | |
| Martin Simard | 49706bf | 2025-07-07 10:27:00 -0700 | [diff] [blame] | 102 | clean_deleted_workspaces_in_cartfs |
| 103 | |
| Sam Lewis | 2404c4a | 2024-09-23 20:06:02 +0000 | [diff] [blame] | 104 | setup_cog_symlink |
| 105 | |
| 106 | export ANDROID_BUILD_ENVIRONMENT_CONFIG="googler-cog" |
| 107 | |
| 108 | # Running repo command within Cog workspaces is not supported, so override |
| 109 | # it with this function. If the user is running repo within a Cog workspace, |
| 110 | # we'll fail with an error, otherwise, we run the original repo command with |
| 111 | # the given args. |
| 112 | if ! ORIG_REPO_PATH=`which repo`; then |
| 113 | return 0 |
| 114 | fi |
| 115 | function repo { |
| 116 | if [[ "${PWD}" == /google/cog/* ]]; then |
| 117 | echo -e "\e[01;31mERROR:\e[0mrepo command is disallowed within Cog workspaces." |
| 118 | kill -INT $$ # exits the script without exiting the user's shell |
| 119 | fi |
| 120 | ${ORIG_REPO_PATH} "$@" |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | # creates a symlink for the out/ dir when inside a cog workspace. |
| 125 | function setup_cog_symlink() { |
| 126 | local out_dir=$(getoutdir) |
| 127 | local top=$(gettop) |
| 128 | |
| Sam Lewis | a7939b2 | 2025-03-10 12:00:35 -0700 | [diff] [blame] | 129 | # return early if out dir is already a symlink. |
| Sam Lewis | 2404c4a | 2024-09-23 20:06:02 +0000 | [diff] [blame] | 130 | if [[ -L "$out_dir" ]]; then |
| Sam Lewis | a7939b2 | 2025-03-10 12:00:35 -0700 | [diff] [blame] | 131 | destination=$(readlink "$out_dir") |
| 132 | # ensure the destination exists. |
| 133 | mkdir -p "$destination" |
| Sam Lewis | 2404c4a | 2024-09-23 20:06:02 +0000 | [diff] [blame] | 134 | return 0 |
| 135 | fi |
| 136 | |
| 137 | # return early if out dir is not in the workspace |
| 138 | if [[ ! "$out_dir" =~ ^$top/ ]]; then |
| 139 | return 0 |
| 140 | fi |
| 141 | |
| 142 | local link_destination="${HOME}/.cog/android-build-out" |
| 143 | |
| Martin Simard | 49706bf | 2025-07-07 10:27:00 -0700 | [diff] [blame] | 144 | # When cartfs is mounted, use it as the destination for output directory. |
| 145 | local cartfs_mount_point=$(cartfs_mount_point) |
| 146 | if [[ -n "$cartfs_mount_point" ]]; then |
| 147 | local cog_workspace_name="$(basename "$(dirname "${top}")")" |
| 148 | link_destination="${cartfs_mount_point}/${cog_workspace_name}/out" |
| 149 | fi |
| 150 | |
| Sam Lewis | 1513eab | 2024-09-24 19:47:08 +0000 | [diff] [blame] | 151 | # remove existing out/ dir if it exists |
| Sam Lewis | 2404c4a | 2024-09-23 20:06:02 +0000 | [diff] [blame] | 152 | if [[ -d "$out_dir" ]]; then |
| Sam Lewis | 1513eab | 2024-09-24 19:47:08 +0000 | [diff] [blame] | 153 | echo "Detected existing out/ directory in the Cog workspace which is not supported. Repairing workspace by removing it and creating the symlink to ~/.cog/android-build-out" |
| 154 | if ! rm -rf "$out_dir"; then |
| 155 | echo "Failed to remove existing out/ directory: $out_dir" >&2 |
| Sam Lewis | 2404c4a | 2024-09-23 20:06:02 +0000 | [diff] [blame] | 156 | kill -INT $$ # exits the script without exiting the user's shell |
| 157 | fi |
| 158 | fi |
| 159 | |
| 160 | # create symlink |
| 161 | echo "Creating symlink: $out_dir -> $link_destination" |
| 162 | mkdir -p ${link_destination} |
| 163 | if ! ln -s "$link_destination" "$out_dir"; then |
| 164 | echo "Failed to create cog symlink: $out_dir -> $link_destination" >&2 |
| 165 | kill -INT $$ # exits the script without exiting the user's shell |
| 166 | fi |
| 167 | } |
| 168 | |
| Joe Onorato | 344e404 | 2022-12-05 15:15:36 -0800 | [diff] [blame] | 169 | function getoutdir |
| 170 | { |
| 171 | local top=$(gettop) |
| 172 | local out_dir="${OUT_DIR:-}" |
| 173 | if [[ -z "${out_dir}" ]]; then |
| 174 | if [[ -n "${OUT_DIR_COMMON_BASE:-}" && -n "${top}" ]]; then |
| 175 | out_dir="${OUT_DIR_COMMON_BASE}/$(basename ${top})" |
| 176 | else |
| 177 | out_dir="out" |
| 178 | fi |
| 179 | fi |
| 180 | if [[ "${out_dir}" != /* ]]; then |
| 181 | out_dir="${top}/${out_dir}" |
| 182 | fi |
| 183 | echo "${out_dir}" |
| 184 | } |
| 185 | |
| Joe Onorato | 1b9ab29 | 2024-05-17 12:16:43 -0700 | [diff] [blame] | 186 | # Pretty print the build status and duration |
| 187 | function _wrap_build() |
| 188 | { |
| 189 | if [[ "${ANDROID_QUIET_BUILD:-}" == true ]]; then |
| 190 | "$@" |
| 191 | return $? |
| 192 | fi |
| 193 | local start_time=$(date +"%s") |
| 194 | "$@" |
| 195 | local ret=$? |
| 196 | local end_time=$(date +"%s") |
| 197 | local tdiff=$(($end_time-$start_time)) |
| 198 | local hours=$(($tdiff / 3600 )) |
| 199 | local mins=$((($tdiff % 3600) / 60)) |
| 200 | local secs=$(($tdiff % 60)) |
| 201 | local ncolors=$(tput colors 2>/dev/null) |
| 202 | if [ -n "$ncolors" ] && [ $ncolors -ge 8 ]; then |
| 203 | color_failed=$'\E'"[0;31m" |
| 204 | color_success=$'\E'"[0;32m" |
| 205 | color_warning=$'\E'"[0;33m" |
| 206 | color_reset=$'\E'"[00m" |
| 207 | else |
| 208 | color_failed="" |
| 209 | color_success="" |
| 210 | color_reset="" |
| 211 | fi |
| 212 | |
| 213 | echo |
| 214 | if [ $ret -eq 0 ] ; then |
| 215 | echo -n "${color_success}#### build completed successfully " |
| 216 | else |
| 217 | echo -n "${color_failed}#### failed to build some targets " |
| 218 | fi |
| 219 | if [ $hours -gt 0 ] ; then |
| Alexander Koskovich | a20a7fb | 2024-10-13 21:33:23 -0400 | [diff] [blame] | 220 | printf "(%02d:%02d:%02d (hh:mm:ss))" $hours $mins $secs |
| Joe Onorato | 1b9ab29 | 2024-05-17 12:16:43 -0700 | [diff] [blame] | 221 | elif [ $mins -gt 0 ] ; then |
| Alexander Koskovich | a20a7fb | 2024-10-13 21:33:23 -0400 | [diff] [blame] | 222 | printf "(%02d:%02d (mm:ss))" $mins $secs |
| Joe Onorato | 1b9ab29 | 2024-05-17 12:16:43 -0700 | [diff] [blame] | 223 | elif [ $secs -gt 0 ] ; then |
| Alexander Koskovich | a20a7fb | 2024-10-13 21:33:23 -0400 | [diff] [blame] | 224 | printf "(%d seconds)" $secs |
| Joe Onorato | 1b9ab29 | 2024-05-17 12:16:43 -0700 | [diff] [blame] | 225 | fi |
| 226 | echo " ####${color_reset}" |
| 227 | echo |
| 228 | return $ret |
| 229 | } |
| 230 | |
| 231 | |
| Joe Onorato | 1f6eddb | 2024-05-31 15:04:44 -0700 | [diff] [blame] | 232 | function log_tool_invocation() |
| 233 | { |
| 234 | if [[ -z $ANDROID_TOOL_LOGGER ]]; then |
| 235 | return |
| 236 | fi |
| 237 | |
| 238 | LOG_TOOL_TAG=$1 |
| 239 | LOG_START_TIME=$(date +%s.%N) |
| 240 | trap ' |
| 241 | exit_code=$?; |
| 242 | # Remove the trap to prevent duplicate log. |
| 243 | trap - EXIT; |
| 244 | $ANDROID_TOOL_LOGGER \ |
| 245 | --tool_tag="${LOG_TOOL_TAG}" \ |
| 246 | --start_timestamp="${LOG_START_TIME}" \ |
| 247 | --end_timestamp="$(date +%s.%N)" \ |
| 248 | --tool_args="$*" \ |
| 249 | --exit_code="${exit_code}" \ |
| 250 | ${ANDROID_TOOL_LOGGER_EXTRA_ARGS} \ |
| 251 | > /dev/null 2>&1 & |
| 252 | exit ${exit_code} |
| 253 | ' SIGINT SIGTERM SIGQUIT EXIT |
| 254 | } |
| Joe Onorato | 344e404 | 2022-12-05 15:15:36 -0800 | [diff] [blame] | 255 | |
| Joe Onorato | 029c50a | 2024-12-09 09:38:01 -0800 | [diff] [blame] | 256 | # Import the build variables supplied as arguments into this shell's environment. |
| 257 | # For absolute variables, prefix the variable name with a '/'. For example: |
| 258 | # import_build_vars OUT_DIR DIST_DIR /HOST_OUT_EXECUTABLES |
| 259 | # Returns nonzero if the build command failed. Stderr is passed through. |
| 260 | function import_build_vars() |
| 261 | { |
| 262 | require_top |
| 263 | local script |
| 264 | script=$(cd $TOP && build/soong/bin/get_build_vars "$@") |
| 265 | local ret=$? |
| 266 | if [ $ret -ne 0 ] ; then |
| 267 | return $ret |
| 268 | fi |
| 269 | eval "$script" |
| 270 | return $? |
| 271 | } |
| Martin Simard | 49706bf | 2025-07-07 10:27:00 -0700 | [diff] [blame] | 272 | |
| 273 | function cartfs_mount_point() { |
| Martin Simard | de9366e | 2025-09-12 07:56:42 -0700 | [diff] [blame] | 274 | # Make sure findmnt is installed. |
| 275 | if ! command -v findmnt &> /dev/null; then |
| 276 | return |
| 277 | fi |
| 278 | |
| Martin Simard | 96c7e3e | 2025-07-08 09:06:20 -0700 | [diff] [blame] | 279 | local cartfs_user_id="$(id -u cartfs 2>/dev/null)" |
| 280 | local cartfs_mount_point="$(findmnt -t fuse -O "user_id=${cartfs_user_id}" | tail -n +2 | awk '{print $1}')" |
| 281 | # Making sure $cartfs_user_id is not empty since findmnt will return mounts |
| 282 | # started by root when it is. |
| 283 | if [[ -n "$cartfs_user_id" ]] && [[ -n "$cartfs_mount_point" ]] && findmnt "$cartfs_mount_point" >/dev/null 2>&1; then |
| Martin Simard | 49706bf | 2025-07-07 10:27:00 -0700 | [diff] [blame] | 284 | echo "$cartfs_mount_point" |
| Martin Simard | 49706bf | 2025-07-07 10:27:00 -0700 | [diff] [blame] | 285 | fi |
| 286 | } |
| 287 | |
| 288 | # Deletes cartfs folders that are mapped to deleted workspaces. |
| 289 | function clean_deleted_workspaces_in_cartfs() { |
| 290 | local cartfs_mount_point=$(cartfs_mount_point) |
| 291 | if [[ -n "$cartfs_mount_point" ]]; then |
| 292 | local folders_list |
| 293 | folders_list=$(find "$cartfs_mount_point" -maxdepth 1 -type d) |
| 294 | if [[ -n "$folders_list" ]]; then |
| Martin Simard | 96c7e3e | 2025-07-08 09:06:20 -0700 | [diff] [blame] | 295 | local log_file="${HOME}/.cartfs/cartfs_workspace_deletion.log" |
| 296 | mkdir -p "$(dirname "${log_file}")" |
| Martin Simard | 49706bf | 2025-07-07 10:27:00 -0700 | [diff] [blame] | 297 | while read -r folder; do |
| 298 | if [[ "$folder" != "$cartfs_mount_point" ]]; then |
| 299 | local workspace_name="$(basename "${folder}")" |
| 300 | local workspaces_path="$(dirname "$(dirname "${top}")")" |
| 301 | local full_path="${workspaces_path}/${workspace_name}" |
| 302 | if [[ ! -d "${full_path}" ]]; then |
| Martin Simard | 96c7e3e | 2025-07-08 09:06:20 -0700 | [diff] [blame] | 303 | local log_timestamp=$(date +"%Y-%m-%d %H:%M:%S") |
| 304 | echo "${log_timestamp}: The workspace ${workspace_name} does not exist, deleting ${folder} from cartfs" >> "${log_file}" |
| Martin Simard | 49706bf | 2025-07-07 10:27:00 -0700 | [diff] [blame] | 305 | rm -Rf "${folder}" |
| 306 | fi |
| 307 | fi |
| 308 | done <<< "$folders_list" |
| 309 | fi |
| 310 | fi |
| 311 | } |