aws/hhvm1/lambdas/common.py (104 lines of code) (raw):

# Copyright (c) 2017-present, Facebook, Inc. # All rights reserved. # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. import boto3 import functools import json import re from urllib import request class Config: override_org = None override_branch = None map_states = { # state name: map key 'ForEachVersion': 'version', 'ForEachPlatform': 'platform', } macos_versions = { # key: name as reported by build_statuses() # value: version as reported by sw_vers -productVersion | cut -d . -f 1,2 'macos-catalina': '10.15', } def is_nightly(version): return re.fullmatch(r'[0-9]{4}\.[0-9]{2}\.[0-9]{2}', version) def is_linux(platform): return re.fullmatch(r'(debian|ubuntu)-[0-9\.]+-[a-z]+', platform) def is_binary_platform(platform): return is_linux(platform) or platform in Config.macos_versions def branch(version): if not version or is_nightly(version): return 'master' else: return 'HHVM-' + re.match(r'[0-9]+\.[0-9]+', version)[0] def url(path, version=None): org = 'hhvm' br = branch(version) # overrides from Config only apply to URLs without version if not version: org = Config.override_org or org br = Config.override_branch or br return f'https://raw.githubusercontent.com/{org}/packaging/{br}/{path}' def fetch(path, version=None): return request.urlopen(url(path, version)).read().decode('ascii') def env_for_version(version): env = { 'IS_NIGHTLY': 'true', 'S3_BUCKET': 'hhvm-downloads', 'S3_PATH': f'source/nightlies/hhvm-nightly-{version}.tar.gz', } if is_nightly(version) else { 'IS_NIGHTLY': 'false', 'S3_BUCKET': 'hhvm-scratch', 'S3_PATH': f'hhvm-{version}.tar.gz', } env['S3_SOURCE'] = 's3://{S3_BUCKET}/{S3_PATH}'.format(**env) env['PACKAGING_BRANCH'] = branch(version) return env def format_env(env): return '\n'.join([f'{var}="{value}"' for var, value in env.items()]) @functools.lru_cache() def build_statuses(version): response = json.loads( boto3.client('lambda').invoke( FunctionName='hhvm-get-build-status', Payload='{"version":"' + version + '"}', )['Payload'].read().decode('ascii') ) return { platform: status for status in ['succeeded', 'built_not_published', 'not_built'] for platform in response.get(status, {}) } def build_status(version, platform): return build_statuses(version)[platform] # debugging options def skip_ec2(event): return event.get('buildInput', {}).get('debug') == 'skip_ec2' def fake_ec2(event): return event.get('buildInput', {}).get('debug') == 'fake_ec2' def is_test_build(event): return event.get('buildInput', {}).get('debug') == 'test_build' def normalize_results(results): """ The state machine output has some unnecessary nesting due to how the state machine is structured -- this cleans it up: - unnecessary nesting due to "parallel states" is flattened - lists of version/platform outputs are normalized into a map of results keyed by the version/platform - this makes the state machine output robust against changes like adding a new state that runs in parallel with some existing states, which is important because the logic in check_if_repos_changed and check_for_failures depends on the structure of the results """ normalized = {} for state_name, result in results.items(): if type(result) == list: if state_name in Config.map_states: # convert from list to map key = Config.map_states[state_name] normalized[state_name] = { item[key]: normalize_results(item['results']) for item in result } else: # flatten for item in result: normalized.update(normalize_results(item['results'])) else: # just remove some redundant stuff result.pop('taskInput', None) if result.get('skip') == False: del result['skip'] normalized[state_name] = result return normalized def all_execution_events(execution_arn): client = boto3.client('stepfunctions') response = client.get_execution_history( executionArn=execution_arn, maxResults=1000, ) events = response['events'] while 'nextToken' in response: response = client.get_execution_history( executionArn=execution_arn, maxResults=1000, nextToken=response['nextToken'], ) events += response['events'] return events