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 from recipe_engine import recipe_api | |
9 | |
10 | |
11 class GaeSdkApi(recipe_api.RecipeApi): | |
12 | |
13 PLAT_PYTHON = 'python' | |
14 PLAT_GO = 'go' | |
15 | |
16 # The Google Storage GAE SDK bucket base. All SDK packages are stored in here | |
17 # under a basename + version ZIP file. | |
18 GS_BUCKET_BASE = 'gs://appengine-sdks/featured' | |
19 # The GS path to the "LATEST" YAML file. | |
20 GS_VERSION_YAML = '%s/VERSION' % (GS_BUCKET_BASE,) | |
21 | |
22 # Hacky regex for the "release" YAML variable. | |
23 RE_RELEASE = re.compile(r'^release:\s+"([^"]+)"$') | |
24 | |
25 # Map of {Platform => {Arch => (base, dirname)}}. Platform names are | |
26 # "recipe_engine/platform" values. | |
27 _PKG_MAP = { | |
28 PLAT_PYTHON: { | |
29 'all': ('google_appengine_', 'google_appengine'), | |
30 }, | |
31 PLAT_GO: { | |
32 'linux-amd64': ('go_appengine_sdk_linux_amd64-', 'go_appengine'), | |
33 'linux-386': ('go_appengine_sdk_linux_386-', 'go_appengine'), | |
34 'mac-amd64': ('go_appengine_sdk_darwin_amd64-', 'go_appengine'), | |
35 }, | |
36 } | |
37 | |
38 # Map of architecture bitness to CIPD bitness suffix. | |
39 _BITS_MAP = { | |
40 64: 'amd64', | |
41 32: '386', | |
iannucci
2016/09/30 21:05:21
hm... I didn't realize it was 386 instead of x86.
dnj
2016/09/30 22:54:54
I've generally seen i386 / i686 vs. amd64 / x86_64
| |
42 } | |
43 | |
44 | |
45 class VersionParseError(Exception): | |
46 pass | |
47 | |
48 | |
49 class PackageNotFound(Exception): | |
50 def __init__(self, plat, arch): | |
51 super(GaeSdkApi.PackageNotFound, self).__init__( | |
52 'Package not found for %s on %s' % (plat, arch)) | |
53 self.plat = plat | |
54 self.arch = arch | |
55 | |
56 | |
57 def __init__(self, *args, **kwargs): | |
58 super(GaeSdkApi, self).__init__(*args, **kwargs) | |
59 self._latest = None | |
60 | |
61 def _step_name(self, desc): | |
62 return 'GAE SDK: %s' % (desc,) | |
63 | |
64 @property | |
65 def latest_ref(self): | |
66 return 'latest' | |
67 | |
68 def version_tag(self, version): | |
69 return ('gae_sdk_version', version) | |
70 | |
71 def _package_spec(self, plat, arch): | |
72 plat_dict = self._PKG_MAP.get(plat, {}) | |
73 for a in (arch, 'all'): | |
74 spec = plat_dict.get(a) | |
75 if spec: | |
76 download_base, dirname = spec | |
77 pkg_name = 'infra/gae_sdk/%s/%s' % (plat, a) | |
78 return pkg_name, download_base, dirname | |
79 raise self.PackageNotFound(plat, arch) | |
80 | |
81 def package(self, plat, arch=None): | |
82 arch = arch or '%s-%s' % ( | |
83 self.m.platform.name, self._BITS_MAP[self.m.platform.bits]) | |
84 pkg_name, _, _ = self._package_spec(plat, arch) | |
85 return pkg_name | |
86 | |
87 @property | |
88 def platforms(self): | |
89 return sorted(self._PKG_MAP.keys()) | |
90 | |
91 @property | |
92 def all_packages(self): | |
93 for plat, arch_dict in sorted(self._PKG_MAP.items()): | |
94 for arch in sorted(arch_dict.keys()): | |
95 yield plat, arch | |
96 | |
97 def latest_upstream_version(self): | |
98 if self._latest is None: | |
99 step_result = self.m.gsutil.cat( | |
100 self.GS_VERSION_YAML, | |
101 name=self._step_name('Get Latest'), | |
102 stdout=self.m.raw_io.output()) | |
103 self._latest = self._parse_latest_yaml(step_result.stdout) | |
104 step_result.presentation.step_text += ' %s' % (self._latest,) | |
105 return self._latest | |
106 | |
107 @classmethod | |
108 def _parse_latest_yaml(cls, text): | |
109 # Rather than import a YAML parser, we will specifically search for the | |
110 # string: | |
111 # | |
112 # release: "<version>" | |
113 for line in text.splitlines(): | |
114 m = cls.RE_RELEASE.match(line) | |
115 if m: | |
116 return m.group(1) | |
117 raise cls.VersionParseError('Could not parse release version from YAML.') | |
118 | |
119 def download_and_unpack(self, plat, arch, version): | |
iannucci
2016/09/30 21:05:21
can we move this to the packaging recipe? Otherwis
dnj
2016/09/30 22:54:54
Done.
| |
120 # Get the package base for this OS. | |
121 _, base, dirname = self._package_spec(plat, arch) | |
122 name = '%s%s.zip' % (base, version) | |
123 artifact_url = '%s/%s' % (self.GS_BUCKET_BASE, name) | |
124 | |
125 tdir = self.m.path.mkdtemp('gae_sdk') | |
126 dst = tdir.join(name) # Store the ZIP file here. | |
127 unzip_dir = tdir.join('unpack') # Unzip contents here. | |
128 self.m.gsutil.download_url( | |
129 artifact_url, | |
130 dst, | |
131 name=self._step_name('Download %s %s' % (plat, arch,))) | |
132 self.m.zip.unzip( | |
133 self._step_name('Unzip %s %s' % (plat, arch)), | |
134 dst, | |
135 unzip_dir, | |
136 quiet=True) | |
137 | |
138 pkg_dir = unzip_dir.join(dirname) | |
139 self.m.path.mock_add_paths(pkg_dir) | |
140 assert self.m.path.exists(pkg_dir), ( | |
141 'Package directory [%s] does not exist' % (pkg_dir,)) | |
142 return pkg_dir | |
143 | |
144 def fetch(self, plat, dst): | |
iannucci
2016/09/30 21:05:21
it should somehow be made clear that this is reall
dnj
2016/09/30 22:54:54
Done.
| |
145 pkg = self.package(plat) | |
146 self.m.cipd.ensure(dst, {pkg: self.latest_ref}) | |
OLD | NEW |