| #!/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" "$@" |