copy gs_utils.py from skia repo into common repo

BUG=skia:2618
R=borenet@google.com

Review URL: https://codereview.chromium.org/385673002
diff --git a/DEPS b/DEPS
new file mode 100644
index 0000000..3580231
--- /dev/null
+++ b/DEPS
@@ -0,0 +1,10 @@
+use_relative_paths = True
+
+# Dependencies on outside packages.
+#
+deps = {
+  "third_party/externals/google-api-python-client" : "https://github.com/google/google-api-python-client.git@ecc64a0a2baa4a77f35dec83ad05c6c9ba2d2841",
+  "third_party/externals/httplib2" : "https://github.com/jcgregorio/httplib2.git@7d1b88a3cf34774242bf4c0578c09c0092bb05d8",
+  "third_party/externals/oauth2client" : "https://github.com/google/oauth2client.git@d02b317af0313dcf66755844f5421651af5eb356",
+  "third_party/externals/uritemplate-py" : "https://github.com/uri-templates/uritemplate-py.git@1e780a49412cdbb273e9421974cb91845c124f3f",
+}
diff --git a/py/utils/gs_utils.py b/py/utils/gs_utils.py
new file mode 100755
index 0000000..efab8ad
--- /dev/null
+++ b/py/utils/gs_utils.py
@@ -0,0 +1,100 @@
+#!/usr/bin/python
+
+"""
+Copyright 2014 Google Inc.
+
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+
+Utilities for accessing Google Cloud Storage.
+"""
+
+# System-level imports
+import os
+import posixpath
+import sys
+
+# Imports from third-party code
+TRUNK_DIRECTORY = os.path.abspath(os.path.join(
+    os.path.dirname(__file__), os.pardir, os.pardir))
+for import_subdir in ['google-api-python-client', 'httplib2', 'oauth2client',
+                      'uritemplate-py']:
+  import_dirpath = os.path.join(
+      TRUNK_DIRECTORY, 'third_party', 'externals', import_subdir)
+  if import_dirpath not in sys.path:
+    # We need to insert at the beginning of the path, to make sure that our
+    # imported versions are favored over others that might be in the path.
+    # Also, the google-api-python-client checkout contains an empty
+    # oauth2client directory, which will confuse things unless we insert
+    # our checked-out oauth2client in front of it in the path.
+    sys.path.insert(0, import_dirpath)
+try:
+  from googleapiclient.discovery import build as build_service
+except ImportError:
+  # We should not require any googleapiclient dependencies to be
+  # installed at a system level, but in the meanwhile, if developers run into
+  # trouble they can install those system-level dependencies to get unblocked.
+  print ('We should not require any googleapiclient dependencies to be '
+         'installed at a system level, but it seems like some are missing. '
+         'Please install google-api-python-client to get those dependencies; '
+         'directions can be found at https://developers.google.com/'
+         'api-client-library/python/start/installation .  '
+         'More details in http://skbug.com/2641 ')
+  raise
+
+# Local imports
+import url_utils
+
+
+def download_file(source_bucket, source_path, dest_path,
+                  create_subdirs_if_needed=False):
+  """ Downloads a single file from Google Cloud Storage to local disk.
+
+  Args:
+    source_bucket: GCS bucket to download the file from
+    source_path: full path (Posix-style) within that bucket
+    dest_path: full path (local-OS-style) on local disk to copy the file to
+    create_subdirs_if_needed: boolean; whether to create subdirectories as
+        needed to create dest_path
+  """
+  source_http_url = posixpath.join(
+      'http://storage.googleapis.com', source_bucket, source_path)
+  url_utils.copy_contents(source_url=source_http_url, dest_path=dest_path,
+                          create_subdirs_if_needed=create_subdirs_if_needed)
+
+
+def list_bucket_contents(bucket, subdir=None):
+  """ Returns files in the Google Cloud Storage bucket as a (dirs, files) tuple.
+
+  Uses the API documented at
+  https://developers.google.com/storage/docs/json_api/v1/objects/list
+
+  Args:
+    bucket: name of the Google Storage bucket
+    subdir: directory within the bucket to list, or None for root directory
+  """
+  # The GCS command relies on the subdir name (if any) ending with a slash.
+  if subdir and not subdir.endswith('/'):
+    subdir += '/'
+  subdir_length = len(subdir) if subdir else 0
+
+  storage = build_service('storage', 'v1')
+  command = storage.objects().list(
+      bucket=bucket, delimiter='/', fields='items(name),prefixes',
+      prefix=subdir)
+  results = command.execute()
+
+  # The GCS command returned two subdicts:
+  # prefixes: the full path of every directory within subdir, with trailing '/'
+  # items: property dict for each file object within subdir
+  #        (including 'name', which is full path of the object)
+  dirs = []
+  for dir_fullpath in results.get('prefixes', []):
+    dir_basename = dir_fullpath[subdir_length:]
+    dirs.append(dir_basename[:-1])  # strip trailing slash
+  files = []
+  for file_properties in results.get('items', []):
+    file_fullpath = file_properties['name']
+    file_basename = file_fullpath[subdir_length:]
+    files.append(file_basename)
+  return (dirs, files)
diff --git a/third_party/externals/README b/third_party/externals/README
new file mode 100644
index 0000000..7bd3808
--- /dev/null
+++ b/third_party/externals/README
@@ -0,0 +1 @@
+Packages imported by DEPS go here.