Flutter命令解析_flutter的脚本文件(含视频)

2,047 阅读6分钟

本篇文章有对应视频放在B站,大概有50多分钟,相对来说会详细些。B站视频地址

本文需要提前了解snapshot和pub get的相关知识点,如果没有了解过可以参考我的另外两篇文章:


我们可以通过使用flutter相关的命令,来完成一些flutter构建相关工作。比如说flutter create来创建flutter项目,flutter run来运行flutter项目。那么他们的具体实现是在哪呢?这篇文章主要就是解决这个问题。

当前使用的flutter 版本:

Flutter 1.17.5 • channel stable • github.com/flutter/flu… Framework • revision 8af6b2f038 (4 周前) • 2020-06-30 12:53:55 -0700 Engine • revision ee76268252 Tools • Dart 2.8.4

flutter 可执行文件

Q : 当我们在终端中输入 flutter时,具体执行逻辑的实现在哪呢?

我们在配置flutter开发环境时,有一步是配置:PATH='./flutter根目录/bin。通过这个可以猜测该脚本是位于bin目录下的。

如上图,其中有个名为flutter的Unix可执行文件。本质其实 就是一个shell脚本。当我们在终端中输入flutter时就会运行这个可执行文件。至于flutter 后面的,比如create , build, run等其实是它的参数。 所以想要搞懂flutter xxx 到底怎么执行得。首先得搞明白,flutter这个shell脚本到底干了啥。

下面是我加了些注解的flutter文件里的源码,接下来的内容就分析这个源码:

#!/usr/bin/env bash
# Copyright 2014 The Flutter 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
#删除 环境变量CDPATH 主要是防止下面的cd命令出现意想不到的情况
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##*/}"
}

# 将文件系统路径转换为Dart URI解析器可用的格式
# Convert a filesystem path to a format usable by Dart's URI parser.
function path_uri() {
  # 将文件系统路径转换为Dart 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" --no-precompile) && 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 () {

  #所以刚拉下代码 这个cache目录应该是不存在的
  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".


  #就是一个防止 同时调upgrade方法的互斥操作
  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
# 将源码当前分支最新的commit hash作为版本的标识,用来判断源码是否更新
  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"
    echo "$PUB_ENVIRONMENT"
    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" --no-enable-mirrors "$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 $?
}
# 测试了下 path_uri 和 follow_links两个函数返回都是null
PROG_NAME="$(path_uri "$(follow_links "$BASH_SOURCE")")"
#BASH_SOURCE[0] BASH_SOURCE[0] 等价于 BASH_SOURCE, 取得当前执行的shell文件所在的路径及文件名。即:/Users/frc/Library/Android/flutter/bin/flutter
# %/* 代表取从头到最后一个/之前的所有内容 即:/Users/frc/Library/Android/flutter/bin
BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
# 进入bin目录的父目录,打印出目录路径就是flutter的根目录。
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"

# 如果是在window系统上,通过git-bash软件执行shell命令的话,会将dart和pub换成.exe和.bat
# uname -s 获取当前系统的内核
# If running over git-bash, overrides the default UNIX
# executables with win32 executables
case "$(uname -s)" in
  MINGW32*)
    DART="$DART.exe"
    PUB="$PUB.bat"
    ;;
esac

# 就是个提示 不建议使用
# 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

# 因为需要通过git来获取当前源码的版本号,拉取源码等,所以需要先保证git可运行
# 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
# 判断flutter目录下是否有.git文件, 因为需要通过.git来获取当前源码的版本号
# 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.
echo "@ is : ""$@"
"$DART" --packages="$FLUTTER_TOOLS_DIR/.packages" $FLUTTER_TOOL_ARGS "$SNAPSHOT_PATH" "$@"

上面源码主要逻辑我将他分为以下几步:

1.获取各种资源路径

这一步主要就是:先得找到flutter源码的跟路径FUTTER_ROOT,然后根据它定义其他常用路径

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"

可以看到上面几个路径都是固定的,唯一不确定的就是FLUTTER_ROOT,那么怎么获取到FLUTTER_ROOT的呢。

1.1 获取当前文件所在的全路径

# BASH_SOURCE可以获取当前执行的shell文件所在的路径及文件名。即:/Users/frc/Library/Android/flutter/bin/flutter

PROG_NAME="$(path_uri "$(follow_links "$BASH_SOURCE")")"

1.2 获取当前文件所在的目录的路径,就是bin目录的路径

# %/* 代表取从头到最后一个/之前的所有内容 即:/Users/frc/Library/Android/flutter/bin
BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"

1.3 bin目录的父目录的路径就是FLUTTER_ROOT,即flutter源码的根目录。

