| #!/usr/bin/env bash | |
| # Copyright 2015 The Chromium Authors. All rights reserved. | |
| # Use of this source code is governed by a BSD-style license that can be | |
| # found in the LICENSE file. | |
| # ---------------------------------- NOTE ---------------------------------- # | |
| # | |
| # Please keep the logic in this file consistent with the logic in the | |
| # `flutter.bat` script in the same directory to ensure that Flutter continues | |
| # to work across all platforms! | |
| # | |
| # -------------------------------------------------------------------------- # | |
| set -e | |
| unset CDPATH | |
| function follow_links() { | |
| cd -P "${1%/*}" | |
| local file="$PWD/${1##*/}" | |
| while [[ -h "$file" ]]; do | |
| # On Mac OS, readlink -f doesn't work. | |
| cd -P "${file%/*}" | |
| file="$(readlink "$file")" | |
| cd -P "${file%/*}" | |
| file="$PWD/${file##*/}" | |
| done | |
| echo "$PWD/${file##*/}" | |
| } | |
| # Convert a filesystem path to a format usable by Dart's URI parser. | |
| function path_uri() { | |
| # Reduce multiple leading slashes to a single slash. | |
| echo "$1" | sed -E -e "s,^/+,/," | |
| } | |
| function _rmlock () { | |
| [ -n "$FLUTTER_UPGRADE_LOCK" ] && rm -f "$FLUTTER_UPGRADE_LOCK" | |
| } | |
| function retry_upgrade { | |
| local total_tries="10" | |
| local remaining_tries=$((total_tries - 1)) | |
| while [[ "$remaining_tries" -gt 0 ]]; do | |
| (cd "$FLUTTER_TOOLS_DIR" && "$PUB" upgrade "$VERBOSITY") && break | |
| echo "Error: Unable to 'pub upgrade' flutter tool. Retrying in five seconds... ($remaining_tries tries left)" | |
| remaining_tries=$((remaining_tries - 1)) | |
| sleep 5 | |
| done | |
| if [[ "$remaining_tries" == 0 ]]; then | |
| echo "Command 'pub upgrade' still failed after $total_tries tries, giving up." | |
| return 1 | |
| fi | |
| return 0 | |
| } | |
| function upgrade_flutter () { | |
| mkdir -p "$FLUTTER_ROOT/bin/cache" | |
| # This function is executed with a redirect that pipes the source of | |
| # this script into file descriptor 3. | |
| # | |
| # To ensure that we don't simultaneously update Dart in multiple | |
| # parallel instances, we try to obtain an exclusive lock on this | |
| # file descriptor (and thus this script's source file) while we are | |
| # updating Dart and compiling the script. To do this, we try to use | |
| # the command line program "flock", which is available on many | |
| # Unix-like platforms, in particular on most Linux distributions. | |
| # You give it a file descriptor, and it locks the corresponding | |
| # file, having inherited the file descriptor from the shell. | |
| # | |
| # Complicating matters, there are two major scenarios where this | |
| # will not work. | |
| # | |
| # The first is if the platform doesn't have "flock", for example on Mac. | |
| # There is not a direct equivalent, so on platforms that don't have flock, | |
| # we fall back to using a lockfile and spinlock with "shlock". This | |
| # doesn't work as well over NFS as it relies on PIDs. Any platform | |
| # without either of these tools has no locking at all. To determine if we | |
| # have "flock" or "shlock" available, we abuse the "hash" shell built-in. | |
| # | |
| # The second complication is NFS. On NFS, to obtain an exclusive | |
| # lock you need a file descriptor that is open for writing, because | |
| # NFS implements exclusive locks by writing, or some such. Thus, we | |
| # ignore errors from flock. We do so by using the '|| true' trick, | |
| # since we are running in a 'set -e' environment wherein all errors | |
| # are fatal, and by redirecting all output to /dev/null, since | |
| # users will typically not care about errors from flock and are | |
| # more likely to be confused by them than helped. | |
| # | |
| # For "flock", the lock is released when the file descriptor goes out of | |
| # scope, i.e. when this function returns. The lock is released via | |
| # a trap when using "shlock". | |
| if hash flock 2>/dev/null; then | |
| flock 3 2>/dev/null || true | |
| elif hash shlock 2>/dev/null; then | |
| FLUTTER_UPGRADE_LOCK="$FLUTTER_ROOT/bin/cache/.upgrade_lock" | |
| while ! shlock -f "$FLUTTER_UPGRADE_LOCK" -p $$ ; do sleep .1 ; done | |
| trap _rmlock EXIT | |
| fi | |
| local revision="$(cd "$FLUTTER_ROOT"; git rev-parse HEAD)" | |
| # Invalidate cache if: | |
| # * SNAPSHOT_PATH is not a file, or | |
| # * STAMP_PATH is not a file with nonzero size, or | |
| # * Contents of STAMP_PATH is not our local git HEAD revision, or | |
| # * pubspec.yaml last modified after pubspec.lock | |
| if [[ ! -f "$SNAPSHOT_PATH" || ! -s "$STAMP_PATH" || "$(cat "$STAMP_PATH")" != "$revision" || "$FLUTTER_TOOLS_DIR/pubspec.yaml" -nt "$FLUTTER_TOOLS_DIR/pubspec.lock" ]]; then | |
| rm -f "$FLUTTER_ROOT/version" | |
| touch "$FLUTTER_ROOT/bin/cache/.dartignore" | |
| "$FLUTTER_ROOT/bin/internal/update_dart_sdk.sh" | |
| VERBOSITY="--verbosity=error" | |
| echo Building flutter tool... | |
| if [[ "$CI" == "true" || "$BOT" == "true" || "$CONTINUOUS_INTEGRATION" == "true" || "$CHROME_HEADLESS" == "1" ]]; then | |
| PUB_ENVIRONMENT="$PUB_ENVIRONMENT:flutter_bot" | |
| VERBOSITY="--verbosity=normal" | |
| fi | |
| export PUB_ENVIRONMENT="$PUB_ENVIRONMENT:flutter_install" | |
| if [[ -d "$FLUTTER_ROOT/.pub-cache" ]]; then | |
| export PUB_CACHE="${PUB_CACHE:-"$FLUTTER_ROOT/.pub-cache"}" | |
| fi | |
| retry_upgrade | |
| "$DART" $FLUTTER_TOOL_ARGS --snapshot="$SNAPSHOT_PATH" --packages="$FLUTTER_TOOLS_DIR/.packages" "$SCRIPT_PATH" | |
| echo "$revision" > "$STAMP_PATH" | |
| fi | |
| # The exit here is duplicitous since the function is run in a subshell, | |
| # but this serves as documentation that running the function in a | |
| # subshell is required to make sure any lockfile created by shlock | |
| # is cleaned up. | |
| exit $? | |
| } | |
| PROG_NAME="$(path_uri "$(follow_links "$BASH_SOURCE")")" | |
| BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)" | |
| export FLUTTER_ROOT="$(cd "${BIN_DIR}/.." ; pwd -P)" | |
| FLUTTER_TOOLS_DIR="$FLUTTER_ROOT/packages/flutter_tools" | |
| SNAPSHOT_PATH="$FLUTTER_ROOT/bin/cache/flutter_tools.snapshot" | |
| STAMP_PATH="$FLUTTER_ROOT/bin/cache/flutter_tools.stamp" | |
| SCRIPT_PATH="$FLUTTER_TOOLS_DIR/bin/flutter_tools.dart" | |
| DART_SDK_PATH="$FLUTTER_ROOT/bin/cache/dart-sdk" | |
| DART="$DART_SDK_PATH/bin/dart" | |
| PUB="$DART_SDK_PATH/bin/pub" | |
| # Test if running as superuser – but don't warn if running within Docker | |
| if [[ "$EUID" == "0" && ! -f /.dockerenv ]]; then | |
| echo " Woah! You appear to be trying to run flutter as root." | |
| echo " We strongly recommend running the flutter tool without superuser privileges." | |
| echo " /" | |
| echo "📎" | |
| fi | |
| # Test if Git is available on the Host | |
| if ! hash git 2>/dev/null; then | |
| echo "Error: Unable to find git in your PATH." | |
| exit 1 | |
| fi | |
| # Test if the flutter directory is a git clone (otherwise git rev-parse HEAD would fail) | |
| if [[ ! -e "$FLUTTER_ROOT/.git" ]]; then | |
| echo "Error: The Flutter directory is not a clone of the GitHub project." | |
| echo " The flutter tool requires Git in order to operate properly;" | |
| echo " to set up Flutter, run the following command:" | |
| echo " git clone -b stable https://github.com/flutter/flutter.git" | |
| exit 1 | |
| fi | |
| # To debug the tool, you can uncomment the following lines to enable checked mode and set an observatory port: | |
| # FLUTTER_TOOL_ARGS="--enable-asserts $FLUTTER_TOOL_ARGS" | |
| # FLUTTER_TOOL_ARGS="$FLUTTER_TOOL_ARGS --observe=65432" | |
| (upgrade_flutter) 3< "$PROG_NAME" | |
| # FLUTTER_TOOL_ARGS isn't quoted below, because it is meant to be considered as | |
| # separate space-separated args. | |
| "$DART" --packages="$FLUTTER_TOOLS_DIR/.packages" $FLUTTER_TOOL_ARGS "$SNAPSHOT_PATH" "$@" |