| # Copyright 2018 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 re |
| |
| from recipe_engine.post_process import ( |
| DoesNotRunRE, |
| Filter, |
| StepCommandContains, |
| StepCommandRE, |
| ) |
| |
| DEPS = [ |
| 'dart', |
| 'depot_tools/git', |
| 'depot_tools/gsutil', |
| 'recipe_engine/context', |
| 'recipe_engine/file', |
| 'recipe_engine/path', |
| 'recipe_engine/platform', |
| 'recipe_engine/properties', |
| 'recipe_engine/raw_io', |
| 'recipe_engine/step', |
| 'recipe_engine/url', |
| ] |
| |
| PACKAGE = 'dart-sdk' |
| RELEASE_BUCKET = 'gs://dart-archive/channels/%s/release/' |
| CHANNELS = ['dev', 'beta', 'stable'] |
| INSTALLER_NAME = 'install.ps1' |
| INSTALLER = 'https://chocolatey.org/%s' % INSTALLER_NAME |
| POWERSHELL = ( |
| 'C:\\\\WINDOWS\\\\system32\\\\WindowsPowerShell\\\\v1.0\\\\powershell.exe') |
| CHECKSUM = ('https://storage.googleapis.com/dart-archive/' |
| 'channels/%s/release/%s/sdk/dartsdk-windows-%s-release.zip.sha256sum') |
| SEMANTIC_VERSION_PATTERN = r'^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$' |
| |
| PYTHON_VERSION_COMPATIBILITY = "PY3" |
| |
| |
| def _is_version(version): |
| "Whether the string is a valid semantic version" |
| return re.match(SEMANTIC_VERSION_PATTERN, version) |
| |
| |
| def _is_modern_version(version): |
| "Whether the version is new enough to synchronize to chocolatey" |
| match = re.match(SEMANTIC_VERSION_PATTERN, version) |
| if not match: |
| return False |
| major = int(match['major']) |
| minor = int(match['minor']) |
| return 3 <= major or (2 == major and 17 <= minor) |
| |
| |
| def _channel_of_version(version): |
| for channel in CHANNELS: |
| if channel in version: |
| return channel |
| return 'stable' |
| |
| |
| def _parse_gsurl_release(line): |
| return line.split('/')[6] |
| |
| |
| def _parse_chocolatey_release(line): |
| return line.split(' ')[1] |
| |
| |
| def _decode_chocolatey_version(version): |
| "2.1.4.22-c-013-dev -> 2.1.4-22.13.dev" |
| majors = version.split('.') |
| if len(majors) <= 3: |
| return version |
| minors = majors[3].split('-') |
| # 1.8.5.0 |
| if len(minors) == 1: |
| return version |
| # 2.0.0.53-dev |
| if len(minors) == 2: |
| return '.'.join(majors[0:3]) + '-' + minors[1] + '.' + minors[0] + '.0' |
| # 2.8.0.20-dev-0 |
| if len(minors) == 3: |
| return '.'.join( |
| majors[0:3]) + '-' + minors[1] + '.' + minors[0] + '.' + minors[2] |
| # 2.17.0.69-c-002-beta |
| return '.'.join(majors[0:3]) + '-' + minors[0] + '.' + str(int( |
| minors[2])) + '.' + minors[3] |
| |
| |
| def _encode_chocolatey_version(version): |
| "2.1.4-22.13.dev -> 2.1.4.22-c-013-dev" |
| if '.dev' in version or '.beta' in version: |
| # todo(athom): remove when chocolatey supports semver 2.0.0 |
| # See https://github.com/chocolatey/choco/issues/1610 |
| (version, build) = version.split('-') |
| parts = build.split('.') |
| # pad with zeros, because chocolatey compares pre-release alphabetically |
| version = "%s.%s-c-%s-%s" % ( |
| (version, parts.pop(0)) + tuple(part.zfill(3) for part in parts)) |
| return version |
| |
| |
| def RunSteps(api): |
| choco_installer = api.path['cleanup'].join(INSTALLER_NAME) |
| api.url.get_file(INSTALLER, choco_installer, 'download chocolatey installer') |
| |
| choco_home = api.path['cleanup'].join('chocolatey') |
| bin_root = api.path['cleanup'].join('bin_root') |
| env = { |
| 'ChocolateyInstall': choco_home, |
| 'ChocolateyBinRoot': bin_root |
| } |
| with api.context(env=env): |
| api.step('install chocolatey', [POWERSHELL, choco_installer]) |
| |
| choco = choco_home.join('choco') |
| api.step('choco --version', [choco, '--version']) |
| |
| cache = api.path['cleanup'].join('cache') |
| api.step('choco set package directory', |
| [choco, 'config', 'set', 'cacheLocation', cache]) |
| |
| # List the released versions via cloud storage. |
| released_versions = set() |
| for channel in CHANNELS: |
| versions_data = api.gsutil.list( |
| RELEASE_BUCKET % channel, |
| name='list %s releases' % channel, |
| stdout=api.raw_io.output_text(add_output_log=True)) |
| for line in versions_data.stdout.splitlines(): |
| version = _parse_gsurl_release(line) |
| if _is_version(version) and _is_modern_version(version): |
| released_versions.add(version) |
| |
| # List the versions already released on chocolatey. |
| published_data = api.step( |
| 'list published versions', |
| [choco, 'list', '--all', '--exact', '--pre', PACKAGE], |
| stdout=api.raw_io.output_text(add_output_log=True)) |
| published_versions = set() |
| for line in published_data.stdout.splitlines(): |
| if line.startswith(PACKAGE + ' '): |
| choco_version = _parse_chocolatey_release(line) |
| version = _decode_chocolatey_version(choco_version) |
| if _is_modern_version(version): |
| published_versions.add(version) |
| |
| # Stop if chocolatey is up to date. |
| new_versions = sorted(released_versions - published_versions) |
| if not new_versions: |
| api.step.empty('chocolatey is up to date') |
| return |
| |
| # Check out the chocolatey package installer template. |
| api.git.checkout( |
| url='https://github.com/dart-lang/chocolatey-packages.git', |
| ref='master') |
| |
| # Read the installer template. |
| chocolatey_dir = api.path['start_dir'].join('chocolatey-packages') |
| package_dir = chocolatey_dir.join(PACKAGE) |
| installer_path = package_dir.join('chocolateyInstall.ps1') |
| installer = api.file.read_text('read installer', installer_path) |
| |
| # Decode the private key for chocolatey uploads. |
| chocolatey_key = api.dart.get_secret('chocolatey') |
| |
| # Release the new versions on chocolatey. |
| for version in new_versions: |
| channel = _channel_of_version(version) |
| _publish_version(api, channel, version, choco, package_dir, installer, |
| installer_path, chocolatey_key) |
| |
| |
| def _publish_version(api, channel, version, choco, package_dir, installer, |
| installer_path, chocolatey_key): |
| checksum = api.url.get_text( |
| CHECKSUM % (channel, version, 'ia32'), |
| default_test_data='abc *should-not-see-this') |
| checksum = checksum.output.split()[0] |
| checksum64 = api.url.get_text( |
| CHECKSUM % (channel, version, 'x64'), |
| default_test_data='def *should-not-see-this') |
| checksum64 = checksum64.output.split()[0] |
| |
| installer = installer.replace('$version$', version) |
| installer = installer.replace('$channel$', channel) |
| installer = installer.replace('$checksum$', checksum) |
| installer = installer.replace('$checksum64$', checksum64) |
| |
| api.file.write_text('write installer %s %s' % (channel, version), |
| installer_path, installer) |
| |
| with api.context(cwd=package_dir): |
| choco_version = _encode_chocolatey_version(version) |
| |
| api.step('choco pack %s %s' % (channel, version), |
| [choco, 'pack', 'version=%s' % choco_version]) |
| |
| api.step('verify with choco install %s %s' % (channel, version), |
| [choco, 'install', PACKAGE, '--pre', '-y', '-dv', '-s', '.']) |
| |
| choco_push = '$secret = cat %s; %s push -k="$secret" %s.%s.nupkg' % ( |
| chocolatey_key, choco, PACKAGE, choco_version) |
| api.step('choco push %s %s' % (channel, version), |
| [POWERSHELL, '-Command', choco_push]) |
| |
| |
| DEV_RELEASES = '\n'.join( |
| map(lambda v: (RELEASE_BUCKET + '%s/') % ('dev', v), [ |
| '1.11.0-dev.3.0', '2.0.0-dev.0.0', '2.16.0-80.0.dev', '2.17.0-1.0.dev', |
| '2.17.0-162.0.dev', '2.17.0-18.0.dev', '2.17.0-7.0.dev', '45519', |
| 'latest' |
| ])) + '\n' |
| |
| BETA_RELEASES = '\n'.join( |
| map(lambda v: (RELEASE_BUCKET + '%s/') % ('beta', v), [ |
| '2.10.0-110.1.beta', '2.16.0-80.1.beta', '2.16.0', '2.16.1', |
| '2.17.0-69.1.beta', 'latest' |
| ])) + '\n' |
| |
| STABLE_RELEASES = '\n'.join( |
| map(lambda v: (RELEASE_BUCKET + '%s/') % ('stable', v), [ |
| '1.11.0', '2.0.0', '2.15.1', '2.16.0', '2.16.1', '2.17.0', '2.2.0', |
| '45692', 'latest' |
| ])) + '\n' |
| |
| CHOCOLATEY_SYNCHRONIZED = """ |
| Chocolatey v0.12.1 |
| dart-sdk 2.17.0 [Approved] Downloads cached for licensed users |
| dart-sdk 2.17.0.162-c-000-dev [Approved] Downloads cached for licensed users |
| dart-sdk 2.17.0.91-c-000-dev [Approved] Downloads cached for licensed users |
| dart-sdk 2.17.0.69-c-002-beta [Approved] |
| dart-sdk 2.17.0.69-c-001-beta [Approved] |
| dart-sdk 2.17.0.69-c-000-dev [Approved] Downloads cached for licensed users |
| dart-sdk 2.17.0.18-c-000-dev [Approved] Downloads cached for licensed users |
| dart-sdk 2.17.0.7-c-000-dev - Possibly broken |
| dart-sdk 2.17.0.1-c-000-dev [Approved] Downloads cached for licensed users |
| dart-sdk 2.16.1 [Approved] Downloads cached for licensed users |
| dart-sdk 2.8.0.15-dev-0 |
| dart-sdk 2.0.0.53-dev [Approved] Downloads cached for licensed users |
| dart-sdk 1.8.5.0 [Approved] |
| dart-sdk 1.6.0 [Approved] |
| 401 packages found. |
| """ |
| |
| CHOCOLATEY_UNSYNCHRONIZED = '\n'.join([ |
| line for line in CHOCOLATEY_SYNCHRONIZED.split('\n') |
| if not ' 2.17.0.18-c-000-dev ' in line and |
| not ' 2.17.0.69-c-001-beta ' in line and not ' 2.17.0 ' in line |
| ]) |
| |
| |
| def GenTests(api): |
| yield api.test( |
| 'synchronized', |
| api.platform('win', 64), |
| api.step_data( |
| 'gsutil list dev releases', |
| stdout=api.raw_io.output_text(DEV_RELEASES)), |
| api.step_data( |
| 'gsutil list beta releases', |
| stdout=api.raw_io.output_text(BETA_RELEASES)), |
| api.step_data( |
| 'gsutil list stable releases', |
| stdout=api.raw_io.output_text(STABLE_RELEASES)), |
| api.step_data( |
| 'list published versions', |
| stdout=api.raw_io.output_text(CHOCOLATEY_SYNCHRONIZED)), |
| api.post_process(DoesNotRunRE, 'choco pack'), |
| ) |
| yield api.test( |
| 'unsynchronized', |
| api.platform('win', 64), |
| api.step_data( |
| 'gsutil list dev releases', |
| stdout=api.raw_io.output_text(DEV_RELEASES)), |
| api.step_data( |
| 'gsutil list beta releases', |
| stdout=api.raw_io.output_text(BETA_RELEASES)), |
| api.step_data( |
| 'gsutil list stable releases', |
| stdout=api.raw_io.output_text(STABLE_RELEASES)), |
| api.step_data( |
| 'list published versions', |
| stdout=api.raw_io.output_text(CHOCOLATEY_UNSYNCHRONIZED)), |
| api.post_process(StepCommandContains, 'choco pack dev 2.17.0-18.0.dev', |
| ['version=2.17.0.18-c-000-dev']), |
| api.post_process(StepCommandRE, 'choco push dev 2.17.0-18.0.dev', |
| ['.*', '.*', r'.*2\.17\.0\.18-c-000-dev\.nupkg']), |
| api.post_process(StepCommandContains, 'choco pack beta 2.17.0-69.1.beta', |
| ['version=2.17.0.69-c-001-beta']), |
| api.post_process(StepCommandRE, 'choco push beta 2.17.0-69.1.beta', |
| ['.*', '.*', r'.*2\.17\.0\.69-c-001-beta\.nupkg']), |
| api.post_process(StepCommandContains, 'choco pack stable 2.17.0', |
| ['version=2.17.0']), |
| api.post_process(StepCommandRE, 'choco push stable 2.17.0', |
| ['.*', '.*', r'.*2\.17\.0.nupkg']), |
| ) |