# 进入bin目录的父目录,打印出目录路径就是flutter的根目录。
export FLUTTER_ROOT="$(cd "${BIN_DIR}/.." ; pwd -P)"

配上下图就更方便理解了:

2.一些兼容和检测

这里主要是做了些关于git和用户权限的检测,以及不同版本系统的兼容。

2.1 检测当前脚本运行的内核

如果当前脚本运行在git-bash上,则需要在dart和pub的路径尾部分别加上exe和bat。因为windows上exe才是可执行文件,bat是脚本文件。其实这里就是兼容了 windows,linux,unix。让当前脚本在主路系统上都能顺利执行。


# 如果是在window系统上,通过git-bash软件执行shell命令的话,会将dart和pub换成.exe和.bat
# uname -s 获取当前系统的内核
# If running over git-bash, overrides the default UNIX
# executables with win32 executables
case "$(uname -s)" in
  MINGW32*)
    DART="$DART.exe"
    PUB="$PUB.bat"
    ;;
esac

2.2 关于git的判断。

由于flutter源码是通过git管理的,因此在源码升级时就是通过git来拉取新代码。所以需要保证git能正常运行。由于要获取当前源码的commit hash,所以也要保证flutter源码根目录下的.git文件是存在的。

  • 判断git的path是否配置正常
# 因为需要通过git来获取当前源码的版本号,拉取源码等,所以需要先保证git可运行
# 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

  • 判断.git文件是否存在
# 判断flutter目录下是否有.git文件, 因为需要通过.git来获取当前源码的版本好号
# 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

上面两条件不成立,是编译不通过的

3. build flutter_tools

这部分比较多,也是比较难看懂的地方。

3.1 保证build flutter_tools不会被多次同时执行。

  #就是一个防止 同时调upgrade方法的互斥操作
  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

3.2 判断flutter_tools是否需要重新编译

flutter的相关工具都在flutter_tools.snapshot中,所以当第一次下载源码、源码更新以及依赖发生改变时,我们都需要重新build flutter_tools.snapshot。 之后看源码我们会发现flutter工具的实现都是用dart写的,dart语言通过.snapshot将很多dart文件的集成到一个可执行的镜像文件中。并且.snapshot执行效率要比直接直线.dart文件高 。

3.2.1 获取源码当前分支最新的commit hash

# 将源码当前分支最新的commit hash作为版本的标识,用来判断源码是否更新
local revision="$(cd "$FLUTTER_ROOT"; git rev-parse HEAD)"

git rev-parse HEAD :获取当前分支上最后一个的 commit hash

看下我当前的commit是什么:

git log 看下我当前的最新commit hash是不是这个

确实是一样的。

3.2.2 flutter_tools.snapshot文件必须存在

! -f "$SNAPSHOT_PATH"

SNAPSHOT_PATH="$FLUTTER_ROOT/bin/cache/flutter_tools.snapshot"

3.2.3 flutter_tools.stamp 尺寸必须大于0

! -s "$STAMP_PATH"

STAMP_PATH="$FLUTTER_ROOT/bin/cache/flutter_tools.stamp"

flutter_tools.stamp文件必须存在且大小不能为空。

查看一下 flutter_tools.stamp文件中的内容,

发现它存的就是revision

3.2.4 flutter_tools.stamp中存放的值必须跟revision一致

"$(cat "$STAMP_PATH")" != "$revision" 

如果 flutter_tools.stamp存的值和revision不一样说明,源码发生了改动。

3.2.5 pubspec.yaml不能比pubspec.lock新

"$FLUTTER_TOOLS_DIR/pubspec.yaml" -nt "$FLUTTER_TOOLS_DIR/pubspec.lock"

FLUTTER_TOOLS_DIR="$FLUTTER_ROOT/packages/flutter_tools"

pubspec.yaml中定义了一些依赖库的路径,每当 pubspec.yaml发生改变并拉取后, pubspec.lock也会改变。所以正常情况pubspec.lock都是比pubspec.yaml新。如果出现pubspec.yaml比pubspec.lock新的情况,肯定是pubspec.yaml中添加了新依赖但是还没有拉取,所以需要拉取依赖。

如果上面四个条件中任何一个发生改变,那么就需要重新编译flutter_tools.snapshot

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"

    ...
    
  fi
 
  exit $?

3.3 pub upgrade

在判断条件内部,会有先文件清空和文件重建,可以自己过下。相对而言除了bulid flutter_tools外还有个很重要的步骤:拉取依赖

开发过flutter项目的都知道,我们可以通过在项目的pubsepc.yaml文件中添加三方库路径,然后通过执行pub upgrade来拉取源码。而这步做的其实类似,不过拉取的应该是整个flutter源码工程的依赖库。

