Adding support for AppRTC closure compiling.

Since AppRTC now uses Closure we need to be able to closure compile.
This is implemented as a grunt task, which means we need grunt, which
means we need node and npm. This patch makes sure to download all the
necessary dependencies and invokes them locally, which means we don't
need to install stuff on the bots. A risk here is increased flakes
since many of these tools (like npm) download stuff in a manner that
likely isn't reliable. I suggest we check how it works out and add
retry mechanisms as necessary.

This checks in node versions
node-v0.10.35-darwin-x64.tar.gz
node-v0.10.35-linux-x64.tar.gz
npm-1.4.9.zip / v0.10.36/x64/node.exe

into source control.

BUG=451985
R=kjellander@chromium.org

Review URL: https://codereview.chromium.org/872423002

git-svn-id: http://src.chromium.org/svn/trunk/deps/third_party/webrtc/webrtc.DEPS@293821 4ff67af0-8c30-449e-8e8b-ad334ec8d88c
diff --git a/DEPS b/DEPS
index 30a5158..0ac437c 100644
--- a/DEPS
+++ b/DEPS
@@ -37,6 +37,12 @@
                 "webrtc.DEPS"],
   },
   {
+    "pattern": ".",
+    "action" : ["python",
+                "webrtc.DEPS/download_node.py",
+                "webrtc.DEPS"],
+  },
+  {
     # "Build" AppRTC, i.e. move it to the out/ dir where the browser test
     # can find it. This is only done on runhooks.
     "pattern": ".",
@@ -56,6 +62,12 @@
                 "webrtc.DEPS/build_apprtc_collider.py"],
   },
   {
+    # Build AppRTC closure Javascript.
+    "pattern": ".",
+    "action" : ["python",
+                "webrtc.DEPS/build_apprtc_closure.py"],
+  },
+  {
     # Download media files and tools used by the webrtc quality browser tests,
     # chrome/browser/media/chrome_webrtc_audio_quality_browsertest.cc and
     # chrome/browser/media/chrome_webrtc_video_quality_browsertest.cc.
diff --git a/build_apprtc_closure.py b/build_apprtc_closure.py
new file mode 100755
index 0000000..60703cf
--- /dev/null
+++ b/build_apprtc_closure.py
@@ -0,0 +1,48 @@
+#!/usr/bin/python
+# 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.
+
+"""Invokes the AppRTC closure compiler.
+
+The AppRTC javascript code must be closure-compiled. This script uses
+the node toolchain we downloaded earlier.
+"""
+
+import os
+import shutil
+import subprocess
+import sys
+
+import utils
+
+
+def main():
+  node_path = os.path.abspath('node')
+  if not os.path.exists(node_path):
+    return 'Expected node at %s.' % node_path
+  samples_path = os.path.join('src', 'out', 'webrtc-samples')
+  if not os.path.exists(samples_path):
+    return 'Expected webrtc-samples at %s.' % os.path.abspath(samples_path)
+
+  os.chdir(samples_path)
+  
+  if utils.GetPlatform() is 'win':
+    npm_bin = os.path.join(node_path, 'npm.cmd')
+    node_bin = os.path.join(node_path, 'node.exe')
+  else:
+    npm_bin = os.path.join(node_path, 'bin', 'npm')
+    node_bin = os.path.join(node_path, 'bin', 'node')
+
+  subprocess.check_call([npm_bin, 'install'])
+  local_grunt_bin = os.path.join('node_modules', 'grunt-cli', 'bin', 'grunt')
+
+  if not os.path.exists(local_grunt_bin):
+    return ('Missing grunt-cli in the webrtc-samples checkout; did '
+            'npm install fail?')
+
+  subprocess.check_call([node_bin, local_grunt_bin, 'closurecompiler:debug'])
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/copy_apprtc.py b/copy_apprtc.py
index c091aa6..5a9a3c9 100755
--- a/copy_apprtc.py
+++ b/copy_apprtc.py
@@ -10,13 +10,25 @@
 understand those symlinks).
 """
 
+import os
 import shutil
 
+import utils
 
 if __name__ == '__main__':
-  web_samples_dir = 'webrtc-samples/samples/web'
-  shutil.rmtree('src/out/apprtc', ignore_errors=True)
-  shutil.copytree(web_samples_dir + '/content/apprtc',
-                  'src/out/apprtc', ignore=shutil.ignore_patterns('.svn'))
-  shutil.copyfile(web_samples_dir + '/js/adapter.js',
-		  'src/out/apprtc/js/adapter.js')
+  target_dir = os.path.join('src', 'out', 'webrtc-samples')
+  if utils.GetPlatform() is 'win':
+    # Work around the fact that node_modules create ridiculously long paths.
+    # Unfortunately shutil will choke on those on Windows, but not rmdir.
+    os.system('rmdir /s /q %s' % target_dir)
+  else:
+    shutil.rmtree(target_dir, ignore_errors=True)
+  shutil.copytree('webrtc-samples',
+                  target_dir, ignore=shutil.ignore_patterns('.svn', '.git'))
+  apprtc_subdir = os.path.join('samples', 'web', 'content', 'apprtc')
+
+  # This file is symlinked on windows, so copy it since win doesn't understand
+  # symlinks.
+  shutil.copyfile(os.path.join('webrtc-samples', 'samples', 'web',
+                               'js', 'adapter.js'),
+                  os.path.join(target_dir, apprtc_subdir, 'js', 'adapter.js'))
diff --git a/download_golang.py b/download_golang.py
index c61ba00..ce7573e 100755
--- a/download_golang.py
+++ b/download_golang.py
@@ -19,18 +19,6 @@
 import utils
 
 
-def _DownloadFilesFromGoogleStorage(webrtc_deps_path):
-  print 'Downloading files in %s...' % webrtc_deps_path
-
-  extension = 'bat' if 'win32' in sys.platform else 'py'
-  cmd = ['download_from_google_storage.%s' % extension,
-         '--bucket=chromium-webrtc-resources',
-         '--auto_platform',
-         '--recursive',
-         '--directory', webrtc_deps_path]
-  subprocess.check_call(cmd)
-
-
 def _GetGoArchivePathForPlatform():
   archive_extension = 'zip' if utils.GetPlatform() == 'win' else 'tar.gz'
   return os.path.join(utils.GetPlatform(), 'go.%s' % archive_extension)
@@ -47,9 +35,10 @@
   archive_path = os.path.join(golang_path, _GetGoArchivePathForPlatform())
   old_archive_sha1 = utils.ComputeSHA1(archive_path)
 
-  _DownloadFilesFromGoogleStorage(golang_path)
+  utils.DownloadFilesFromGoogleStorage(golang_path)
 
-  if old_archive_sha1 != utils.ComputeSHA1(archive_path):
+  if (old_archive_sha1 != utils.ComputeSHA1(archive_path)
+      or not os.path.exists('go')):
     utils.DeleteDirNextToGclient('go')
     utils.UnpackToWorkingDir(archive_path)
 
diff --git a/download_node.py b/download_node.py
new file mode 100755
index 0000000..8d8d82c
--- /dev/null
+++ b/download_node.py
@@ -0,0 +1,55 @@
+#!/usr/bin/python
+# 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.
+
+"""Downloads the node binaries from WebRTC storage and unpacks it.
+
+Requires that depot_tools is installed and in the PATH. This script expects
+to run with Chrome's base dir as the working directory, e.g. where the .gclient
+file is. This is what should happen if this script is invoked as a hook action.
+"""
+
+import glob
+import os
+import sys
+import tarfile
+import zipfile
+
+import utils
+
+
+def _GetNodeArchivePathForPlatform():
+  archive_extension = 'zip' if utils.GetPlatform() == 'win' else 'tar.gz'
+  return os.path.join(utils.GetPlatform(), 'node.%s' % archive_extension)
+
+
+def _StripVersionNumberFromNodeDir():
+  # The node dir will be called node-x-x-x.tar.gz, rename to just node.
+  unpacked_name = glob.glob('node*')
+  assert len(unpacked_name) == 1, 'Should have precisely one node!'
+  os.rename(unpacked_name[0], 'node')
+
+
+def main(argv):
+  if len(argv) == 1:
+    return 'Usage: %s <path to webrtc.DEPS>' % argv[0]
+  if not os.path.exists('.gclient'):
+    return 'Invoked from wrong dir; invoke from dir with .gclient'
+
+  webrtc_deps_path = argv[1]
+  node_path = os.path.join(webrtc_deps_path, 'node')
+  archive_path = os.path.join(node_path, _GetNodeArchivePathForPlatform())
+  old_archive_sha1 = utils.ComputeSHA1(archive_path)
+
+  utils.DownloadFilesFromGoogleStorage(node_path)
+
+  if (old_archive_sha1 != utils.ComputeSHA1(archive_path)
+      or not os.path.exists('node')):
+    utils.DeleteDirNextToGclient('node')
+    utils.UnpackToWorkingDir(archive_path)
+    _StripVersionNumberFromNodeDir()
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/node/linux/node.tar.gz.sha1 b/node/linux/node.tar.gz.sha1
new file mode 100644
index 0000000..5706dea
--- /dev/null
+++ b/node/linux/node.tar.gz.sha1
@@ -0,0 +1 @@
+3a202a749492e48542d2c28220e43ef6dae084bc
\ No newline at end of file
diff --git a/node/mac/node.tar.gz.sha1 b/node/mac/node.tar.gz.sha1
new file mode 100644
index 0000000..ed7bec7
--- /dev/null
+++ b/node/mac/node.tar.gz.sha1
@@ -0,0 +1 @@
+98f61cb09685ed45f2db6e0fc5ccbdd273204091
\ No newline at end of file
diff --git a/node/win/README b/node/win/README
new file mode 100644
index 0000000..640dab1
--- /dev/null
+++ b/node/win/README
@@ -0,0 +1,9 @@
+This zip file requires some manual work. First, download node.exe
+from http://nodejs.org/download/, then download the npm stuff from
+http://nodejs.org/dist/npm/. Unzip both in the same dir and do this:
+
+mkdir node
+mv node.exe node
+mv npm.cmd node
+mv node_modules node
+zip -r node.zip node
diff --git a/node/win/node.zip.sha1 b/node/win/node.zip.sha1
new file mode 100644
index 0000000..f5bf9e4
--- /dev/null
+++ b/node/win/node.zip.sha1
@@ -0,0 +1 @@
+a0f8d1cf0ef8375f1a760a3c33d6a9f69b045103
\ No newline at end of file
diff --git a/utils.py b/utils.py
index 1cf998d..827cd3e 100755
--- a/utils.py
+++ b/utils.py
@@ -9,10 +9,23 @@
 import os
 import shutil
 import sys
+import subprocess
 import tarfile
 import zipfile
 
 
+def DownloadFilesFromGoogleStorage(path):
+  print 'Downloading files in %s...' % path
+
+  extension = 'bat' if 'win32' in sys.platform else 'py'
+  cmd = ['download_from_google_storage.%s' % extension,
+         '--bucket=chromium-webrtc-resources',
+         '--auto_platform',
+         '--recursive',
+         '--directory', path]
+  subprocess.check_call(cmd)
+
+
 def ComputeSHA1(path):
   if not os.path.exists(path):
     return 0