Improve activate-emsdk script

- Avoid maintaining the Emscripten toolchain release version separately
  from the emsdk DEPS entry, by installing/activating 'latest' instead
  of a pinned version. This works because emsdk itself has a pinned
  definition of 'latest' for each emsdk release. Avoids bugs like
  https://dawn-review.googlesource.com/c/dawn/+/240534
- Silence subprocess output from emsdk unless it fails (tested locally).

Bug: 414330682
Change-Id: I41e36da14b3cd43a604e8549ac997247458733cb
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/240535
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Loko Kung <lokokung@google.com>
Auto-Submit: Kai Ninomiya <kainino@chromium.org>
diff --git a/DEPS b/DEPS
index dd56ad9..820b379 100644
--- a/DEPS
+++ b/DEPS
@@ -366,6 +366,8 @@
 
   # Dependencies required to build / run WebAssembly bindings
   'third_party/emsdk': {
+    # Note: Always use an emsdk hash referring to a tagged release, just so
+    # emsdk and emscripten are always in sync with an exact release.
     'url': '{chromium_git}/external/github.com/emscripten-core/emsdk.git@419021fa040428bc69ef1559b325addb8e10211f',
     'condition': 'dawn_wasm',
   },
diff --git a/tools/activate-emsdk b/tools/activate-emsdk
index 9c3f5d5..075161c 100644
--- a/tools/activate-emsdk
+++ b/tools/activate-emsdk
@@ -6,6 +6,7 @@
 # found in the LICENSE file.
 
 import argparse
+import json
 import os
 import subprocess
 import sys
@@ -17,7 +18,18 @@
 EMSDK_PATH = os.path.join(EMSDK_ROOT, 'emsdk.py')
 EMSDK_CONFIG_PATH = os.path.join(EMSDK_ROOT, '.emscripten')
 
-EMSDK_VERSION = '4.0.8'
+
+# Run a subprocess with stderr forwarded to stdout. Raise an exception if it fails.
+def run_or_exit(name, args):
+    try:
+        subprocess.run(args,
+                       encoding='utf-8',
+                       check=True,
+                       stdout=subprocess.PIPE,
+                       stderr=subprocess.STDOUT)
+    except subprocess.CalledProcessError as ex:
+        raise Exception(name + ' failed:\n' + ex.stdout) from ex
+
 
 def main(args):
     parser = argparse.ArgumentParser()
@@ -25,23 +37,22 @@
     options = parser.parse_args()
 
     if options.get_emsdk_version:
-        print(EMSDK_VERSION)
-        return 0
+        # https://github.com/emscripten-core/emsdk/blob/main/emscripten-releases-tags.json
+        with open(os.path.join(EMSDK_ROOT, 'emscripten-releases-tags.json')) as f:
+            print(json.load(f)['aliases']['latest'])
+        return
 
     # Install and activate the default dependencies for emsdk.
-    try:
-        subprocess.check_call([sys.executable, EMSDK_PATH, 'install', EMSDK_VERSION])
-    except subprocess.CalledProcessError:
-        print ('Failed to install emsdk')
-        return 1
-    try:
-        subprocess.check_call([sys.executable, EMSDK_PATH, 'activate', EMSDK_VERSION])
-    except subprocess.CalledProcessError:
-        print ('Failed to activate emsdk')
-        return 1
+    # 'latest' is a static alias in emsdk for the toolchain corresponding to
+    # this emsdk release, so we can use it stably.
+    run_or_exit('emsdk install',
+                [sys.executable, EMSDK_PATH, 'install', 'latest'])
+    run_or_exit('emsdk activate',
+                [sys.executable, EMSDK_PATH, 'activate', 'latest'])
 
     # If we ever need to override the Python, Node, and LLVM binaries used by Emscripten, do that
     # here. See https://dawn-review.googlesource.com/c/dawn/+/238814/4..5 which removed support.
 
+
 if __name__ == '__main__':
-  sys.exit(main(sys.argv))
+    main(sys.argv)