Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

Side by Side Diff: gsutil.py

Issue 742173002: GSUtil.py wrapper script (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/depot_tools.git@master
Patch Set: Nits Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « .gitignore ('k') | tests/gsutil_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright (c) 2014 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """Run a pinned gsutil."""
7
8
9 import argparse
10 import shutil
11 import zipfile
12 import hashlib
13 import base64
14 import os
15 import sys
16 import json
17 import urllib
18 import subprocess
19
20
21 GSUTIL_URL = 'https://storage.googleapis.com/pub/'
22 API_URL = 'https://www.googleapis.com/storage/v1/b/pub/o/'
23
24 THIS_DIR = os.path.dirname(os.path.abspath(__file__))
25 DEFAULT_BIN_DIR = os.path.join(THIS_DIR, 'external_bin', 'gsutil')
26 DEFAULT_FALLBACK_GSUTIL = os.path.join(
27 THIS_DIR, 'third_party', 'gsutil', 'gsutil')
28
29
30 class SubprocessError(Exception):
31 pass
32
33
34 class InvalidGsutilError(Exception):
35 pass
36
37
38 def call(args, verbose=True, **kwargs):
39 kwargs['stdout'] = subprocess.PIPE
40 kwargs['stderr'] = subprocess.STDOUT
41 proc = subprocess.Popen(args, **kwargs)
42 out = []
43 for line in proc.stdout:
44 out.append(line)
45 if verbose:
46 sys.stdout.write(line)
47 code = proc.wait()
48 if code:
49 raise SubprocessError('%s failed with %s' % (args, code))
50 return ''.join(out)
51
52
53 def download_gsutil(version, target_dir):
54 """Downloads gsutil into the target_dir."""
55 filename = 'gsutil_%s.zip' % version
56 target_filename = os.path.join(target_dir, filename)
57
58 # Check if the target exists already.
59 if os.path.exists(target_filename):
60 md5_calc = hashlib.md5()
61 with open(target_filename, 'rb') as f:
62 while True:
63 buf = f.read(4096)
64 if not buf:
65 break
66 md5_calc.update(buf)
67 local_md5 = md5_calc.hexdigest()
68
69 metadata_url = '%s%s' % (API_URL, filename)
70 metadata = json.load(urllib.urlopen(metadata_url))
71 remote_md5 = base64.b64decode(metadata['md5Hash'])
72
73 if local_md5 == remote_md5:
74 return target_filename
75 os.remove(target_filename)
76
77 # Do the download.
78 url = '%s%s' % (GSUTIL_URL, filename)
79 u = urllib.urlopen(url)
80 with open(target_filename, 'wb') as f:
81 while True:
82 buf = u.read(4096)
83 if not buf:
84 break
85 f.write(buf)
86 return target_filename
87
88
89 def check_gsutil(gsutil_bin):
90 """Run gsutil version and make sure it runs."""
91 try:
92 call([sys.executable, gsutil_bin, 'version'], verbose=False)
93 return True
94 except SubprocessError:
95 return False
96
97
98 def ensure_gsutil(version, target):
99 bin_dir = os.path.join(target, 'gsutil_%s' % version)
100 gsutil_bin = os.path.join(bin_dir, 'gsutil', 'gsutil')
101 if os.path.isfile(gsutil_bin) and check_gsutil(gsutil_bin):
102 # Everything is awesome! we're all done here.
103 return gsutil_bin
104
105 if os.path.isdir(bin_dir):
106 # Clean up if we're redownloading a corrupted gsutil.
107 shutil.rmtree(bin_dir)
108 cache_dir = os.path.join(target, '.cache_dir')
109 if not os.path.isdir(cache_dir):
110 os.makedirs(cache_dir)
111 target_zip_filename = download_gsutil(version, cache_dir)
112 with zipfile.ZipFile(target_zip_filename, 'r') as target_zip:
113 target_zip.extractall(bin_dir)
114
115 # Final check that the gsutil bin is okay. This should never fail.
116 if not check_gsutil(gsutil_bin):
117 raise InvalidGsutilError()
118
119 return gsutil_bin
120
121
122 def run_gsutil(force_version, fallback, target, args):
123 if force_version:
124 gsutil_bin = ensure_gsutil(force_version, target)
125 else:
126 gsutil_bin = fallback
127 cmd = [sys.executable, gsutil_bin] + args
128 call(cmd)
129
130
131 def parse_args():
132 parser = argparse.ArgumentParser()
133 parser.add_argument('--force-version')
134 parser.add_argument('--fallback', default=DEFAULT_FALLBACK_GSUTIL)
135 parser.add_argument('--target', default=DEFAULT_BIN_DIR)
136 parser.add_argument('args', nargs=argparse.REMAINDER)
137
138 args = parser.parse_args()
139 return args.force_version, args.fallback, args.target, args.args
140
141
142 def main():
143 force_version, fallback, target, args = parse_args()
144 run_gsutil(force_version, fallback, target, args)
145
146 if __name__ == '__main__':
147 sys.exit(main())
OLDNEW
« no previous file with comments | « .gitignore ('k') | tests/gsutil_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698