[embedder] Add commit hooks and bootstrap script.

The Git commit hooks check for changes to
the Fuchsia SDK as you pull updates to the
embedder repo to warn you when your ffx
version has changed in case you need to update
running emulators etc.

The hooks also look out for updates to the hooks themselves
to let you know when there are new updates
to the hooks to install.

The bootstrap script removes a couple of steps of setup and warns you
when KVM is not enabled, which is vital for
working in the embedder repo.

Change-Id: I41312994074ff465cbc4764e068f101c1d4beb3f
diff --git a/README.md b/README.md
index d11be1b..2042f9d 100644
--- a/README.md
+++ b/README.md
@@ -13,34 +13,23 @@
 1. Set `$FUCHSIA_EMBEDDER_DIR` to your flutter-embedder.git checkout location,
    for example `~/flutter-embedder`.
 
-2. Make sure this repository has the required submodules:
-
    ```sh
-   git submodule update --recursive --init
+   export FUCHSIA_EMBEDDER_DIR=$HOME/flutter-embedder
    ```
 
-3. Run `$FUCHSIA_EMBEDDER_DIR/scripts/bootstrap.sh`.
-
-4. Ensure that there are Fuchsia SSH keys in your host machine. You will need
-   them for running the Fuchsia emulator.
+2. Bootstrap the repository's dependencies:
 
    ```sh
-    [[ -f "${HOME}/.ssh/fuchsia_ed25519" ]] || ssh-keygen -P "" -t ed25519 -f "${HOME}/.ssh/fuchsia_ed25519" -C "${USER}@$(hostname -f) Shared SSH Key for Fuchsia"
-
-    [[ -f "${HOME}/.ssh/fuchsia_authorized_keys" ]] || ssh-keygen -y -f "${HOME}/.ssh/fuchsia_ed25519" > "${HOME}/.ssh/fuchsia_authorized_keys"
+   $FUCHSIA_EMBEDDER_DIR/scripts/bootstrap.sh
    ```
 
-## Build and package the sample
+   This script initializes tools (including `bazel` and `ffx`), installs some Git
+   hooks and downloads the `workstation_eng.qemu-x64` product bundle, which you can
+   use to run the examples below.
 
-Now the repository is ready to build the sample.
+## Run an example app
 
-1. Fetch an emulator image:
-
-   ```sh
-   $FUCHSIA_EMBEDDER_DIR/tools/ffx product-bundle get workstation_eng.qemu-x64
-   ```
-
-2. Start the emulator.
+1. Start the emulator.
 
    If running in a graphical environment:
 
@@ -72,8 +61,8 @@
 
 ## Syncing engine artifacts
 
-Occasionally you will need to update the Flutter Engine artifacts (embedder.h and
-libengine_flutter.so) that are used by the embedder to run Flutter apps. A script
+Occasionally you will need to update the Flutter Engine artifacts (`embedder.h` and
+`libengine_flutter.so`) that are used by the embedder to run Flutter apps. A script
 is provided for this workflow.
 
 ### Requirements
@@ -83,12 +72,10 @@
    **Note that this is not just cloning https://github.com/flutter/engine.**
 2. Set `$ENGINE_DIR` to the `src` folder of your Flutter Engine checkout location,
    for example `~/engine/src`.