直接看这个函数源码:

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" --no-precompile) && 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
}

可以看到核心逻辑就一句 (cd "$FLUTTER_TOOLS_DIR" && "$PUB" upgrade "$VERBOSITY" --no-precompile) && break 。如果执行失败会进行重试,一共重试10次,如果都失败了,就放弃了。

看下核心干了什么:

  1. 进入 flutter_tools目录
  2. 执行 pub upgrade命令

为什么要到flutter_tools目录下执行 pub upgrade呢,因为那有个pubspec.yaml文件,这个文件记录了需要下载的依赖库,所以整个retry_upgrade就是要下载flutter的依赖库。

我们可以做个实验:到flutter_tools的父目录下执行 pub upgrade

我们看到会提示你当前目录没有pubspec.yaml。 我们再到flutter_tools目录下执行 pub upgrade

可以看到提示Resolving dependencies...。其实就是在拉取依赖。

4. 生成flutter_tools.snapshot文件

这一步非常重要

"$DART" $FLUTTER_TOOL_ARGS --snapshot="$SNAPSHOT_PATH" --packages="$FLUTTER_TOOLS_DIR/.packages" --no-enable-mirrors "$SCRIPT_PATH"

我将他简单转换下就是下面的: dart --snapshot="$FLUTTER_ROOT/bin/cache/flutter_tools.snapshot" --packages="$FLUTTER_ROOT/packages/flutter_tools/.package" 其实就是将flutter_tools/.pacakge文件中写的目录下的所有.dart文件打包成bin/cache/flutter_tools.snapshot文件。然后执行了flutter_tools.snapshot文件。

可以参考下面代码,看看怎么讲dart文件转换成snapshot文件。

$ dart  --snapshot=hello.dart.snapshot hello.dart
$ dart hello.dart.snapshot arguments-for-use
Hello, world!

为什么要生成snapshot文件呢?:snapshot针对启动速度做了相应的优化,本质上是要创建的对象的列表和他们之间关系。相对于解析Dart源码并逐步创建VM内部的数据结构,VM可以将isolate所必须的数据结构全部打包在snapshot中。

我们打开这个.package文件看下

