OLD | NEW |
(Empty) | |
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. |
| 4 |
| 5 """Utility functions common to the Google storage scripts.""" |
| 6 |
| 7 import hashlib |
| 8 import os |
| 9 import re |
| 10 import sys |
| 11 |
| 12 import subprocess2 |
| 13 |
| 14 |
| 15 class Gsutil(object): |
| 16 """Call gsutil with some predefined settings.""" |
| 17 def __init__(self, path, boto_path=None, timeout=None): |
| 18 if not os.path.exists(path): |
| 19 raise OSError('GSUtil not found in %s' % path) |
| 20 self.path = path |
| 21 self.timeout = timeout |
| 22 self.boto_path = boto_path |
| 23 |
| 24 def call(self, *args): |
| 25 env = os.environ.copy() |
| 26 if self.boto_path is not None: |
| 27 env['AWS_CREDENTIAL_FILE'] = self.boto_path |
| 28 return subprocess2.call((sys.executable, self.path) + args, |
| 29 env=env, |
| 30 timeout=self.timeout) |
| 31 |
| 32 def check_call(self, *args): |
| 33 env = os.environ.copy() |
| 34 if self.boto_path is not None: |
| 35 env['AWS_CREDENTIAL_FILE'] = self.boto_path |
| 36 ((out, err), code) = subprocess2.communicate( |
| 37 (sys.executable, self.path) + args, |
| 38 stdout=subprocess2.PIPE, |
| 39 stderr=subprocess2.PIPE, |
| 40 env=env, |
| 41 timeout=self.timeout) |
| 42 |
| 43 # Parse output. |
| 44 status_code_match = re.search('status=([0-9]+)', err) |
| 45 if status_code_match: |
| 46 return int(status_code_match.groups(1)) |
| 47 elif ('You are attempting to access protected data with ' |
| 48 'no configured credentials.' in err): |
| 49 return (403, out, err) |
| 50 elif 'No such object' in err: |
| 51 return (404, out, err) |
| 52 else: |
| 53 return (code, out, err) |
| 54 |
| 55 def clone(self): |
| 56 return Gsutil(self.path, self.boto_path, self.timeout) |
| 57 |
| 58 |
| 59 def CheckBucketPermissions(bucket, gsutil): |
| 60 if not bucket: |
| 61 print >> sys.stderr, 'Missing bucket %s.' |
| 62 return (None, 1) |
| 63 base_url = 'gs://%s' % bucket |
| 64 |
| 65 # Check if we have permissions to the Google Storage bucket. |
| 66 code, _, ls_err = gsutil.check_call('ls', base_url) |
| 67 if code == 403: |
| 68 code, _, _ = gsutil.call('config') |
| 69 if code != 0: |
| 70 print >> sys.stderr, 'Error while authenticating to %s.' % base_url |
| 71 elif code == 404: |
| 72 print >> sys.stderr, '%s not found.' % base_url |
| 73 elif code != 0: |
| 74 print >> sys.stderr, ls_err |
| 75 return (base_url, code) |
| 76 |
| 77 |
| 78 def GetSHA1(filename): |
| 79 sha1 = hashlib.sha1() |
| 80 with open(filename, 'rb') as f: |
| 81 while True: |
| 82 # Read in 1mb chunks, so it doesn't all have to be loaded into memory. |
| 83 chunk = f.read(1024*1024) |
| 84 if not chunk: |
| 85 break |
| 86 sha1.update(chunk) |
| 87 return sha1.hexdigest() |
| 88 |
| 89 |
| 90 def GetMD5(filename, lock): |
| 91 md5_calculator = hashlib.md5() |
| 92 with lock: |
| 93 with open(filename, 'rb') as f: |
| 94 while True: |
| 95 chunk = f.read(1024*1024) |
| 96 if not chunk: |
| 97 break |
| 98 md5_calculator.update(chunk) |
| 99 return md5_calculator.hexdigest() |
| 100 |
| 101 |
| 102 def GetMD5Cached(filename, lock): |
| 103 """Don't calculate the MD5 if we can find a .md5 file.""" |
| 104 # See if we can find an existing MD5 sum stored in a file. |
| 105 if os.path.exists('%s.md5' % filename): |
| 106 with open('%s.md5' % filename) as f: |
| 107 md5_match = re.search('([a-z0-9]{32})', f.read()) |
| 108 if md5_match: |
| 109 return md5_match.group(1) |
| 110 else: |
| 111 md5_hash = GetMD5(filename, lock) |
| 112 with open('%s.md5' % filename, 'w') as f: |
| 113 f.write(md5_hash) |
| 114 return md5_hash |
OLD | NEW |