OLD | NEW |
(Empty) | |
| 1 # Copyright 2016 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 import collections |
| 6 import re |
| 7 |
| 8 |
| 9 DEPS = [ |
| 10 'depot_tools/cipd', |
| 11 'gae_sdk', |
| 12 'gsutil', |
| 13 'recipe_engine/path', |
| 14 'recipe_engine/python', |
| 15 'recipe_engine/raw_io', |
| 16 'recipe_engine/step', |
| 17 'zip', |
| 18 ] |
| 19 |
| 20 # CIPD builder service account, deployed by Puppet. |
| 21 _CIPD_CREDENTIAL_PATH = ('/creds/service_accounts/' |
| 22 'service-account-cipd-builder.json') |
| 23 |
| 24 |
| 25 def RunSteps(api): |
| 26 pb = _PackageBuilder(api) |
| 27 |
| 28 # Determine the current GAE SDK version. |
| 29 try: |
| 30 version = pb.latest_upstream_version() |
| 31 except pb.VersionParseError as e: |
| 32 api.python.failing_step('Version Fetch', |
| 33 'Failed to fetch latest version: %s' % (e,)) |
| 34 |
| 35 # Make sure the CIPD client is installed. |
| 36 api.cipd.install_client() |
| 37 api.cipd.set_service_account_credentials(_CIPD_CREDENTIAL_PATH) |
| 38 |
| 39 # Iterate over all of the GAE SDK packages and build any that don't exist. |
| 40 version_tag = pb.version_tag(version) |
| 41 pkg_outdir = api.path.mkdtemp('gae_sdk_package') |
| 42 for plat, arch in api.gae_sdk.all_packages: |
| 43 pkg_name = api.gae_sdk.package(plat, arch=arch) |
| 44 with api.step.nest('Sync %s' % (pkg_name,)): |
| 45 step = api.cipd.search(pkg_name, '%s:%s' % (version_tag)) |
| 46 if len(step.json.output['result']) > 0: |
| 47 api.python.succeeding_step('Synced', 'Package is up to date.') |
| 48 continue |
| 49 |
| 50 # Create a temporary directory to build the package in. |
| 51 pkg_base = pb.download_and_unpack(plat, arch, version) |
| 52 |
| 53 # Build and register our CIPD package. |
| 54 pkg_path = pkg_outdir.join('gae_sdk_%s_%s.pkg' % (plat, arch)) |
| 55 api.cipd.build( |
| 56 pkg_base, |
| 57 pkg_path, |
| 58 pkg_name, |
| 59 install_mode='copy', |
| 60 ) |
| 61 api.cipd.register( |
| 62 pkg_name, |
| 63 pkg_path, |
| 64 refs=[api.gae_sdk.latest_ref], |
| 65 tags={version_tag[0]: version_tag[1]}, |
| 66 ) |
| 67 |
| 68 |
| 69 class _PackageBuilder(object): |
| 70 # The Google Storage GAE SDK bucket base. All SDK packages are stored in here |
| 71 # under a basename + version ZIP file. |
| 72 _GS_BUCKET_BASE = 'gs://appengine-sdks/featured' |
| 73 # The GS path to the "LATEST" YAML file. |
| 74 _GS_VERSION_YAML = '%s/VERSION' % (_GS_BUCKET_BASE,) |
| 75 |
| 76 # Hacky regex for the "release" YAML variable. |
| 77 _RE_RELEASE = re.compile(r'^release:\s+"([^"]+)"$') |
| 78 |
| 79 class VersionParseError(Exception): |
| 80 pass |
| 81 |
| 82 def __init__(self, api): |
| 83 self._api = api |
| 84 |
| 85 def version_tag(self, version): |
| 86 return ('gae_sdk_version', version) |
| 87 |
| 88 @property |
| 89 def api(self): |
| 90 return self._api |
| 91 |
| 92 def latest_upstream_version(self): |
| 93 step_result = self.api.gsutil.cat( |
| 94 self._GS_VERSION_YAML, |
| 95 name='Get Latest', |
| 96 stdout=self.api.raw_io.output()) |
| 97 latest = self._parse_latest_yaml(step_result.stdout) |
| 98 step_result.presentation.step_text += ' %s' % (latest,) |
| 99 return latest |
| 100 |
| 101 @classmethod |
| 102 def _parse_latest_yaml(cls, text): |
| 103 # Rather than import a YAML parser, we will specifically search for the |
| 104 # string: |
| 105 # |
| 106 # release: "<version>" |
| 107 for line in text.splitlines(): |
| 108 m = cls._RE_RELEASE.match(line) |
| 109 if m: |
| 110 return m.group(1) |
| 111 raise cls.VersionParseError('Could not parse release version from YAML.') |
| 112 |
| 113 def download_and_unpack(self, plat, arch, version): |
| 114 # Get the package base for this OS. |
| 115 _, base, dirname = self.api.gae_sdk.package_spec(plat, arch) |
| 116 name = '%s%s.zip' % (base, version) |
| 117 artifact_url = '%s/%s' % (self._GS_BUCKET_BASE, name) |
| 118 |
| 119 tdir = self.api.path.mkdtemp('gae_sdk') |
| 120 dst = tdir.join(name) # Store the ZIP file here. |
| 121 unzip_dir = tdir.join('unpack') # Unzip contents here. |
| 122 self.api.gsutil.download_url( |
| 123 artifact_url, |
| 124 dst, |
| 125 name='Download %s %s' % (plat, arch,)) |
| 126 self.api.zip.unzip( |
| 127 'Unzip %s %s' % (plat, arch), |
| 128 dst, |
| 129 unzip_dir, |
| 130 quiet=True) |
| 131 |
| 132 pkg_dir = unzip_dir.join(dirname) |
| 133 self.api.path.mock_add_paths(pkg_dir) |
| 134 assert self.api.path.exists(pkg_dir), ( |
| 135 'Package directory [%s] does not exist' % (pkg_dir,)) |
| 136 return pkg_dir |
| 137 |
| 138 |
| 139 def GenTests(api): |
| 140 LATEST_YAML = '\n'.join(( |
| 141 'release: "1.2.3"', |
| 142 'foo: bar', |
| 143 'baz:', |
| 144 ' - qux', |
| 145 )) |
| 146 |
| 147 def cipd_pkg(plat, pkg_base, exists): |
| 148 pkg_name = 'infra/gae_sdk/%s/%s' % (plat, pkg_base) |
| 149 cipd_step = 'cipd search %s gae_sdk_version:1.2.3' % (pkg_name,) |
| 150 instances = (2) if exists else (0) |
| 151 return api.step_data('Sync %s.%s' % (pkg_name, cipd_step), |
| 152 api.cipd.example_search(pkg_name, instances=instances)) |
| 153 |
| 154 yield (api.test('packages') + |
| 155 api.step_data('gsutil Get Latest', |
| 156 api.raw_io.stream_output(LATEST_YAML, stream='stdout')) + |
| 157 cipd_pkg('go', 'linux-amd64', False) + |
| 158 cipd_pkg('go', 'linux-386', True) + |
| 159 cipd_pkg('go', 'mac-amd64', True) + |
| 160 cipd_pkg('python', 'all', False)) |
| 161 |
| 162 yield (api.test('bad_version_yaml') + |
| 163 api.step_data('gsutil Get Latest', |
| 164 api.raw_io.stream_output('', stream='stdout'))) |
OLD | NEW |