-3. `$FUCHSIA_EMBEDDER_DIR` should be set to your flutter-embedder.git checkout
-   location, for example `~/flutter-embedder`.
-4. `$DEPOT_TOOLS` should be set to your
+3. `$DEPOT_TOOLS` should be set to your
     [`depot_tools`](https://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools_tutorial.html#_setting_up)
     location, for example `~/depot_tools`.
-5. You will need to `git stash` or `git commit` any local changes to the Flutter
+4. You will need to `git stash` or `git commit` any local changes to the Flutter
    Engine or the script will fail.
 
 ### Running the script
diff --git a/hooks/post-checkout b/hooks/post-checkout
new file mode 100755
index 0000000..5513b35
--- /dev/null
+++ b/hooks/post-checkout
@@ -0,0 +1,51 @@
+#!/bin/bash
+#
+# Copyright 2022 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Returns true if colors are supported.
+function is-stderr-tty {
+  [[ -t 2 ]]
+}
+
+# echo-info prints a line to stderr with a green INFO: prefix.
+function echo-info {
+  if is-stderr-tty; then
+    echo -e >&2 "\033[1;32mINFO:\033[0m $*"
+  else
+    echo -e >&2 "INFO: $*"
+  fi
+}
+
+# echo-warning prints a line to stderr with a yellow WARNING: prefix.
+function echo-warning {
+  if is-stderr-tty; then
+    echo -e >&2 "\033[1;33mWARNING:\033[0m $*"
+  else
+    echo -e >&2 "WARNING: $*"
+  fi
+}
+
+# Check if sdk-integration has changed.
+# If it has, the SDK version has changed for the
+# repo, and the user will likely want to shut down
+# things that were run using the old SDK to avoid
+# incompatibility issues between old things and the new SDK.
+sdk_folder="third_party/sdk-integration"
+if [[ $(git diff HEAD@{1}..HEAD@{0} -- "${sdk_folder}" | wc -l) -gt 0 ]]; then
+  echo
+  echo-warning "\e[33;1m${sdk_folder}\e[0m has changed."
+  echo-warning "This can lead to incompatiblities with emulators started using the old SDK."
+  echo-warning "We recommend running the following command to clean up resources from the old SDK:"
+  echo-warning '$FUCHSIA_EMBEDDER_DIR/scripts/update_fuchsia_sdk.sh --no-version-bump --cleanup'
+fi
+
+# Check if git hooks have changed.
+# Prompt the user to install the new hooks if they have.
+hooks_folder="hooks"
+if [[ $(git diff HEAD@{1}..HEAD@{0} -- hooks | wc -l) -gt 0 ]]; then
+  echo
+  echo-info "\e[33;1mhooks/\e[0m has changed. To install the new Git hooks, run:"
+  echo-info '$FUCHSIA_EMBEDDER_DIR/scripts/install_hooks.sh'
+fi
diff --git a/scripts/bootstrap.sh b/scripts/bootstrap.sh
new file mode 100755
index 0000000..df8cdd7
--- /dev/null
+++ b/scripts/bootstrap.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+#
+# Copyright 2022 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Sets up this repository and all its dependencies.
+#
+# Usage:
+#   bootstrap.sh
+#
+# Requirements:
+#   1. $FUCHSIA_EMBEDDER_DIR is set to your flutter-embedder.git checkout.
+
+set -e # Fail on any error.
+source "$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"/lib/echo_helpers.sh || exit $?
+
+if [[ -z $FUCHSIA_EMBEDDER_DIR ]]
+then
+  echo-error '$FUCHSIA_EMBEDDER_DIR must be set to your flutter-embedder folder before running this script.'
+  echo-error 'Add this line to your shell profile:'
+  echo-error "export FUCHSIA_EMBEDDER_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && cd .. && pwd)"
+  exit 1
+fi
+
+echo-info "Initializing submodules..."
+git -C $FUCHSIA_EMBEDDER_DIR submodule update --recursive --init
+
+echo-info "Bootstrapping Bazel..."
+$FUCHSIA_EMBEDDER_DIR/scripts/bootstrap_bazel.sh
+$FUCHSIA_EMBEDDER_DIR/tools/bazel clean
+
+echo-info 'Building the embedder to fetch external dependencies (clang)...'
+$FUCHSIA_EMBEDDER_DIR/tools/bazel build --config=fuchsia_x64 //src/embedder
+
+echo-info "Initializing Fuchsia SSH keys (if not already created)..."
+[[ -f "${HOME}/.ssh/fuchsia_ed25519" ]] || ssh-keygen -P "" -t ed25519 -f "${HOME}/.ssh/fuchsia_ed25519" -C "${USER}@$(hostname -f) Shared SSH Key for Fuchsia"
+[[ -f "${HOME}/.ssh/fuchsia_authorized_keys" ]] || ssh-keygen -y -f "${HOME}/.ssh/fuchsia_ed25519" > "${HOME}/.ssh/fuchsia_authorized_keys"
+
+echo-info "Installing Git hooks..."
+$FUCHSIA_EMBEDDER_DIR/scripts/install_hooks.sh
+
+# Installing the product-bundle fails when the user has product bundles
+# from a previous version of ffx installed, so we clean up old product bundles
+# here.
+# TODO(akbiggs): Is there something less invasive we can do here?
+echo-warning "Deleting other product bundles to ensure the new product bundle installs... Sorry..."
+rm -rf ~/.local/share/Fuchsia/ffx/pbms
+
+echo-info "Installing the workstation_eng.qemu-x64 product bundle..."
+$FUCHSIA_EMBEDDER_DIR/tools/ffx product-bundle get workstation_eng.qemu-x64
+echo
+
+if [[ -r /dev/kvm ]] && grep '^flags' /proc/cpuinfo | grep -qE 'vmx|svm'
+then
+  # I'm bad at shell and couldn't figure out how to invert this condition properly.
+  :
+else
+  echo-warning 'VM acceleration (KVM) is not enabled on your machine. Consider enabling it by following https://fuchsia.dev/fuchsia-src/get-started/set_up_femu?hl=en#enable-vm-acceleration.'
+  echo-warning 'Without KVM enabled, emulator performance will be terrible.'
+  echo-warning 'If you have already enabled KVM, you may need to reboot your machine.'
+fi
+
+echo "Done. You're now ready to run a Flutter on Fuchsia example app:"
+echo "https://fuchsia.googlesource.com/flutter-embedder#run-an-example-app"
+
diff --git a/scripts/bootstrap.sh b/scripts/bootstrap_bazel.sh
similarity index 100%
rename from scripts/bootstrap.sh
rename to scripts/bootstrap_bazel.sh
diff --git a/scripts/build_and_run_example.sh b/scripts/build_and_run_example.sh
index fd16c43..7bf1172 100755
--- a/scripts/build_and_run_example.sh
+++ b/scripts/build_and_run_example.sh
@@ -25,7 +25,7 @@
 while [[ $# -gt 0 ]]; do
   case $1 in
     --headless)
-      echo "--headless apps will not work yet because there's no collection to run JIT components in."
+      echo-warning "--headless apps will not work yet because there's no collection to run JIT components in."
       headless=1
       shift # past argument
       ;;
diff --git a/scripts/install_hooks.sh b/scripts/install_hooks.sh
new file mode 100755
index 0000000..e22f59d
--- /dev/null
+++ b/scripts/install_hooks.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# Copyright 2022 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Installs git hooks for this repo into .git/hooks.
+#
+# Usage:
+#   install_hooks.sh
+#
+# Requirements:
+#   1. $FUCHSIA_EMBEDDER_DIR is set to your flutter-embedder.git checkout.
+
+# Apply the post-checkout hook on checkout, merge and rebase.
+cp $FUCHSIA_EMBEDDER_DIR/hooks/post-checkout $FUCHSIA_EMBEDDER_DIR/.git/hooks/post-checkout
+cp $FUCHSIA_EMBEDDER_DIR/hooks/post-checkout $FUCHSIA_EMBEDDER_DIR/.git/hooks/post-merge
+cp $FUCHSIA_EMBEDDER_DIR/hooks/post-checkout $FUCHSIA_EMBEDDER_DIR/.git/hooks/post-rewrite
+
+# post-rewrite gets fired for `amend` as well, so add a line that
+# exits the post-rewrite hook immediately for anything but 'rebase'.
+sed -i -e '6iif [[ $1 -ne "rebase" ]]; then exit 0; fi;\' $FUCHSIA_EMBEDDER_DIR/.git/hooks/post-rewrite
diff --git a/scripts/lib/echo_helpers.sh b/scripts/lib/echo_helpers.sh
index 7955f6a..49df823 100644
--- a/scripts/lib/echo_helpers.sh
+++ b/scripts/lib/echo_helpers.sh
@@ -26,3 +26,12 @@
     echo -e >&2 "WARNING: $*"
   fi
 }
+
+# echo-error prints a line to stderr with a red ERROR: prefix.
+function echo-error {
+  if is-stderr-tty; then
+    echo -e >&2 "\033[1;31mERROR:\033[0m $*"
+  else
+    echo -e >&2 "ERROR: $*"
+  fi
+}
diff --git a/scripts/update_fuchsia_sdk.sh b/scripts/update_fuchsia_sdk.sh
index 3eb8880..28ebe65 100755
--- a/scripts/update_fuchsia_sdk.sh
+++ b/scripts/update_fuchsia_sdk.sh
@@ -18,31 +18,40 @@
 
 # Parse arguments.
 cleanup=0
+no_version_bump=0
 while [[ $# -gt 0 ]]; do
   case $1 in
     --cleanup)
       cleanup=1
       shift # past argument
       ;;
+    --no-version-bump)
+      no_version_bump=1
+      shift # past argument
+      ;;
     *)
       shift # past value
       ;;
   esac
 done
 
