Index: scripts/slave/recipes/infra/gae_sdk_cipd_packager.py |
diff --git a/scripts/slave/recipes/infra/gae_sdk_cipd_packager.py b/scripts/slave/recipes/infra/gae_sdk_cipd_packager.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..be49e4ebcd7fd31e236f4bf6fd1dd85ba2545686 |
--- /dev/null |
+++ b/scripts/slave/recipes/infra/gae_sdk_cipd_packager.py |
@@ -0,0 +1,164 @@ |
+# Copyright 2016 The Chromium Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+import collections |
+import re |
+ |
+ |
+DEPS = [ |
+ 'depot_tools/cipd', |
+ 'gae_sdk', |
+ 'gsutil', |
+ 'recipe_engine/path', |
+ 'recipe_engine/python', |
+ 'recipe_engine/raw_io', |
+ 'recipe_engine/step', |
+ 'zip', |
+] |
+ |
+# CIPD builder service account, deployed by Puppet. |
+_CIPD_CREDENTIAL_PATH = ('/creds/service_accounts/' |
+ 'service-account-cipd-builder.json') |
+ |
+ |
+def RunSteps(api): |
+ pb = _PackageBuilder(api) |
+ |
+ # Determine the current GAE SDK version. |
+ try: |
+ version = pb.latest_upstream_version() |
+ except pb.VersionParseError as e: |
+ api.python.failing_step('Version Fetch', |
+ 'Failed to fetch latest version: %s' % (e,)) |
+ |
+ # Make sure the CIPD client is installed. |
+ api.cipd.install_client() |
+ api.cipd.set_service_account_credentials(_CIPD_CREDENTIAL_PATH) |
+ |
+ # Iterate over all of the GAE SDK packages and build any that don't exist. |
+ version_tag = pb.version_tag(version) |
+ pkg_outdir = api.path.mkdtemp('gae_sdk_package') |
+ for plat, arch in api.gae_sdk.all_packages: |
+ pkg_name = api.gae_sdk.package(plat, arch=arch) |
+ with api.step.nest('Sync %s' % (pkg_name,)): |
+ step = api.cipd.search(pkg_name, '%s:%s' % (version_tag)) |
+ if len(step.json.output['result']) > 0: |
+ api.python.succeeding_step('Synced', 'Package is up to date.') |
+ continue |
+ |
+ # Create a temporary directory to build the package in. |
+ pkg_base = pb.download_and_unpack(plat, arch, version) |
+ |
+ # Build and register our CIPD package. |
+ pkg_path = pkg_outdir.join('gae_sdk_%s_%s.pkg' % (plat, arch)) |
+ api.cipd.build( |
+ pkg_base, |
+ pkg_path, |
+ pkg_name, |
+ install_mode='copy', |
+ ) |
+ api.cipd.register( |
+ pkg_name, |
+ pkg_path, |
+ refs=[api.gae_sdk.latest_ref], |
+ tags={version_tag[0]: version_tag[1]}, |
+ ) |
+ |
+ |
+class _PackageBuilder(object): |
+ # The Google Storage GAE SDK bucket base. All SDK packages are stored in here |
+ # under a basename + version ZIP file. |
+ _GS_BUCKET_BASE = 'gs://appengine-sdks/featured' |
+ # The GS path to the "LATEST" YAML file. |
+ _GS_VERSION_YAML = '%s/VERSION' % (_GS_BUCKET_BASE,) |
+ |
+ # Hacky regex for the "release" YAML variable. |
+ _RE_RELEASE = re.compile(r'^release:\s+"([^"]+)"$') |
+ |
+ class VersionParseError(Exception): |
+ pass |
+ |
+ def __init__(self, api): |
+ self._api = api |
+ |
+ def version_tag(self, version): |
+ return ('gae_sdk_version', version) |
+ |
+ @property |
+ def api(self): |
+ return self._api |
+ |
+ def latest_upstream_version(self): |
+ step_result = self.api.gsutil.cat( |
+ self._GS_VERSION_YAML, |
+ name='Get Latest', |
+ stdout=self.api.raw_io.output()) |
+ latest = self._parse_latest_yaml(step_result.stdout) |
+ step_result.presentation.step_text += ' %s' % (latest,) |
+ return latest |
+ |
+ @classmethod |
+ def _parse_latest_yaml(cls, text): |
+ # Rather than import a YAML parser, we will specifically search for the |
+ # string: |
+ # |
+ # release: "<version>" |
+ for line in text.splitlines(): |
+ m = cls._RE_RELEASE.match(line) |
+ if m: |
+ return m.group(1) |
+ raise cls.VersionParseError('Could not parse release version from YAML.') |
+ |
+ def download_and_unpack(self, plat, arch, version): |
+ # Get the package base for this OS. |
+ _, base, dirname = self.api.gae_sdk.package_spec(plat, arch) |
+ name = '%s%s.zip' % (base, version) |
+ artifact_url = '%s/%s' % (self._GS_BUCKET_BASE, name) |
+ |
+ tdir = self.api.path.mkdtemp('gae_sdk') |
+ dst = tdir.join(name) # Store the ZIP file here. |
+ unzip_dir = tdir.join('unpack') # Unzip contents here. |
+ self.api.gsutil.download_url( |
+ artifact_url, |
+ dst, |
+ name='Download %s %s' % (plat, arch,)) |
+ self.api.zip.unzip( |
+ 'Unzip %s %s' % (plat, arch), |
+ dst, |
+ unzip_dir, |
+ quiet=True) |
+ |
+ pkg_dir = unzip_dir.join(dirname) |
+ self.api.path.mock_add_paths(pkg_dir) |
+ assert self.api.path.exists(pkg_dir), ( |
+ 'Package directory [%s] does not exist' % (pkg_dir,)) |
+ return pkg_dir |
+ |
+ |
+def GenTests(api): |
+ LATEST_YAML = '\n'.join(( |
+ 'release: "1.2.3"', |
+ 'foo: bar', |
+ 'baz:', |
+ ' - qux', |
+ )) |
+ |
+ def cipd_pkg(plat, pkg_base, exists): |
+ pkg_name = 'infra/gae_sdk/%s/%s' % (plat, pkg_base) |
+ cipd_step = 'cipd search %s gae_sdk_version:1.2.3' % (pkg_name,) |
+ instances = (2) if exists else (0) |
+ return api.step_data('Sync %s.%s' % (pkg_name, cipd_step), |
+ api.cipd.example_search(pkg_name, instances=instances)) |
+ |
+ yield (api.test('packages') + |
+ api.step_data('gsutil Get Latest', |
+ api.raw_io.stream_output(LATEST_YAML, stream='stdout')) + |
+ cipd_pkg('go', 'linux-amd64', False) + |
+ cipd_pkg('go', 'linux-386', True) + |
+ cipd_pkg('go', 'mac-amd64', True) + |
+ cipd_pkg('python', 'all', False)) |
+ |
+ yield (api.test('bad_version_yaml') + |
+ api.step_data('gsutil Get Latest', |
+ api.raw_io.stream_output('', stream='stdout'))) |