Changeset 245364 in webkit
- Timestamp:
- May 15, 2019 3:39:57 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 9 added
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/Scripts/check-xcfilelists.sh
r244987 r245364 9 9 10 10 SCRIPT="${BUILD_SCRIPTS_DIR}/generate-xcfilelists" 11 [ -f "${SCRIPT}" ] || SCRIPT="${PROJECT_DIR}/../../../${WK_ADDITIONAL_SCRIPTS_DIR}/generate-xcfilelists" 11 12 [ -f "${SCRIPT}" ] || SCRIPT="${PROJECT_DIR}/../../Tools/Scripts/generate-xcfilelists" 12 13 [ -f "${SCRIPT}" ] || { echo "### Cannot find generate-xcfilelists script"; exit 1; } -
trunk/Source/WebCore/Scripts/check-xcfilelists.sh
r244987 r245364 9 9 10 10 SCRIPT="${BUILD_SCRIPTS_DIR}/generate-xcfilelists" 11 [ -f "${SCRIPT}" ] || SCRIPT="${PROJECT_DIR}/../../../${WK_ADDITIONAL_SCRIPTS_DIR}/generate-xcfilelists" 11 12 [ -f "${SCRIPT}" ] || SCRIPT="${PROJECT_DIR}/../../Tools/Scripts/generate-xcfilelists" 12 13 [ -f "${SCRIPT}" ] || { echo "### Cannot find generate-xcfilelists script"; exit 1; } -
trunk/Source/WebKit/Scripts/check-xcfilelists.sh
r244987 r245364 9 9 10 10 SCRIPT="${BUILD_SCRIPTS_DIR}/generate-xcfilelists" 11 [ -f "${SCRIPT}" ] || SCRIPT="${PROJECT_DIR}/../../../${WK_ADDITIONAL_SCRIPTS_DIR}/generate-xcfilelists" 11 12 [ -f "${SCRIPT}" ] || SCRIPT="${PROJECT_DIR}/../../Tools/Scripts/generate-xcfilelists" 12 13 [ -f "${SCRIPT}" ] || { echo "### Cannot find generate-xcfilelists script"; exit 1; } -
trunk/Tools/ChangeLog
r245359 r245364 1 2019-05-15 Keith Rollin <krollin@apple.com> 2 3 Rewrite generate-xcfilelists in Python 4 https://bugs.webkit.org/show_bug.cgi?id=197622 5 <rdar://problem/50508222> 6 7 Reviewed by Jonathan Bedard, Alex Christensen. 8 9 For a number of reasons, rewrite generate-xcfilelists in Python: 10 11 - The previous bash script was large and unmaintainable. 12 - We have more internal expertise with Python than with bash. 13 - The bash script used temporary files in /tmp that got stranded and 14 were owned by root, making them awkward to clear out. 15 <rdar://problem/49490262> 16 - We needed to complete support for engineers that built with Xcode 17 rather than the command line. 18 - There are some bugs leading to mildly corrupted .xcfilelist files. 19 It's not apparent the source of the bugs, but one general reason 20 might be due to approaches born of using bash. Rewriting in Python 21 may clear these up. 22 23 * Scripts/generate-xcfilelists: 24 * Scripts/webkitpy/common/attribute_saver.py: Added. 25 (AttributeSaver): 26 (AttributeSaver.__init__): 27 (AttributeSaver.__enter__): 28 (AttributeSaver.__exit__): 29 * Scripts/webkitpy/common/attribute_saver_unittest.py: Added. 30 (AttributeSaverTest): 31 (AttributeSaverTest.SimpleTestClass): 32 (AttributeSaverTest.SimpleTestClass.__init__): 33 (AttributeSaverTest.test_class): 34 (AttributeSaverTest.test_normal_default): 35 (AttributeSaverTest.test_normal_value): 36 (AttributeSaverTest.test_normal_value_on_exception): 37 (AttributeSaverTest.test_normal_value_on_normal_exit): 38 (AttributeSaverTest.test_normal_value_with_finally_on_exception): 39 (AttributeSaverTest.test_normal_value_with_finally_on_normal_exit): 40 (AttributeSaverTest.test_normal_value_with_else_on_exception): 41 (AttributeSaverTest.test_normal_value_with_else_on_normal_exit): 42 * Scripts/webkitpy/generate_xcfilelists_lib/__init__.py: Added. 43 * Scripts/webkitpy/generate_xcfilelists_lib/application.py: Added. 44 (Application): 45 (Application.__init__): 46 (Application.run): 47 (Application._initialize): 48 (Application._initialize.collect_attributes): 49 (Application._create_parser): 50 (_validate_args): 51 (_cmd_generate): 52 (_cmd_check): 53 (_cmd_subgenerate): 54 (_cmd_help): 55 (_do_generate): 56 (_do_merge): 57 (_report_results): 58 (_report_merge_results): 59 (_report_remediation_steps): 60 (_report_remediation_steps.add_to_message): 61 (_any_have_errors): 62 (_any_have_actions): 63 (_log_progress): 64 (_log_results): 65 (get_generate_xcfilelists_script_path): 66 (_get_root_dir): 67 (get_opensource_dir): 68 (get_build_scripts_dir): 69 (get_extract_dependencies_from_makefile_script): 70 (get_xcode_built_products_dir): 71 (_getenv): 72 * Scripts/webkitpy/generate_xcfilelists_lib/generators.py: Added. 73 (BaseGenerator): 74 (BaseGenerator.__init__): 75 (BaseGenerator.__str__): 76 (BaseGenerator.generate): 77 (BaseGenerator._sublaunch_under_xcode): 78 (BaseGenerator.subgenerate): 79 (BaseGenerator.merge): 80 (BaseGenerator.pickle_to_file): 81 (BaseGenerator.has_action): 82 (BaseGenerator.has_error): 83 (BaseGenerator.is_valid): 84 (BaseGenerator.report_error): 85 (BaseGenerator._generate_derived): 86 (BaseGenerator._merge_derived): 87 (BaseGenerator._generate_unified): 88 (BaseGenerator._merge_unified): 89 (BaseGenerator._replace): 90 (BaseGenerator._unexpand): 91 (BaseGenerator._find_added_lines): 92 (BaseGenerator._merge_added_lines): 93 (BaseGenerator._get_file_lines): 94 (BaseGenerator._getenv): 95 (BaseGenerator._get_project_file_path): 96 (BaseGenerator._get_project_dir): 97 (BaseGenerator._get_project_file_name): 98 (BaseGenerator._get_project_name): 99 (BaseGenerator._get_sym_root): 100 (BaseGenerator._get_obj_root): 101 (BaseGenerator._get_shared_precomps_dir): 102 (BaseGenerator._get_build_dirs): 103 (BaseGenerator._get_build_dirs.define_xcode_build_dirs): 104 (BaseGenerator._get_build_dirs.define_xcode_build_dirs.read_xcode_user_default): 105 (BaseGenerator._get_build_dirs.define_command_line_build_dirs): 106 (BaseGenerator._get_derived_sources_dir): 107 (BaseGenerator._get_xcfilelist_dir): 108 (BaseGenerator._get_input_derived_xcfilelist_project_path): 109 (BaseGenerator._get_output_derived_xcfilelist_project_path): 110 (BaseGenerator._get_input_unified_xcfilelist_project_path): 111 (BaseGenerator._get_output_unified_xcfilelist_project_path): 112 (BaseGenerator._get_generate_derived_sources_script): 113 (BaseGenerator._get_generate_unified_sources_script): 114 (JavaScriptCoreGenerator): 115 (JavaScriptCoreGenerator._get_project_file_path): 116 (JavaScriptCoreGenerator._get_generate_derived_sources_script): 117 (JavaScriptCoreGenerator._get_generate_unified_sources_script): 118 (WebCoreGenerator): 119 (WebCoreGenerator._get_project_file_path): 120 (WebCoreGenerator._get_generate_derived_sources_script): 121 (WebCoreGenerator._get_generate_unified_sources_script): 122 (WebKitGenerator): 123 (WebKitGenerator._get_project_file_path): 124 (WebKitGenerator._get_derived_sources_dir): 125 (WebKitGenerator._get_generate_derived_sources_script): 126 (WebKitGenerator._get_generate_unified_sources_script): 127 (DumpRenderTreeGenerator): 128 (DumpRenderTreeGenerator._get_project_file_path): 129 (DumpRenderTreeGenerator._get_generate_derived_sources_script): 130 (WebKitTestRunnerGenerator): 131 (WebKitTestRunnerGenerator._get_project_file_path): 132 (WebKitTestRunnerGenerator._get_generate_derived_sources_script): 133 * Scripts/webkitpy/generate_xcfilelists_lib/util.py: Added. 134 (debug_log): 135 (LogEntryHelper): 136 (LogEntryHelper.__init__): 137 (LogEntryHelper.log_entry): 138 (LogEntryHelper.log_result): 139 (LogEntryHelper.log_exception): 140 (LogEntryHelper._print): 141 (LogEntryExit): 142 (LogEntryExit._show_debug_logging): 143 (LogEntryExitClass): 144 (LogEntryExitClass._show_debug_logging): 145 (LogEntryExitGlobal): 146 (LogEntryExitGlobal._show_debug_logging): 147 (subprocess_run): 148 (is_running_under_xcode): 149 (CheckValidItemAction): 150 (CheckValidItemAction.__init__): 151 (CheckValidItemAction.__call__): 152 (CheckValidItemAction.validate_item): 153 (CheckCommandAction): 154 (CheckCommandAction.__call__): 155 (InvalidCommandError): 156 (InvalidArgumentError): 157 (InvalidConfigurationError): 158 (CalledProcessError): 159 (CalledProcessError.__str__): 160 * Scripts/webkitpy/xcode/__init__.py: 161 (xcode_hash_for_path): 162 (xcode_hash_for_path.convert_to_string): 163 * Scripts/webkitpy/xcode/sdk.py: Added. 164 (SDK): 165 (SDK.__init__): 166 (SDK.__repr__): 167 (SDK.as_xcode_specification): 168 (SDK.get_preferred_sdk_for_platform): 169 (SDK._parse_sdk): 170 * Scripts/webkitpy/xcode/sdk_unittest.py: Added. 171 (SDKTest): 172 1 173 2019-05-15 Aakash Jain <aakash_jain@apple.com> 2 174 -
trunk/Tools/DumpRenderTree/Scripts/check-xcfilelists.sh
r244987 r245364 9 9 10 10 SCRIPT="${BUILD_SCRIPTS_DIR}/generate-xcfilelists" 11 [ -f "${SCRIPT}" ] || SCRIPT="${PROJECT_DIR}/../../../${WK_ADDITIONAL_SCRIPTS_DIR}/generate-xcfilelists" 11 12 [ -f "${SCRIPT}" ] || SCRIPT="${PROJECT_DIR}/../../Tools/Scripts/generate-xcfilelists" 12 13 [ -f "${SCRIPT}" ] || { echo "### Cannot find generate-xcfilelists script"; exit 1; } -
trunk/Tools/Scripts/generate-xcfilelists
r243527 r245364 1 #!/bin/bash 1 #!/usr/bin/env python 2 # -*- coding: utf-8 -*- 2 3 # 3 # Copyright (C) 201 8-2019 Apple Inc. All rights reserved.4 # Copyright (C) 2019 Apple Inc. All rights reserved. 4 5 # 5 6 # Redistribution and use in source and binary forms, with or without … … 48 49 # As part of its operation, this script can sub-launch itself under Xcode. It 49 50 # does this in order to establish the context in which builds occur. In 50 # particular, it does this in order to set needed environment variables. In 51 # order to protect against environment variable name collision, all variable 52 # names in this script start with "GX_". 51 # particular, it does this in order to set needed environment variables. 53 52 53 import sys 54 54 55 function stdout() 56 { 57 (( ${GX_QUIET} )) || echo "$@" >&1 58 } 55 from webkitpy.generate_xcfilelists_lib.application import Application 56 from webkitpy.port.config import apple_additions 59 57 60 61 function stderr() 62 { 63 echo "$@" >&2 64 } 65 66 67 function remove_extra_spaces() 68 { 69 echo $1 70 } 71 72 function print_option() 73 { 74 local GX_OPTION="$1" 75 local GX_MESSAGE="$(remove_extra_spaces "$2")" 76 77 local GX_LINE 78 local GX_LINE_WIDTH=90 79 local GX_OPTION_WIDTH=17 80 81 if (( ${#GX_OPTION} <= GX_OPTION_WIDTH )) 82 then 83 local GX_MESSAGE_CATENATED=$(printf " %-${GX_OPTION_WIDTH}s %s" "$GX_OPTION" "$GX_MESSAGE") 84 if (( ${#GX_MESSAGE_CATENATED} <= GX_LINE_WIDTH )) 85 then 86 stderr "${GX_MESSAGE_CATENATED}" 87 return 88 fi 89 90 local GX_MESSAGE_FIRST_LINE="${GX_MESSAGE_CATENATED:0:${GX_LINE_WIDTH}}" # Get the first 80 characters 91 GX_MESSAGE_FIRST_LINE="${GX_MESSAGE_FIRST_LINE% *}" # Trim back to the last space 92 GX_MESSAGE="${GX_MESSAGE_CATENATED:${#GX_MESSAGE_FIRST_LINE}+1}" # Get the rest after that space 93 94 stderr "${GX_MESSAGE_FIRST_LINE}" 95 else 96 stderr " ${GX_OPTION}" 97 fi 98 99 while IFS='' read -r GX_LINE 100 do 101 GX_LINE=$(printf " %${GX_OPTION_WIDTH}s %s" "" "$GX_LINE") 102 stderr "${GX_LINE}" 103 done < <(echo "${GX_MESSAGE}" | fold -w $(( GX_LINE_WIDTH - GX_OPTION_WIDTH - 3)) -s) 104 } 105 106 107 function join_by() 108 { 109 local GX_DELIM=$1 110 shift 111 112 echo -n "$1" 113 shift 114 115 printf "%s" "${@/#/${GX_DELIM}}" 116 } 117 118 119 function usage() 120 { 121 local GX_JOINED_PROJECT_TAGS=$(join_by ", " "${GX_PROJECT_TAGS[@]}") 122 123 stderr "Usage: $(basename "${GX_ME}") [OPTION...] COMMAND [PARAMETER...]" 124 stderr "" 125 stderr "Generate or check .xcfilelist files" 126 stderr "" 127 stderr "Commands:" 128 stderr "" 129 print_option "generate" "Generate a complete and up-to-date set of 130 .xcfilelist files and copy them to their appropriate places in the 131 project directories." 132 print_option "generate-xcode" "Generate .xcfilelist files for the current 133 target configuration an copy them to their appropriate places in the 134 project directories. Invoked from withing Xcode to update the current 135 build if needed." 136 print_option "check" "Generate a complete and up-to-date set of .xcfilelist 137 files and compare them to their counterparts in the project 138 directories." 139 print_option "check-xcode" "Generate .xcfilelist files for the current 140 target configuration and see if any files appear that aren't in the 141 checked-in .xcfilelist files. Invoked from within Xcode to validate the 142 current build." 143 print_option "subgenerate" "Generate an .xcfilelist file for a particular 144 combination of project, platform, and configuration. This operation is 145 performed in the context of an Xcode build in order to inherit the same 146 environment as that build." 147 print_option "help" "Print this text and exit." 148 stderr "" 149 stderr "Options:" 150 stderr "" 151 print_option "--project <project>" "Specify which project for which to 152 generate .xcfilelist files or to check. Possible values are 153 (${GX_JOINED_PROJECT_TAGS}). Default is to iterate over all projects." 154 print_option "--platform <platform>" "Specify which platform for which to 155 generate .xcfilelist files or to check. Possible values are (macosx, 156 iphoneos). Default is to iterate over all platforms, filtered to those 157 platforms that a particular project supports (e.g., you can't specify 158 'iphoneos' for WebKitTestRunner)." 159 print_option "--configuration <configuration>" "Specify which configuration 160 for which to generate .xcfilelist files or to check, Possible values 161 are (release, debug). Default is to iterate over all configurations." 162 print_option "--xcode" "Specify that existing build output can be found in 163 the directory created by the Xcode IDE (in ~/Library/Developer/Xcode)." 164 print_option "--webkitbuild" "Specify that existing build output can be 165 found in the directory used by the WebKit make files or the 166 build-webkit script (that is, in WebKitBuild or in the directory 167 identified by WEBKIT_OUTPUTDIR). This option is the default, so it 168 doesn't really get you anything by specifying this option (or by my 169 implementing it)." 170 print_option "--nocleanup" "Disable cleaning up temporary files after a 171 subgenerate operation. Normally these are cleaned up, but if 172 'subgenerate' is part of an overall 'generate' operation, then the 173 'generate' operation needs to keep around the temporary files until it 174 can complete aggregating them." 175 stderr "" 176 print_option "--dry-run" "When running through the requested process, don't 177 make any material changes. For example, for 'generate', create the new 178 .xcfilelist files, but don't copy them into their final locations" 179 print_option "--debug" "Provide verbose output." 180 print_option "--quiet" "Don't print any std output." 181 print_option "--help" "Print this text and exit." 182 stderr "" 183 } 184 185 186 function cleanup() 187 { 188 if (( ${GX_DO_CLEANUP} )) && (( ${GX_DEFERRED_EXIT_CODE} == 0 )) 189 then 190 rm -rf "${GX_TEMP}" &> /dev/null 191 fi 192 } 193 194 195 function my_exit() 196 { 197 local GX_ERR=$1 198 exit $GX_ERR 199 } 200 201 202 function die() 203 { 204 local GX_ERR=$2 205 [[ "$GX_ERR" == "" ]] && GX_ERR=1 206 stderr "### (${FUNCNAME[@]}) $1" 207 my_exit $GX_ERR 208 } 209 210 211 function log_debug() 212 { 213 (( "${GX_DEBUG}" > 0 )) && stderr "GXCF: $@" 214 } 215 216 217 function log_debug_var() 218 { 219 local GX_VAR_NAME=$1 220 local GX_IS_ARRAY=$(declare -p ${GX_VAR_NAME} 2> /dev/null | grep -q '^declare -a' && echo 1 || echo 0) 221 222 if (( $GX_IS_ARRAY )) 223 then 224 log_debug $(printf "%-47s = (%s)" $GX_VAR_NAME "$(eval echo \$\{${GX_VAR_NAME}\[\@\]\})") 225 else 226 log_debug $(printf "%-47s = %s" $GX_VAR_NAME "$(eval echo \$\{${GX_VAR_NAME}\})") 227 fi 228 } 229 230 231 function log_callstack_and_parameters() 232 { 233 if (( "${GX_DEBUG}" > "1" )) 234 then 235 local GX_ARGS=("$@") 236 local GX_CALLSTACK=("${FUNCNAME[@]}") 237 unset GX_CALLSTACK[0] 238 stderr "GXCF: (${GX_CALLSTACK[@]}): ${GX_ARGS[@]}" 239 fi 240 } 241 242 243 function log_progress() 244 { 245 stdout "GXCF: $@" 246 } 247 248 249 function log_progress_long() 250 { 251 local GX_MESSAGE="$(remove_extra_spaces "$1")" 252 local GX_LINE 253 while IFS='' read -r GX_LINE 254 do 255 log_progress $GX_LINE 256 done < <(echo "${GX_MESSAGE}" | fold -w 86 -s) 257 } 258 259 260 function normalize_directory_path() 261 { 262 log_callstack_and_parameters "$@" 263 264 [[ -z "$1" ]] && { echo "$1"; return; } 265 cd "$1" 2> /dev/null || { echo "$1"; return; } 266 pwd -P 267 } 268 269 270 function normalize_file_path() 271 { 272 log_callstack_and_parameters "$@" 273 274 [[ -z "$1" ]] && { echo "$1"; return; } 275 echo $(normalize_directory_path "$(dirname "$1")")/$(basename "$1") 276 } 277 278 279 function call() 280 { 281 log_callstack_and_parameters "$@" 282 283 local GX_FN="$1" 284 [[ "$(type -t ${GX_FN})" == "function" ]] || return $? 285 eval "${GX_FN}" 286 } 287 288 289 function set_project_specific_settings_for_JavaScriptCore() 290 { 291 log_callstack_and_parameters "$@" 292 293 GX_PS_PROJECT_FILE_PATH="${GX_OPENSOURCE_DIR}/Source/JavaScriptCore/JavaScriptCore.xcodeproj" # Can't use PROJECT_FILE_PATH because this is used pre-Xcode. 294 GX_PS_DERIVEDSOURCES_GENERATOR_RELATIVE_PATH="Scripts/generate-derived-sources.sh" 295 GX_PS_UNIFIEDSOURCES_GENERATOR_RELATIVE_PATH="Scripts/generate-unified-sources.sh" 296 GX_PS_PLATFORM_NAMES=(macosx iphoneos) 297 } 298 299 300 function set_project_specific_settings_for_WebCore() 301 { 302 log_callstack_and_parameters "$@" 303 304 GX_PS_PROJECT_FILE_PATH="${GX_OPENSOURCE_DIR}/Source/WebCore/WebCore.xcodeproj" # Can't use PROJECT_FILE_PATH because this is used pre-Xcode. 305 GX_PS_DERIVEDSOURCES_GENERATOR_RELATIVE_PATH="Scripts/generate-derived-sources.sh" 306 GX_PS_UNIFIEDSOURCES_GENERATOR_RELATIVE_PATH="Scripts/generate-unified-sources.sh" 307 GX_PS_PLATFORM_NAMES=(macosx iphoneos) 308 } 309 310 311 function set_project_specific_settings_for_WebKit() 312 { 313 log_callstack_and_parameters "$@" 314 315 GX_PS_PROJECT_FILE_PATH="${GX_OPENSOURCE_DIR}/Source/WebKit/WebKit.xcodeproj" # Can't use PROJECT_FILE_PATH because this is used pre-Xcode. 316 GX_PS_DERIVED_SOURCES_DIR="${BUILT_PRODUCTS_DIR}/DerivedSources/WebKit2" 317 GX_PS_DERIVEDSOURCES_GENERATOR_RELATIVE_PATH="Scripts/generate-derived-sources.sh" 318 GX_PS_UNIFIEDSOURCES_GENERATOR_RELATIVE_PATH="Scripts/generate-unified-sources.sh" 319 GX_PS_PLATFORM_NAMES=(macosx iphoneos) 320 } 321 322 323 function set_project_specific_settings_for_DumpRenderTree() 324 { 325 log_callstack_and_parameters "$@" 326 327 GX_PS_PROJECT_FILE_PATH="${GX_OPENSOURCE_DIR}/Tools/DumpRenderTree/DumpRenderTree.xcodeproj" # Can't use PROJECT_FILE_PATH because this is used pre-Xcode. 328 GX_PS_DERIVEDSOURCES_GENERATOR_RELATIVE_PATH="Scripts/generate-derived-sources.sh" 329 GX_PS_PLATFORM_NAMES=(macosx) 330 } 331 332 333 function set_project_specific_settings_for_WebKitTestRunner() 334 { 335 log_callstack_and_parameters "$@" 336 337 GX_PS_PROJECT_FILE_PATH="${GX_OPENSOURCE_DIR}/Tools/WebKitTestRunner/WebKitTestRunner.xcodeproj" # Can't use PROJECT_FILE_PATH because this is used pre-Xcode. 338 GX_PS_DERIVEDSOURCES_GENERATOR_RELATIVE_PATH="Scripts/generate-derived-sources.sh" 339 GX_PS_PLATFORM_NAMES=(macosx) 340 } 341 342 343 function set_project_specific_settings() 344 { 345 log_callstack_and_parameters "$@" 346 347 # Unset the variables that the set_project_specific_settings_for_FOO 348 # functions set. We need to do this in case the function for project BAR 349 # doesn't define one or more of them, causing it to inherit the settings 350 # for a previous project FOO. 351 # 352 # To achieve this unsetting, we prefix all the variables we want to unset 353 # with "GX_PS_" ("PS for "project specific"). We can then gather all 354 # variables that start with this prefix and unset them. 355 356 unset ${!GX_PS_*} 357 358 [[ -n "${GX_PROJECT_TAG}" ]] || die "GX_PROJECT_TAG is not defined." 359 360 call set_project_specific_settings_for_${GX_PROJECT_TAG} || die "Could not set build variables for ${GX_PROJECT_TAG}." 361 } 362 363 364 function set_common_project_settings() 365 { 366 log_callstack_and_parameters "$@" 367 368 local GX_EFFECTIVE_PROJECT_FILE_PATH="${GX_PS_PROJECT_FILE_PATH}" 369 local GX_EFFECTIVE_PROJECT_DIR=$(dirname "${GX_EFFECTIVE_PROJECT_FILE_PATH}") 370 371 [[ -n "${GX_EFFECTIVE_PROJECT_FILE_PATH}" ]] || die "GX_EFFECTIVE_PROJECT_FILE_PATH is not defined." 372 [[ -d "${GX_EFFECTIVE_PROJECT_FILE_PATH}" ]] || die "${GX_EFFECTIVE_PROJECT_FILE_PATH} is not a directory." 373 [[ -n "${GX_EFFECTIVE_PROJECT_DIR}" ]] || die "GX_EFFECTIVE_PROJECT_DIR is not defined." 374 [[ -d "${GX_EFFECTIVE_PROJECT_DIR}" ]] || die "${GX_EFFECTIVE_PROJECT_DIR} is not a directory." 375 376 # Get the paths to the scripts that drive the generation of the 377 # .xcfilelists or the data going into the .xcfilelists. 378 379 GX_DERIVEDSOURCES_GENERATOR="${GX_PS_DERIVEDSOURCES_GENERATOR_RELATIVE_PATH:+${GX_EFFECTIVE_PROJECT_DIR}/${GX_PS_DERIVEDSOURCES_GENERATOR_RELATIVE_PATH}}" 380 GX_UNIFIEDSOURCES_GENERATOR="${GX_PS_UNIFIEDSOURCES_GENERATOR_RELATIVE_PATH:+${GX_EFFECTIVE_PROJECT_DIR}/${GX_PS_UNIFIEDSOURCES_GENERATOR_RELATIVE_PATH}}" 381 382 [[ -n "${GX_DERIVEDSOURCES_GENERATOR}" ]] && { [[ -f "${GX_DERIVEDSOURCES_GENERATOR}" ]] || die "${GX_DERIVEDSOURCES_GENERATOR} does not exist."; } 383 [[ -n "${GX_UNIFIEDSOURCES_GENERATOR}" ]] && { [[ -f "${GX_UNIFIEDSOURCES_GENERATOR}" ]] || die "${GX_UNIFIEDSOURCES_GENERATOR} does not exist."; } 384 385 # Get the paths to the locations of the final .xcfilelist files. 386 387 local GX_BASE_PATH="${GX_EFFECTIVE_PROJECT_DIR}/${GX_PS_XCFILELIST_RELATIVE_PATH}" 388 GX_INPUT_DERIVED_XCFILELIST_PROJECT_PATH="${GX_BASE_PATH}/DerivedSources-input.xcfilelist" 389 GX_OUTPUT_DERIVED_XCFILELIST_PROJECT_PATH="${GX_BASE_PATH}/DerivedSources-output.xcfilelist" 390 GX_OUTPUT_UNIFIED_XCFILELIST_PROJECT_PATH="${GX_BASE_PATH}/UnifiedSources-output.xcfilelist" 391 392 # Get the paths to the locations of the temporary .xcfilelist files (the 393 # ones being built up before being moved to their final locations). 394 395 GX_INPUT_DERIVED_XCFILELIST_PROJECT_TEMP_PATH="${GX_TEMP}/${GX_INPUT_DERIVED_XCFILELIST_PROJECT_PATH}" 396 GX_OUTPUT_DERIVED_XCFILELIST_PROJECT_TEMP_PATH="${GX_TEMP}/${GX_OUTPUT_DERIVED_XCFILELIST_PROJECT_PATH}" 397 GX_OUTPUT_UNIFIED_XCFILELIST_PROJECT_TEMP_PATH="${GX_TEMP}/${GX_OUTPUT_UNIFIED_XCFILELIST_PROJECT_PATH}" 398 399 # Collect the default per-project commands to execute during the generate, 400 # merge, and compare stages. 401 402 GX_SUBGENERATE_ACTIONS=() 403 GX_MERGE_ACTIONS=() 404 GX_CHECK_ACTIONS=() 405 406 if [[ -n "${GX_DERIVEDSOURCES_GENERATOR}" ]] 407 then 408 GX_SUBGENERATE_ACTIONS+=(generate_derivedsources_xcfilelists) 409 GX_MERGE_ACTIONS+=(merge_derivedsources_xcfilelists) 410 GX_CHECK_ACTIONS+=(check_derivedsources_xcfilelists) 411 fi 412 413 if [[ -n "${GX_UNIFIEDSOURCES_GENERATOR}" ]] 414 then 415 GX_SUBGENERATE_ACTIONS+=(generate_unifiedsources_xcfilelists) 416 GX_MERGE_ACTIONS+=(merge_unifiedsources_xcfilelists) 417 GX_CHECK_ACTIONS+=(check_unifiedsources_xcfilelists) 418 fi 419 420 [[ -z "${GX_PS_DERIVED_SOURCES_DIR}" ]] && GX_PS_DERIVED_SOURCES_DIR="${BUILT_PRODUCTS_DIR}/DerivedSources/${PROJECT_NAME}" 421 422 GX_TEMP_INPUT_XCFILELIST="${GX_TEMP}/input.xcfilelist" 423 GX_TEMP_OUTPUT_XCFILELIST="${GX_TEMP}/output.xcfilelist" 424 } 425 426 427 function dump_project_settings() 428 { 429 log_callstack_and_parameters "$@" 430 431 log_debug_var BUILD_SCRIPTS_DIR 432 log_debug_var BUILT_PRODUCTS_DIR 433 log_debug_var CONFIGURATION 434 log_debug_var DERIVED_SOURCES_DIR 435 log_debug_var JAVASCRIPTCORE_PRIVATE_HEADERS_DIR 436 log_debug_var PROJECT_DIR 437 log_debug_var PROJECT_FILE_PATH 438 log_debug_var PROJECT_NAME 439 log_debug_var WEBCORE_PRIVATE_HEADERS_DIR 440 log_debug_var WEBKIT2_PRIVATE_HEADERS_DIR 441 log_debug 442 log_debug_var GX_PS_PROJECT_FILE_PATH 443 log_debug_var GX_PS_DERIVEDSOURCES_GENERATOR_RELATIVE_PATH 444 log_debug_var GX_PS_UNIFIEDSOURCES_GENERATOR_RELATIVE_PATH 445 log_debug_var GX_PS_XCFILELIST_RELATIVE_PATH 446 log_debug_var GX_PS_PLATFORM_NAMES 447 log_debug 448 log_debug_var GX_PROJECT_TAG 449 log_debug_var GX_PLATFORM_NAME 450 log_debug_var GX_CONFIGURATION 451 log_debug 452 log_debug_var GX_EFFECTIVE_PROJECT_FILE_PATH 453 log_debug_var GX_EFFECTIVE_PROJECT_DIR 454 log_debug 455 log_debug_var GX_DERIVEDSOURCES_GENERATOR 456 log_debug_var GX_UNIFIEDSOURCES_GENERATOR 457 log_debug 458 log_debug_var GX_INPUT_DERIVED_XCFILELIST_PROJECT_TEMP_PATH 459 log_debug_var GX_OUTPUT_DERIVED_XCFILELIST_PROJECT_TEMP_PATH 460 log_debug_var GX_OUTPUT_UNIFIED_XCFILELIST_PROJECT_TEMP_PATH 461 log_debug 462 log_debug_var GX_INPUT_DERIVED_XCFILELIST_PROJECT_PATH 463 log_debug_var GX_OUTPUT_DERIVED_XCFILELIST_PROJECT_PATH 464 log_debug_var GX_OUTPUT_UNIFIED_XCFILELIST_PROJECT_PATH 465 log_debug 466 log_debug_var GX_PS_DERIVED_SOURCES_DIR 467 log_debug 468 log_debug_var GX_SUBGENERATE_ACTIONS 469 log_debug_var GX_MERGE_ACTIONS 470 log_debug_var GX_CHECK_ACTIONS 471 } 472 473 474 function set_project_settings() 475 { 476 log_callstack_and_parameters "$@" 477 478 [[ -z "${GX_PROJECT_TAG}" ]] && return 479 480 set_project_specific_settings 481 set_common_project_settings 482 dump_project_settings 483 } 484 485 486 function ensure_directories_exist() 487 { 488 log_callstack_and_parameters "$@" 489 490 local GX_DIR 491 for GX_DIR in "$@" 492 do 493 log_debug "Creating ${GX_DIR}" 494 mkdir -p "${GX_DIR}" &> /dev/null || die "Unable to create "${GX_DIR}"." 495 done 496 } 497 498 499 function create_empty_files() 500 { 501 log_callstack_and_parameters "$@" 502 503 local GX_FILE 504 for GX_FILE in "$@" 505 do 506 ensure_directories_exist "$(dirname "${GX_FILE}")" 507 508 log_debug "Creating ${GX_FILE}" 509 echo -n '' > "${GX_FILE}" 510 done 511 } 512 513 514 function append_xcfilelist_header() 515 { 516 log_callstack_and_parameters "$@" 517 518 local GX_FILE 519 for GX_FILE in "$@" 520 do 521 echo '# This file is generated by the generate-xcfilelists script.' >> "${GX_FILE}" 522 done 523 } 524 525 526 function sort_and_unique_in_place() 527 { 528 sort -u "$1" -o "$1" 529 } 530 531 532 function replace() 533 { 534 log_callstack_and_parameters "$@" 535 536 local GX_FILE="$1" 537 local GX_PATTERN="$2" 538 local GX_REPLACEMENT="$3" 539 540 [[ -n "${GX_FILE}" ]] || die "GX_FILE is not defined." 541 [[ -f "${GX_FILE}" ]] || die "${GX_FILE} does not exist." 542 543 sed -E -e "s|${GX_PATTERN}|${GX_REPLACEMENT}|" -i '' "${GX_FILE}" 544 } 545 546 547 function unexpand() 548 { 549 log_callstack_and_parameters "$@" 550 551 local GX_FILE="$1" 552 local GX_VAR="$2" 553 local GX_VALUE=$(eval echo \$${GX_VAR}) 554 555 [[ -n "${GX_VALUE}" ]] && replace "${GX_FILE}" "^${GX_VALUE}/" "\$\($GX_VAR\)/" 556 } 557 558 559 function find_additions() 560 { 561 # Find additions and removals so that we can report them. 562 # 563 # UPDATE: We can't really report removals. It's possible -- even 564 # overwhelmingly likely -- that we are generating .xcfilelist information 565 # for only a subset of the possible configurations for which we build. For 566 # example, a developer may be building for macOS and iOS, but not watchOS. 567 # In situations like this, we'll be generating the .xcfilelist for those 568 # two platforms, but any files specific to watchOS will not be discovered 569 # and won't be included in the .xcfilelists. If we were to report those 570 # watchOS files as files that should be removed from the .xcfilelists, then 571 # the watchOS build may fail. So, for now, let any obsolete files 572 # accumulate in the .xcfilelist files; they're mostly harmless. 573 574 local GX_NEW="$1" 575 local GX_ORIG="$2" 576 local GX_ADDITIONS="$3" 577 578 [[ -f "${GX_NEW}" ]] || die "${GX_NEW} does not exist." 579 [[ -f "${GX_ORIG}" ]] || die "${GX_ORIG} does not exist." 580 581 comm -2 -3 <(sort "${GX_NEW}") <(sort "${GX_ORIG}") > "${GX_ADDITIONS}" 582 } 583 584 585 function get_sdks() 586 { 587 log_callstack_and_parameters "$@" 588 589 (( ${#GX_SDKS[@]} )) && return 590 591 GX_SDKS=($( 592 xcodebuild -showsdks \ 593 | grep -e '\s-sdk\s' \ 594 | sed -E \ 595 -e 's/.*-sdk ([^[:digit:]]+)$/\1/' \ 596 -e 's/.*-sdk ([^[:digit:]]+)([[:digit:]\.]+)$/\1/' \ 597 -e 's/.*-sdk ([^[:digit:]]+)([[:digit:]\.]+)([^[:digit:]]+)$/\1.\3/' \ 598 | sort -u 599 )) 600 601 (( ${#GX_SDKS[@]} )) || die "Unable to find any SDKs." 602 } 603 604 605 function get_canonical_configuration() 606 { 607 log_callstack_and_parameters "$@" 608 609 local GX_PROVISIONAL_CONFIGURATION=$(echo "$1" | tr '[:upper:]' '[:lower:]') 610 local GX_RESULT=$2 611 612 [[ "${GX_PROVISIONAL_CONFIGURATION}" == "" ]] && { eval $GX_RESULT=""; return; } 613 614 [[ "${GX_PROVISIONAL_CONFIGURATION}" == "debug" ]] && { eval $GX_RESULT="Debug"; return; } 615 [[ "${GX_PROVISIONAL_CONFIGURATION}" == "release" ]] && { eval $GX_RESULT="Release"; return; } 616 [[ "${GX_PROVISIONAL_CONFIGURATION}" == "production" ]] && { eval $GX_RESULT="Production"; return; } 617 [[ "${GX_PROVISIONAL_CONFIGURATION}" == "profiling" ]] && { eval $GX_RESULT="Profiling"; return; } 618 619 die "Unrecognized configuration: $1" 620 } 621 622 623 function get_canonical_platform_name() 624 { 625 log_callstack_and_parameters "$@" 626 627 local GX_PROVISIONAL_PLATFORM_NAME=$(echo "$1" | tr '[:upper:]' '[:lower:]') 628 local GX_RESULT=$2 629 630 [[ "${GX_PROVISIONAL_PLATFORM_NAME}" == "" ]] && { eval $GX_RESULT=""; return; } 631 632 [[ "${GX_PROVISIONAL_PLATFORM_NAME}" == "ios" ]] && { eval $GX_RESULT="iphoneos"; return; } 633 [[ "${GX_PROVISIONAL_PLATFORM_NAME}" == "iphone" ]] && { eval $GX_RESULT="iphoneos"; return; } 634 [[ "${GX_PROVISIONAL_PLATFORM_NAME}" == "ipad" ]] && { eval $GX_RESULT="iphoneos"; return; } 635 [[ "${GX_PROVISIONAL_PLATFORM_NAME}" == "iphoneos" ]] && { eval $GX_RESULT="iphoneos"; return; } 636 [[ "${GX_PROVISIONAL_PLATFORM_NAME}" == "iphonesimulator" ]] && { eval $GX_RESULT="iphonesimulator"; return; } 637 638 [[ "${GX_PROVISIONAL_PLATFORM_NAME}" == "mac" ]] && { eval $GX_RESULT="macosx"; return; } 639 [[ "${GX_PROVISIONAL_PLATFORM_NAME}" == "osx" ]] && { eval $GX_RESULT="macosx"; return; } 640 [[ "${GX_PROVISIONAL_PLATFORM_NAME}" == "macos" ]] && { eval $GX_RESULT="macosx"; return; } 641 [[ "${GX_PROVISIONAL_PLATFORM_NAME}" == "macosx" ]] && { eval $GX_RESULT="macosx"; return; } 642 643 [[ "${GX_PROVISIONAL_PLATFORM_NAME}" == "tvos" ]] && { eval $GX_RESULT="appletvos"; return; } 644 [[ "${GX_PROVISIONAL_PLATFORM_NAME}" == "appletvos" ]] && { eval $GX_RESULT="appletvos"; return; } 645 [[ "${GX_PROVISIONAL_PLATFORM_NAME}" == "tvsimulator" ]] && { eval $GX_RESULT="appletvsimulator"; return; } 646 [[ "${GX_PROVISIONAL_PLATFORM_NAME}" == "appletvsimulator" ]] && { eval $GX_RESULT="appletvsimulator"; return; } 647 648 [[ "${GX_PROVISIONAL_PLATFORM_NAME}" == "watchos" ]] && { eval $GX_RESULT="watchos"; return; } 649 [[ "${GX_PROVISIONAL_PLATFORM_NAME}" == "watchsimulator" ]] && { eval $GX_RESULT="watchsimulator"; return; } 650 651 die "Unrecognized platform name: $1" 652 } 653 654 655 function get_sdk_name() 656 { 657 log_callstack_and_parameters "$@" 658 659 local GX_SDK=$1 660 local GX_RESULT=$2 661 get_canonical_platform_name "${GX_SDK}" GX_SDK 662 local GX_INTERNAL_SDK="${GX_SDK}.internal" 663 664 get_sdks 665 666 # Prefer an internal SDK if one exists. 667 668 [[ " ${GX_SDKS[@]} " =~ " ${GX_INTERNAL_SDK} " ]] && { eval $GX_RESULT="${GX_INTERNAL_SDK}"; return; } 669 [[ " ${GX_SDKS[@]} " =~ " ${GX_SDK} " ]] && { eval $GX_RESULT="${GX_SDK}"; return; } 670 671 die "Unsupported SDK: ${GX_SDK}." 672 } 673 674 675 function invoke_each_action() 676 { 677 log_callstack_and_parameters "$@" 678 679 local GX_ACTION 680 for GX_ACTION in "$@" 681 do 682 eval "${GX_ACTION}" 683 done 684 } 685 686 687 function for_each_configuration() 688 { 689 log_callstack_and_parameters "$@" 690 691 if [[ -z "${GX_CONFIGURATION}" ]] 692 then 693 for GX_CONFIGURATION in "${GX_CONFIGURATIONS[@]}" 694 do 695 eval "$@" 696 done 697 698 GX_CONFIGURATION= 699 else 700 eval "$@" 701 fi 702 } 703 704 705 function for_each_platform() 706 { 707 log_callstack_and_parameters "$@" 708 709 if [[ -z "${GX_PLATFORM_NAME}" ]] 710 then 711 for GX_PLATFORM_NAME in "${GX_PS_PLATFORM_NAMES[@]}" 712 do 713 eval "$@" 714 done 715 716 GX_PLATFORM_NAME= 717 else 718 eval "$@" 719 fi 720 } 721 722 723 function for_each_project() 724 { 725 log_callstack_and_parameters "$@" 726 727 if [[ -z "${GX_PROJECT_TAG}" ]] 728 then 729 for GX_PROJECT_TAG in "${GX_PROJECT_TAGS[@]}" 730 do 731 set_project_settings 732 eval "$@" 733 done 734 735 GX_PROJECT_TAG= 736 else 737 set_project_settings 738 eval "$@" 739 fi 740 } 741 742 743 function generate_derivedsources_xcfilelists() 744 { 745 log_callstack_and_parameters "$@" 746 747 create_empty_files "${GX_TEMP_INPUT_XCFILELIST}" "${GX_TEMP_OUTPUT_XCFILELIST}" 748 749 local GX_DERIVEDSOURCES_EXTRACTOR="${GX_HERE}/extract-dependencies-from-makefile" 750 751 [[ -n "${GX_DERIVEDSOURCES_GENERATOR}" ]] || die "GX_DERIVEDSOURCES_GENERATOR is not defined." 752 [[ -x "${GX_DERIVEDSOURCES_GENERATOR}" ]] || die "${GX_DERIVEDSOURCES_GENERATOR} does not exist or is not executable." 753 [[ -x "${GX_DERIVEDSOURCES_EXTRACTOR}" ]] || die "${GX_DERIVEDSOURCES_EXTRACTOR} does not exist or is not executable." 754 755 log_debug "Creating derived .xcfilelists for ${PROJECT_NAME}/${PLATFORM_NAME}/${CONFIGURATION}" 756 757 "${GX_DERIVEDSOURCES_GENERATOR}" \ 758 NO_SUPPLEMENTAL_FILES=1 \ 759 --no-builtin-rules \ 760 --dry-run \ 761 --always-make \ 762 --debug=abvijm all \ 763 1> "${GX_TEMP}/std.out" 2> "${GX_TEMP}/std.err" 764 local GX_RESULT=$? 765 766 if (( ${GX_RESULT} )) 767 then 768 sed -E -e 's/^/GXCF: /' < "${GX_TEMP}/std.err" 769 die "Error generating derived sources: error = ${GX_RESULT}" ${GX_RESULT} 770 fi 771 772 cat "${GX_TEMP}/std.out" \ 773 | "${GX_DERIVEDSOURCES_EXTRACTOR}" \ 774 --input "${GX_TEMP_INPUT_XCFILELIST}" \ 775 --output "${GX_TEMP_OUTPUT_XCFILELIST}" 776 local GX_RESULT=$? 777 778 (( ${GX_RESULT} )) && die "Error extracting dependencies from DerivedSources.make: error = ${GX_RESULT}" 779 [[ -f "${GX_TEMP_INPUT_XCFILELIST}" ]] || die "${GX_TEMP_INPUT_XCFILELIST} was not generated." 780 [[ -f "${GX_TEMP_OUTPUT_XCFILELIST}" ]] || die "${GX_TEMP_OUTPUT_XCFILELIST} was not generated." 781 782 replace "${GX_TEMP_INPUT_XCFILELIST}" '^WebCore/' '$(PROJECT_DIR)/' 783 replace "${GX_TEMP_INPUT_XCFILELIST}" '^JavaScriptCore/' '$(PROJECT_DIR)/' 784 replace "${GX_TEMP_INPUT_XCFILELIST}" '^JavaScriptCorePrivateHeaders/' '$(JAVASCRIPTCORE_PRIVATE_HEADERS_DIR)/' 785 replace "${GX_TEMP_INPUT_XCFILELIST}" '^WebKit2PrivateHeaders/' '$(WEBKIT2_PRIVATE_HEADERS_DIR)/' 786 unexpand "${GX_TEMP_INPUT_XCFILELIST}" PROJECT_DIR 787 unexpand "${GX_TEMP_INPUT_XCFILELIST}" WEBKITADDITIONS_HEADERS_FOLDER_PATH 788 unexpand "${GX_TEMP_INPUT_XCFILELIST}" WEBCORE_PRIVATE_HEADERS_DIR 789 unexpand "${GX_TEMP_INPUT_XCFILELIST}" WEBKIT2_PRIVATE_HEADERS_DIR 790 unexpand "${GX_TEMP_INPUT_XCFILELIST}" JAVASCRIPTCORE_PRIVATE_HEADERS_DIR 791 unexpand "${GX_TEMP_INPUT_XCFILELIST}" BUILT_PRODUCTS_DIR 792 793 replace "${GX_TEMP_OUTPUT_XCFILELIST}" "^" "${GX_PS_DERIVED_SOURCES_DIR}/" 794 unexpand "${GX_TEMP_OUTPUT_XCFILELIST}" BUILT_PRODUCTS_DIR 795 796 merge_xcfilelists_helper "${GX_TEMP_INPUT_XCFILELIST}" "${GX_INPUT_DERIVED_XCFILELIST_PROJECT_TEMP_PATH}" 797 merge_xcfilelists_helper "${GX_TEMP_OUTPUT_XCFILELIST}" "${GX_OUTPUT_DERIVED_XCFILELIST_PROJECT_TEMP_PATH}" 798 } 799 800 801 function generate_unifiedsources_xcfilelists() 802 { 803 log_callstack_and_parameters "$@" 804 805 create_empty_files "${GX_TEMP_OUTPUT_XCFILELIST}" 806 807 [[ -n "${GX_UNIFIEDSOURCES_GENERATOR}" ]] || die "GX_UNIFIEDSOURCES_GENERATOR is not defined." 808 [[ -x "${GX_UNIFIEDSOURCES_GENERATOR}" ]] || die "${GX_UNIFIEDSOURCES_GENERATOR} does not exist or is not executable." 809 810 local GX_BUILD_SCRIPTS_DIR="${GX_OPENSOURCE_DIR}/Source/WTF/Scripts" 811 [[ -d "${GX_BUILD_SCRIPTS_DIR}" ]] || die "${GX_BUILD_SCRIPTS_DIR} does not exist or is not a directory." 812 [[ -f "${GX_BUILD_SCRIPTS_DIR}/generate-unified-source-bundles.rb" ]] || die "${GX_BUILD_SCRIPTS_DIR}/generate-unified-source-bundles.rb does not exist or is not a file." 813 814 log_debug "Creating unified .xcfilelists for ${PROJECT_NAME}/${PLATFORM_NAME}/${CONFIGURATION}" 815 816 BUILD_SCRIPTS_DIR="${GX_BUILD_SCRIPTS_DIR}" \ 817 "${GX_UNIFIEDSOURCES_GENERATOR}" \ 818 --generate-xcfilelists \ 819 --output-xcfilelist-path "${GX_TEMP_OUTPUT_XCFILELIST}" 820 GX_RESULT=$? 821 822 (( ${GX_RESULT} )) && die "Error generating unified sources: error = ${GX_RESULT}" 823 [[ -f "${GX_TEMP_OUTPUT_XCFILELIST}" ]] || die "${GX_TEMP_OUTPUT_XCFILELIST} was not generated." 824 825 unexpand "${GX_TEMP_OUTPUT_XCFILELIST}" BUILT_PRODUCTS_DIR 826 827 merge_xcfilelists_helper "${GX_TEMP_OUTPUT_XCFILELIST}" "${GX_OUTPUT_UNIFIED_XCFILELIST_PROJECT_TEMP_PATH}" 828 } 829 830 831 function subgenerate_xcfilelists() 832 { 833 log_callstack_and_parameters "$@" 834 835 invoke_each_action "${GX_SUBGENERATE_ACTIONS[@]}" 836 } 837 838 839 function sublaunch_under_xcode() 840 { 841 log_callstack_and_parameters "$@" 842 843 # Sublaunch the script for the given project, for each platform for which 844 # the project is built, and for Debug and Release configurations. 845 846 local GX_ARGS=("$@") 847 (( ${GX_DRY_RUN} )) && GX_ARGS+=("--dry-run") 848 (( ${GX_DEBUG} )) && { for n in $(seq $GX_DEBUG); do GX_ARGS+=("--debug"); done; } 849 (( ${GX_QUIET} )) && GX_ARGS+=("--quiet") 850 851 local GX_SDK_NAME 852 get_sdk_name "${GX_PLATFORM_NAME}" GX_SDK_NAME 853 854 log_debug "Sublaunching for: ${GX_PROJECT_TAG}/${GX_PLATFORM_NAME}/${GX_CONFIGURATION}" 855 856 local GX_XCODE_PARAMETERS=( 857 -project "${GX_PS_PROJECT_FILE_PATH}" 858 -sdk "${GX_SDK_NAME}" 859 -configuration "${GX_CONFIGURATION}" 860 -target "Apply Configuration to XCFileLists" 861 ) 862 863 if (( ${GX_USE_WEBKITBUILD_BUILD_OUTPUT} )) 864 then 865 local GX_WEBKITBUILD_DIR="${WEBKIT_OUTPUTDIR:-${GX_OPENSOURCE_DIR}/WebKitBuild}" 866 [[ -d "${GX_WEBKITBUILD_DIR}" ]] || die "${GX_WEBKITBUILD_DIR} does not exist." 867 868 GX_XCODE_PARAMETERS+=( 869 SYMROOT="${GX_WEBKITBUILD_DIR}" 870 OBJROOT="${GX_WEBKITBUILD_DIR}" 871 SHARED_PRECOMPS_DIR="${GX_WEBKITBUILD_DIR}/PrecompiledHeaders" 872 ) 873 fi 874 875 if (( $GX_DEBUG > 0 )) 876 then 877 WK_SUBLAUNCH_SCRIPT_PARAMETERS=("${GX_ARGS[@]}") xcodebuild "${GX_XCODE_PARAMETERS[@]}" 878 else 879 WK_SUBLAUNCH_SCRIPT_PARAMETERS=("${GX_ARGS[@]}") xcodebuild "${GX_XCODE_PARAMETERS[@]}" | grep '^\.\.\. ' 880 fi 881 882 local GX_RESULT=${PIPESTATUS[0]} 883 (( ${GX_RESULT} )) && die "Error sub-launching under xcode: error = ${GX_RESULT}" 884 } 885 886 887 function reset_project_specific_temp_files() 888 { 889 log_callstack_and_parameters "$@" 890 891 create_empty_files \ 892 "${GX_INPUT_DERIVED_XCFILELIST_PROJECT_TEMP_PATH}" "${GX_OUTPUT_DERIVED_XCFILELIST_PROJECT_TEMP_PATH}" \ 893 "${GX_OUTPUT_UNIFIED_XCFILELIST_PROJECT_TEMP_PATH}" 894 } 895 896 897 function generate_xcfilelists() 898 { 899 log_callstack_and_parameters "$@" 900 901 reset_project_specific_temp_files 902 903 for_each_platform \ 904 for_each_configuration \ 905 sublaunch_under_xcode \ 906 "${GX_SUBEXECUTE_SCRIPT}" subgenerate --nocleanup --project "${GX_PROJECT_TAG}" 907 } 908 909 910 function merge_xcfilelists_helper() 911 { 912 log_callstack_and_parameters "$@" 913 914 local GX_SOURCE="$1" 915 local GX_DEST="$2" 916 local GX_ADDITIONS="${GX_TEMP}/diff_added.tmp" 917 918 append_xcfilelist_header "${GX_SOURCE}" 919 sort_and_unique_in_place "${GX_SOURCE}" 920 921 find_additions "${GX_SOURCE}" "${GX_DEST}" "${GX_ADDITIONS}" 922 923 if [[ -s "${GX_ADDITIONS}" ]] 924 then 925 cat "${GX_SOURCE}" >> "${GX_DEST}" 926 sort_and_unique_in_place "${GX_DEST}" 927 return 0 928 fi 929 930 return 1 931 } 932 933 934 function merge_derivedsources_xcfilelists() 935 { 936 log_callstack_and_parameters "$@" 937 938 log_debug "Merging ${GX_INPUT_DERIVED_XCFILELIST_PROJECT_TEMP_PATH} into ${GX_INPUT_DERIVED_XCFILELIST_PROJECT_PATH}" 939 log_debug "Merging ${GX_OUTPUT_DERIVED_XCFILELIST_PROJECT_TEMP_PATH} into ${GX_OUTPUT_DERIVED_XCFILELIST_PROJECT_PATH}" 940 941 if (( ! ${GX_DRY_RUN} )) 942 then 943 merge_xcfilelists_helper "${GX_INPUT_DERIVED_XCFILELIST_PROJECT_TEMP_PATH}" "${GX_INPUT_DERIVED_XCFILELIST_PROJECT_PATH}" && GX_DEFERRED_EXIT_CODE=3 944 log_debug "GX_DEFERRED_EXIT_CODE = $GX_DEFERRED_EXIT_CODE" 945 946 merge_xcfilelists_helper "${GX_OUTPUT_DERIVED_XCFILELIST_PROJECT_TEMP_PATH}" "${GX_OUTPUT_DERIVED_XCFILELIST_PROJECT_PATH}" && GX_DEFERRED_EXIT_CODE=3 947 log_debug "GX_DEFERRED_EXIT_CODE = $GX_DEFERRED_EXIT_CODE" 948 fi 949 } 950 951 952 function merge_unifiedsources_xcfilelists() 953 { 954 log_callstack_and_parameters "$@" 955 956 log_debug "Merging ${GX_OUTPUT_UNIFIED_XCFILELIST_PROJECT_TEMP_PATH} into ${GX_OUTPUT_UNIFIED_XCFILELIST_PROJECT_PATH}" 957 958 if (( ! ${GX_DRY_RUN} )) 959 then 960 merge_xcfilelists_helper "${GX_OUTPUT_UNIFIED_XCFILELIST_PROJECT_TEMP_PATH}" "${GX_OUTPUT_UNIFIED_XCFILELIST_PROJECT_PATH}" && GX_DEFERRED_EXIT_CODE=3 961 log_debug "GX_DEFERRED_EXIT_CODE = $GX_DEFERRED_EXIT_CODE" 962 fi 963 } 964 965 966 function merge_xcfilelists() 967 { 968 log_callstack_and_parameters "$@" 969 970 invoke_each_action "${GX_MERGE_ACTIONS[@]}" 971 972 log_debug "GX_DEFERRED_EXIT_CODE = $GX_DEFERRED_EXIT_CODE" 973 } 974 975 976 function check_xcfilelists_helper() 977 { 978 log_callstack_and_parameters "$@" 979 980 local GX_NEW="$1" 981 local GX_ORIG="$2" 982 local GX_ADDITIONS="${GX_TEMP}/diff_added.tmp" 983 984 log_debug "Checking ${GX_NEW} against ${GX_ORIG}" 985 986 find_additions "${GX_NEW}" "${GX_ORIG}" "${GX_ADDITIONS}" 987 988 if [[ -s "${GX_ADDITIONS}" ]] 989 then 990 log_progress 991 log_progress "------------------------------------------------------------------------------" 992 log_progress "Found added files for ${GX_ORIG}:" 993 log_progress "------------------------------------------------------------------------------" 994 995 local GX_LINE 996 while IFS='' read -r GX_LINE 997 do 998 log_progress "${GX_LINE}" 999 done < "${GX_ADDITIONS}" 1000 1001 log_progress "------------------------------------------------------------------------------" 1002 1003 GX_DEFERRED_EXIT_CODE=2 1004 fi 1005 } 1006 1007 1008 function check_derivedsources_xcfilelists() 1009 { 1010 log_callstack_and_parameters "$@" 1011 1012 check_xcfilelists_helper "${GX_INPUT_DERIVED_XCFILELIST_PROJECT_TEMP_PATH}" "${GX_INPUT_DERIVED_XCFILELIST_PROJECT_PATH}" 1013 check_xcfilelists_helper "${GX_OUTPUT_DERIVED_XCFILELIST_PROJECT_TEMP_PATH}" "${GX_OUTPUT_DERIVED_XCFILELIST_PROJECT_PATH}" 1014 } 1015 1016 1017 function check_unifiedsources_xcfilelists() 1018 { 1019 log_callstack_and_parameters "$@" 1020 1021 check_xcfilelists_helper "${GX_OUTPUT_UNIFIED_XCFILELIST_PROJECT_TEMP_PATH}" "${GX_OUTPUT_UNIFIED_XCFILELIST_PROJECT_PATH}" 1022 } 1023 1024 1025 function check_xcfilelists() 1026 { 1027 log_callstack_and_parameters "$@" 1028 1029 invoke_each_action "${GX_CHECK_ACTIONS[@]}" 1030 } 1031 1032 1033 function report_merge_results() 1034 { 1035 log_callstack_and_parameters "$@" 1036 1037 log_debug "GX_DEFERRED_EXIT_CODE = $GX_DEFERRED_EXIT_CODE" 1038 1039 if (( ${GX_DEFERRED_EXIT_CODE} )) 1040 then 1041 log_progress 1042 1043 local GX_MESSAGE='".xcfilelist" files tell the build system what files 1044 are consumed and produced by the "Run Script" build phases in 1045 Xcode. At least one of these .xcfilelist files was out of date and 1046 has been updated. You now need to restart your build.' 1047 1048 log_progress_long "${GX_MESSAGE}" 1049 fi 1050 } 1051 1052 1053 function report_remediation_steps() 1054 { 1055 log_callstack_and_parameters "$@" 1056 1057 if (( ${GX_DEFERRED_EXIT_CODE} )) 1058 then 1059 log_progress 1060 1061 # We can either be called from within an xcodebuild context (meaning 1062 # that we are being called during a build to validate the .xcfilelists 1063 # for the current build configuration) or from the command line (to 1064 # validate all .xcfilelists). We'll determine which of these is the 1065 # case by checking $GX_PROJECT_TAG (which will have been set via the 1066 # --project <TAG> option passed in to us when we're invoked in this 1067 # context). 1068 # 1069 # Further, if called from within xcodebuild, it's important to know if 1070 # we're being called from within Xcode or being invoked by a Makefile. 1071 # If the former, the output/build files we are looking for are found in 1072 # ~/Library/Developer/Xcode/DerivedData. Otherwise, they'll be found in 1073 # OpenSource/WebKitBuild (or whatever $WEBKIT_OUTPUTDIR points to). We 1074 # need to distinguish between these so that we can tell the user how to 1075 # invoke us in a way that finds the right output/build files. 1076 # 1077 # If invoked from the command line, we really can't tell where the 1078 # output files are, so give the user advice in this area. 1079 1080 local GX_MESSAGE='".xcfilelist" files tell the build system what files 1081 are consumed and produced by the "Run Script" build phases in 1082 Xcode. At least one of these .xcfilelist files are out of date and 1083 need to be regenerated. Regenerate these files by running 1084 `Tools/Scripts/generate-xcfilelists generate' 1085 1086 if [[ -n "${GX_PROJECT_TAG}" ]] 1087 then 1088 local GX_MESSAGE+=" --project ${GX_PROJECT_TAG}" 1089 if [[ "${SYMROOT}" =~ Library/Developer/Xcode/DerivedData ]] 1090 then 1091 local GX_MESSAGE+=" --xcode" 1092 fi 1093 else 1094 if (( ${GX_USE_XCODE_BUILD_OUTPUT} )) 1095 then 1096 local GX_MESSAGE+=" --xcode" 1097 fi 1098 fi 1099 1100 local GX_MESSAGE+='`, or manually add the file or files shown above to 1101 the indicated .xcfilelist files. Then restart your build. When 1102 submitting, include the updated .xcfilelist files.' 1103 1104 log_progress_long "${GX_MESSAGE}" 1105 fi 1106 } 1107 1108 1109 function do_generate() 1110 { 1111 # Invoked from the command line to generate .xcfilelist files. Use any 1112 # specified project, platform, and/or configuration. Any of those that 1113 # aren't specified results in our iterating over all possible values for 1114 # the unspecified value. 1115 1116 log_callstack_and_parameters "$@" 1117 1118 if [[ -z "${GX_PROJECT_TAG}" ]] 1119 then 1120 log_progress "=== Generating all .xcfilelists ===" 1121 else 1122 log_progress "=== Generating .xcfilelists for ${GX_PROJECT_TAG} ===" 1123 fi 1124 1125 for_each_project \ 1126 generate_xcfilelists 1127 } 1128 1129 1130 function do_merge() 1131 { 1132 # Implicitly invoked for generate and generate-xcode operations to move the 1133 # temporary results into the Xcode project. 1134 1135 log_callstack_and_parameters "$@" 1136 1137 if [[ -z "${GX_PROJECT_TAG}" ]] 1138 then 1139 log_progress "=== Merging all .xcfilelists into place ===" 1140 else 1141 log_progress "=== Merging .xcfilelists for ${GX_PROJECT_TAG} ===" 1142 fi 1143 1144 for_each_project \ 1145 merge_xcfilelists 1146 1147 log_debug "GX_DEFERRED_EXIT_CODE = $GX_DEFERRED_EXIT_CODE" 1148 } 1149 1150 1151 function do_check() 1152 { 1153 # Implicitly invoked for check and check-xcode operations to check the 1154 # temporary results against the Xcode project. 1155 1156 log_callstack_and_parameters "$@" 1157 1158 # Being invoked from the command-line to check everything. 1159 1160 if [[ -z "${GX_PROJECT_TAG}" ]] 1161 then 1162 log_progress "=== Checking all .xcfilelists ===" 1163 else 1164 log_progress "=== Checking .xcfilelists for ${GX_PROJECT_TAG} ===" 1165 fi 1166 1167 for_each_project \ 1168 check_xcfilelists 1169 } 1170 1171 1172 function do_subgenerate() 1173 { 1174 # Invoked from within an Xcode context to generate .xcfilelist files. Use 1175 # the project, platform, an configuration established in the environment. 1176 1177 log_callstack_and_parameters "$@" 1178 1179 [[ -n "${GX_PROJECT_TAG}" ]] || die "GX_PROJECT_TAG is not defined." 1180 [[ -n "${PROJECT_NAME}" ]] || die "subgenerate should only be invoked in an Xcode context." 1181 1182 log_progress "=== Generating .xcfilelists for ${PROJECT_NAME}/${PLATFORM_NAME}/${CONFIGURATION} ===" 1183 1184 set_project_settings 1185 1186 # We're called during generate-xcode, check-xcode, and subgenerate 1187 # operations. We need to reset our project-specific temp files for the 1188 # first two, but not the last one. 1189 1190 (( ${GX_DO_SUBGENERATE} )) || reset_project_specific_temp_files 1191 1192 subgenerate_xcfilelists 1193 } 1194 1195 1196 function main() 1197 { 1198 log_callstack_and_parameters "$@" 1199 1200 log_debug_var GX_ME 1201 log_debug_var GX_HERE 1202 log_debug_var GX_ROOT_DIR 1203 log_debug_var GX_OPENSOURCE_DIR 1204 log_debug_var GX_TEMP 1205 log_debug_var GX_PROJECT_TAGS 1206 log_debug_var GX_CONFIGURATIONS 1207 log_debug_var GX_SUBEXECUTE_SCRIPT 1208 log_debug_var GX_DO_GENERATE 1209 log_debug_var GX_DO_GENERATE_XCODE 1210 log_debug_var GX_DO_CHECK 1211 log_debug_var GX_DO_CHECK_XCODE 1212 log_debug_var GX_DO_SUBGENERATE 1213 log_debug_var GX_DO_CLEANUP 1214 log_debug_var GX_USE_XCODE_BUILD_OUTPUT 1215 log_debug_var GX_USE_WEBKITBUILD_BUILD_OUTPUT 1216 log_debug_var GX_DRY_RUN 1217 log_debug_var GX_DEBUG 1218 log_debug_var GX_QUIET 1219 log_debug_var GX_ORIG_ARGS 1220 1221 if (( ${GX_DO_HELP} )) 1222 then 1223 usage 1224 my_exit 0 1225 fi 1226 1227 if (( GX_DO_GENERATE + GX_DO_GENERATE_XCODE + GX_DO_CHECK + GX_DO_CHECK_XCODE + GX_DO_SUBGENERATE + GX_DO_HELP < 1 )) 1228 then 1229 stderr "### One of generate, generate-xcode, check, check-xcode, subgenerate, or --help must be specified." 1230 my_exit 1 1231 fi 1232 1233 if (( GX_DO_GENERATE + GX_DO_GENERATE_XCODE + GX_DO_CHECK + GX_DO_CHECK_XCODE + GX_DO_SUBGENERATE + GX_DO_HELP > 1 )) 1234 then 1235 stderr "### Only one of generate, generate-xcode, check, check-xcode, subgenerate, or --help can be specified." 1236 my_exit 1 1237 fi 1238 1239 [[ -z "${GX_PROJECT_TAG}" || ( " ${GX_PROJECT_TAGS[@]} " =~ " ${GX_PROJECT_TAG} " ) ]] || { die "Unrecognized project: ${GX_PROJECT_TAG}"; } 1240 get_canonical_platform_name "${GX_PLATFORM_NAME}" GX_PLATFORM_NAME 1241 get_canonical_configuration "${GX_CONFIGURATION}" GX_CONFIGURATION 1242 1243 if (( ${GX_DO_GENERATE} )) 1244 then 1245 do_generate 1246 call post_generate_hook 1247 1248 do_merge 1249 call post_merge_hook 1250 1251 report_merge_results 1252 elif (( ${GX_DO_GENERATE_XCODE} )) 1253 then 1254 do_subgenerate 1255 call post_generate_hook 1256 1257 do_merge 1258 call post_merge_hook 1259 1260 report_merge_results 1261 elif (( ${GX_DO_CHECK} )) 1262 then 1263 do_generate 1264 call post_generate_hook 1265 1266 do_check 1267 call post_check_hook 1268 1269 report_remediation_steps 1270 elif (( ${GX_DO_CHECK_XCODE} )) 1271 then 1272 do_subgenerate 1273 call post_generate_hook 1274 1275 do_check 1276 call post_check_hook 1277 1278 report_remediation_steps 1279 elif (( ${GX_DO_SUBGENERATE} )) 1280 then 1281 do_subgenerate 1282 else 1283 stderr "### No subcommand provided" 1284 usage 1285 my_exit 1 1286 fi 1287 1288 my_exit ${GX_DEFERRED_EXIT_CODE} 1289 } 1290 1291 1292 # Initialize and sanity check 1293 1294 GX_ORIG_ARGS=("$@") 1295 1296 GX_DO_GENERATE=0 1297 GX_DO_GENERATE_XCODE=0 1298 GX_DO_CHECK=0 1299 GX_DO_CHECK_XCODE=0 1300 GX_DO_SUBGENERATE=0 1301 GX_DO_HELP=0 1302 GX_DO_CLEANUP=0 1303 GX_USE_XCODE_BUILD_OUTPUT=0 1304 GX_USE_WEBKITBUILD_BUILD_OUTPUT=1 1305 GX_DRY_RUN=0 1306 GX_DEBUG=0 1307 GX_QUIET=0 1308 1309 GX_DEFERRED_EXIT_CODE=0 1310 GX_PROJECT_TAG= 1311 GX_PLATFORM_NAME= 1312 GX_CONFIGURATION= 1313 GX_SDKS=() 1314 1315 GX_ME=$(normalize_file_path "${BASH_SOURCE[0]}") 1316 GX_HERE=$(dirname "${GX_ME}") 1317 GX_ROOT_DIR=$(normalize_directory_path "${GX_HERE}/../../..") 1318 GX_OPENSOURCE_DIR="${GX_ROOT_DIR}/OpenSource" 1319 GX_TEMP=$(normalize_directory_path /tmp/generate-xcfilelists) 1320 GX_PROJECT_TAGS=(JavaScriptCore WebCore WebKit DumpRenderTree WebKitTestRunner) 1321 GX_CONFIGURATIONS=(Release Debug) 1322 GX_SUBEXECUTE_SCRIPT="${GX_ME}" 1323 1324 [[ -n "${GX_ROOT_DIR}" ]] || die "Could not find GX_ROOT_DIR." 1325 [[ -n "${GX_OPENSOURCE_DIR}" ]] || die "Could not find GX_OPENSOURCE_DIR." 1326 [[ -d "${GX_ROOT_DIR}" ]] || die "${GX_ROOT_DIR} does not exist." 1327 [[ -d "${GX_OPENSOURCE_DIR}" ]] || die "${GX_OPENSOURCE_DIR} does not exist." 1328 1329 trap cleanup EXIT 1330 1331 ensure_directories_exist "${GX_TEMP}" 1332 1333 1334 # Process command-line parameters. 1335 1336 while [[ "${1:+x}" ]] 1337 do 1338 case "${1}" in 1339 generate) GX_DO_GENERATE=1 ;; 1340 generate-xcode) GX_DO_GENERATE_XCODE=1 ;; 1341 check) GX_DO_CHECK=1 ;; 1342 check-xcode) GX_DO_CHECK_XCODE=1 ;; 1343 subgenerate) GX_DO_SUBGENERATE=1 ;; 1344 help) GX_DO_HELP=1 ;; 1345 1346 --project) shift; GX_PROJECT_TAG="$1" ;; 1347 --platform) shift; GX_PLATFORM_NAME="$1" ;; 1348 --configuration)shift; GX_CONFIGURATION="$1" ;; 1349 --xcode) GX_USE_XCODE_BUILD_OUTPUT=1; GX_USE_WEBKITBUILD_BUILD_OUTPUT=0 ;; 1350 --webkitbuild) GX_USE_XCODE_BUILD_OUTPUT=0; GX_USE_WEBKITBUILD_BUILD_OUTPUT=1 ;; 1351 --nocleanup) GX_DO_CLEANUP=0 ;; 1352 1353 -n | --dry-run) GX_DRY_RUN=1 ;; 1354 -d | --debug) GX_DEBUG=$(( $GX_DEBUG + 1 )) ;; 1355 -q | --quiet) GX_QUIET=1 ;; 1356 -h | --help) GX_DO_HELP=1 ;; 1357 1358 *) stderr "### Unknown command: $1" 1359 usage 1360 my_exit 1 ;; 1361 esac 1362 shift 1363 done 1364 1365 1366 GX_SOURCED=$([[ "$0" == "${BASH_SOURCE[@]}" ]] && echo 0 || echo 1) 1367 if (( ! ${GX_SOURCED} )) 1368 then 1369 GX_INTERNAL_ME="${GX_ROOT_DIR}/Internal/Tools/Scripts/generate-xcfilelists" 1370 if [[ -x "${GX_INTERNAL_ME}" ]] 1371 then 1372 "${GX_INTERNAL_ME}" "${GX_ORIG_ARGS[@]}" 1373 else 1374 main 1375 fi 1376 fi 58 if __name__ == "__main__": 59 application_class = apple_additions().get_generate_xcfilelists_application() if apple_additions() else Application 60 sys.exit(application_class(__file__).run()) -
trunk/Tools/Scripts/webkitpy/xcode/__init__.py
r226812 r245364 1 1 # Required for Python to search this directory for module files 2 3 import hashlib 4 import struct 5 6 7 # The default location for Xcode's "DerivedData" (build output and intermediate 8 # files) is a unique directory in ~/Library/Developer/Xcode/DerivedData with a 9 # name incorporating a hash based on the full path of the project or workspace 10 # being built. The following function takes that path and returns the 11 # corresponding hash. 12 # 13 # The algorithm is adapted from the following article: 14 # 15 # <https://pewpewthespells.com/blog/xcode_deriveddata_hashes.pdf> 16 17 def xcode_hash_for_path(path): 18 def convert_to_string(n): 19 s = '' 20 for _ in range(0, 14): 21 (n, r) = divmod(n, 26) 22 s = chr(r + 97) + s 23 return s 24 25 (part1, part2) = struct.unpack(">QQ", hashlib.md5(path.encode()).digest()) 26 return convert_to_string(part1) + convert_to_string(part2) -
trunk/Tools/WebKitTestRunner/Scripts/check-xcfilelists.sh
r244987 r245364 9 9 10 10 SCRIPT="${BUILD_SCRIPTS_DIR}/generate-xcfilelists" 11 [ -f "${SCRIPT}" ] || SCRIPT="${PROJECT_DIR}/../../../${WK_ADDITIONAL_SCRIPTS_DIR}/generate-xcfilelists" 11 12 [ -f "${SCRIPT}" ] || SCRIPT="${PROJECT_DIR}/../../Tools/Scripts/generate-xcfilelists" 12 13 [ -f "${SCRIPT}" ] || { echo "### Cannot find generate-xcfilelists script"; exit 1; }
Note: See TracChangeset
for help on using the changeset viewer.