-echo-info "Updating the Fuchsia SDK checkout..."
-git -C $FUCHSIA_EMBEDDER_DIR/third_party/sdk-integration pull origin main
+if [[ "${no_version_bump}" -eq 0 ]]
+then
+  echo-info "Updating the Fuchsia SDK checkout..."
+  git -C $FUCHSIA_EMBEDDER_DIR/third_party/sdk-integration pull origin main
+fi
 
-echo-info "Building the embedder to fetch the Fuchsia SDK tools..."
+echo-info "Building the embedder to fetch the updated Fuchsia SDK tools..."
 pushd $FUCHSIA_EMBEDDER_DIR
-bazel build --config=fuchsia_x64 //src/embedder
+$FUCHSIA_EMBEDDER_DIR/tools/bazel clean
+$FUCHSIA_EMBEDDER_DIR/tools/bazel build --config=fuchsia_x64 //src/embedder
 popd
 
 if [[ "${cleanup}" -eq 0 ]]
 then
-  echo-info "Your Fuchsia SDK has been updated to version `$FUCHSIA_EMBEDDER_DIR/tools/ffx version`."
-  echo-warning 'You should restart any running emulators (`ffx emu stop`)'
-  echo-warning 'and update your product bundles (`ffx product-bundle get workstation_eng.qemu-x64`) as'
+  echo-info "flutter-embedder's Fuchsia SDK has been updated to version $($FUCHSIA_EMBEDDER_DIR/tools/ffx version)."
+  echo-warning 'You should restart any running emulators (`$FUCHSIA_EMBEDDER_DIR/tools/ffx emu stop`)'
+  echo-warning 'and update your product bundles (`$FUCHSIA_EMBEDDER_DIR/tools/ffx product-bundle get workstation_eng.qemu-x64`) as'
   echo-warning 'old images may be incompatible with the updated SDK.'
   echo-warning 'To do this automatically, run: $FUCHSIA_EMBEDDER_DIR/scripts/update_fuchsia_sdk.sh --cleanup'
   exit 0
