Chris Sosa | 47a7d4e | 2012-03-28 11:26:55 -0700 | [diff] [blame] | 1 | # Copyright (c) 2012 The Chromium OS 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 | """Module containing gsutil helper methods.""" |
| 6 | |
| 7 | import subprocess |
Chris Sosa | 101fd86 | 2012-06-12 17:44:53 -0700 | [diff] [blame] | 8 | import time |
Chris Sosa | 47a7d4e | 2012-03-28 11:26:55 -0700 | [diff] [blame] | 9 | |
| 10 | GSUTIL_ATTEMPTS = 5 |
| 11 | |
| 12 | |
| 13 | class GSUtilError(Exception): |
| 14 | """Exception raises when we run into an error running gsutil.""" |
| 15 | pass |
| 16 | |
| 17 | |
| 18 | def GSUtilRun(cmd, err_msg): |
| 19 | """Runs a GSUTIL command up to GSUTIL_ATTEMPTS number of times. |
| 20 | |
Chris Sosa | 101fd86 | 2012-06-12 17:44:53 -0700 | [diff] [blame] | 21 | Attempts are tried with exponential backoff. |
| 22 | |
Chris Sosa | 47a7d4e | 2012-03-28 11:26:55 -0700 | [diff] [blame] | 23 | Returns: |
| 24 | stdout of the called gsutil command. |
| 25 | Raises: |
| 26 | subprocess.CalledProcessError if all attempt to run gsutil cmd fails. |
| 27 | """ |
| 28 | proc = None |
Chris Sosa | 101fd86 | 2012-06-12 17:44:53 -0700 | [diff] [blame] | 29 | sleep_timeout = 1 |
Chris Sosa | 47a7d4e | 2012-03-28 11:26:55 -0700 | [diff] [blame] | 30 | for _attempt in range(GSUTIL_ATTEMPTS): |
| 31 | # Note processes can hang when capturing from stderr. This command |
| 32 | # specifically doesn't pipe stderr. |
| 33 | proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) |
| 34 | stdout, _stderr = proc.communicate() |
| 35 | if proc.returncode == 0: |
| 36 | return stdout |
Chris Sosa | 101fd86 | 2012-06-12 17:44:53 -0700 | [diff] [blame] | 37 | |
| 38 | time.sleep(sleep_timeout) |
| 39 | sleep_timeout *= 2 |
| 40 | |
Chris Sosa | 47a7d4e | 2012-03-28 11:26:55 -0700 | [diff] [blame] | 41 | else: |
| 42 | raise GSUtilError('%s GSUTIL cmd %s failed with return code %d' % ( |
| 43 | err_msg, cmd, proc.returncode)) |
| 44 | |
| 45 | |
| 46 | def DownloadFromGS(src, dst): |
| 47 | """Downloads object from gs_url |src| to |dst|. |
| 48 | |
| 49 | Raises: |
| 50 | GSUtilError: if an error occurs during the download. |
| 51 | """ |
| 52 | cmd = 'gsutil cp %s %s' % (src, dst) |
| 53 | msg = 'Failed to download "%s".' % src |
| 54 | GSUtilRun(cmd, msg) |