# Generated by pub on 2020-07-24 20:00:11.773033.
_fe_analyzer_shared:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/_fe_analyzer_shared-1.0.3/lib/
analyzer:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/analyzer-0.39.4/lib/
archive:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/archive-2.0.13/lib/
args:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/args-1.6.0/lib/
async:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/async-2.4.1/lib/
boolean_selector:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/boolean_selector-2.0.0/lib/
browser_launcher:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/browser_launcher-0.1.5/lib/
build_daemon:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/build_daemon-2.1.4/lib/
built_collection:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/built_collection-4.3.2/lib/
built_value:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/built_value-7.0.9/lib/
charcode:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/charcode-1.1.3/lib/
checked_yaml:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/checked_yaml-1.0.2/lib/
collection:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/collection-1.14.12/lib/
completion:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/completion-0.2.2/lib/
convert:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/convert-2.1.1/lib/
coverage:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/coverage-0.13.9/lib/
crypto:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/crypto-2.1.4/lib/
csslib:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/csslib-0.16.1/lib/
devtools:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/devtools-0.2.3/lib/
devtools_server:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/devtools_server-0.2.4-dev.1/lib/
devtools_shared:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/devtools_shared-0.2.4-dev.1/lib/
dwds:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/dwds-3.0.2/lib/
file:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/file-5.1.0/lib/
file_testing:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/file_testing-2.1.0/lib/
fixnum:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/fixnum-0.10.11/lib/
flutter_goldens_client:../flutter_goldens_client/lib/
flutter_template_images:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/flutter_template_images-1.0.0/lib/
glob:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/glob-1.2.0/lib/
html:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/html-0.14.0+3/lib/
http:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/http-0.12.0+4/lib/
http_multi_server:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/http_multi_server-2.2.0/lib/
http_parser:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/http_parser-3.1.4/lib/
intl:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/intl-0.16.1/lib/
io:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/io-0.3.3/lib/
js:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/js-0.6.1+1/lib/
json_annotation:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/json_annotation-3.0.1/lib/
json_rpc_2:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/json_rpc_2-2.1.0/lib/
logging:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/logging-0.11.4/lib/
matcher:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/matcher-0.12.6/lib/
meta:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/meta-1.1.8/lib/
mime:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/mime-0.9.6+3/lib/
mockito:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/mockito-4.1.1/lib/
multi_server_socket:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/multi_server_socket-1.0.2/lib/
multicast_dns:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/multicast_dns-0.2.2/lib/
mustache_template:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/mustache_template-1.0.0+1/lib/
native_stack_traces:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/native_stack_traces-0.3.1/lib/
node_interop:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/node_interop-1.0.3/lib/
node_io:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/node_io-1.0.1+2/lib/
node_preamble:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/node_preamble-1.4.8/lib/
package_config:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/package_config-1.9.1/lib/
package_resolver:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/package_resolver-1.0.10/lib/
path:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/path-1.6.4/lib/
pedantic:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/pedantic-1.9.0/lib/
petitparser:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/petitparser-2.4.0/lib/
platform:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/platform-2.2.1/lib/
pool:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/pool-1.4.0/lib/
process:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/process-3.0.12/lib/
pub_semver:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/pub_semver-1.4.4/lib/
pubspec_parse:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/pubspec_parse-0.1.5/lib/
quiver:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/quiver-2.1.3/lib/
shelf:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/shelf-0.7.5/lib/
shelf_packages_handler:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/shelf_packages_handler-1.0.4/lib/
shelf_proxy:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/shelf_proxy-0.1.0+7/lib/
shelf_static:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/shelf_static-0.2.8/lib/
shelf_web_socket:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/shelf_web_socket-0.2.3/lib/
source_map_stack_trace:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/source_map_stack_trace-2.0.0/lib/
source_maps:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/source_maps-0.10.9/lib/
source_span:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/source_span-1.7.0/lib/
sse:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/sse-3.2.1/lib/
stack_trace:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/stack_trace-1.9.3/lib/
stream_channel:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/stream_channel-2.0.0/lib/
stream_transform:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/stream_transform-1.2.0/lib/
string_scanner:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/string_scanner-1.0.5/lib/
sync_http:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/sync_http-0.2.0/lib/
term_glyph:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/term_glyph-1.1.0/lib/
test:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/test-1.14.2/lib/
test_api:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/test_api-0.2.15/lib/
test_core:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/test_core-0.3.3/lib/
typed_data:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/typed_data-1.1.6/lib/
usage:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/usage-3.4.1/lib/
uuid:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/uuid-2.0.4/lib/
vm_service:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/vm_service-4.0.0/lib/
watcher:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/watcher-0.9.7+14/lib/
web_socket_channel:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/web_socket_channel-1.1.0/lib/
webdriver:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/webdriver-2.1.2/lib/
webkit_inspection_protocol:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/webkit_inspection_protocol-0.5.0+1/lib/
xml:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/xml-3.6.1/lib/
yaml:file:///Users/frc/.pub-cache/hosted/pub.flutter-io.cn/yaml-2.2.0/lib/
flutter_tools:lib/

里面都是些路径,上面的我们先不看,太多。只看最后一个路径:flutter_tools:lib/,我们进去看看

看到这个目录下都是.dart文件。

从截图上就能看到一些有意思的文件名比如说docotor.dart。我猜应该跟flutter docotor命令有关。 我就瞎翻两下看到commands目录下的东西,高兴坏了:

这些文件名,都跟我们常用的命令差不多。

所以我猜测flutter常用的命令实现都在这了。

先不纠结这个,跳回去继续把flutter文件内容看完。

4 flutter各种命令是如何调用的的

执行完upgrade_flutter (),这个文件也就剩最后一行逻辑了。

"$DART" --packages="$FLUTTER_TOOLS_DIR/.packages" $FLUTTER_TOOL_ARGS "$SNAPSHOT_PATH" "$@"

简化一下就是

dart flutter_tools.snapshot "$@"

这个“$@”是什么呢,加上以下代码打印出来看看就知道了:

echo "@ is : ""$@"

我们可以看到@就是你输入的flutter 参数。

所以你如果输入flutter upgrade那么最终执行的是

dart flutter_tools.snapshot upgrade

总结: flutter 命令其实就是通过flutter_tools.snapshot来指定对应的命令。

参考资料:

filename为文件名
-e (equal)
-e filename, 判断文件是否存在
 
-d (directory)
-d filename,判断文件是否为目录
 
-f (file)
-f filename,判断文件是否为常规文件
 
-L (link)
-L filename,判断文件是否问链接文件
 
-r (read)
-r filename,判断文件是否可读
 
-w (write)
-w filename,判断文件是否可写
 
-x (exec)
-x filename,判断文件是否可执行
 
-s (size)
-s filename,判断文件长度是否为0
 
-h (hard link)
-h filename,判断文件是否为硬链接文件
 
-nt (newer than)
filename1 -nt filename2,判断文件1是否比文件2新
 
-ot (older than)