@@ -50,18 +59,20 @@
 
 echo-info "Cleaning up old things that are incompatible with the new SDK."
 echo-info "If you don't want this, don't run the script with --cleanup."
-echo-info "Killing any running emulators."
-ffx emu stop
+echo-info "Killing any running emulators..."
+$FUCHSIA_EMBEDDER_DIR/tools/ffx emu stop
 
 # TODO(https://fxbug.dev/106963): Replace with an ffx product-bundle clean command once
 # one exists.
-echo-info "Deleting old product bundles."
+echo-info "Deleting old product bundles..."
 rm -rf ~/.local/share/Fuchsia/ffx/pbms
 
-echo-info "Refetching the workstation_eng.qemu-x64 product bundle."
-ffx product-bundle get workstation_eng.qemu-x64
+echo-info "Refetching the workstation_eng.qemu-x64 product bundle..."
+$FUCHSIA_EMBEDDER_DIR/tools/ffx product-bundle get workstation_eng.qemu-x64
 
 echo
-echo-info "Your Fuchsia SDK has been updated to version `$FUCHSIA_EMBEDDER_DIR/tools/ffx version`."
+echo-info "flutter-embedder's Fuchsia SDK has been updated to version $($FUCHSIA_EMBEDDER_DIR/tools/ffx version)."
 echo-info "You will need to restart your emulator by running:"
 echo '$FUCHSIA_EMBEDDER_DIR/tools/ffx emu start workstation_eng.qemu-x64'
+echo-info "Or if you're running from a non-graphical environment:"
+echo '$FUCHSIA_EMBEDDER_DIR/tools/ffx emu start workstation_eng.qemu-x64 --headless'