##// END OF EJS Templates
packaging: add support for PyOxidizer...
packaging: add support for PyOxidizer I've successfully built Mercurial on the development tip of PyOxidizer on Linux and Windows. It mostly "just works" on Linux. Windows is a bit more finicky. In-memory resource files are probably not all working correctly due to bugs in PyOxidizer's naming of modules. PyOxidizer now now supports installing files next to the produced binary. (We do this for templates in the added file.) So a workaround should be available. Also, since the last time I submitted support for PyOxidizer, PyOxidizer gained the ability to auto-generate Rust projects to build executables. So we don't need to worry about vendoring any Rust code to initially support PyOxidizer. However, at some point we will likely want to write our own command line driver that embeds a Python interpreter via PyOxidizer so we can run Rust code outside the confines of a Python interpreter. But that will be a follow-up. I would also like to add packaging.py CLI commands to build PyOxidizer distributions. This can come later, if ever. PyOxidizer's new "targets" feature makes it really easy to define packaging tasks in its Starlark configuration file. While not much is implemented yet, eventually we should be able to produce MSIs, etc using a `pyoxidizer build` one-liner. We'll get there... Differential Revision: https://phab.mercurial-scm.org/D7450

File last commit:

r43346:2372284d default
r44697:281b6690 default
Show More
cli.py
487 lines | 13.4 KiB | text/x-python | PythonLexer
Gregory Szorc
automation: perform tasks on remote machines...
r42191 # cli.py - Command line interface for automation
#
# Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
# no-check-code because Python 3 native.
import argparse
Gregory Szorc
automation: initial support for running Linux tests...
r42471 import concurrent.futures as futures
Gregory Szorc
automation: perform tasks on remote machines...
r42191 import os
import pathlib
Gregory Szorc
automation: initial support for running Linux tests...
r42471 import time
Gregory Szorc
automation: perform tasks on remote machines...
r42191
from . import (
aws,
HGAutomation,
Gregory Szorc
automation: initial support for running Linux tests...
r42471 linux,
Gregory Szorc
automation: add a command to submit to a Try server...
r43327 try_server,
Gregory Szorc
automation: perform tasks on remote machines...
r42191 windows,
)
Augie Fackler
formatting: blacken the codebase...
r43346 SOURCE_ROOT = pathlib.Path(
os.path.abspath(__file__)
).parent.parent.parent.parent
Gregory Szorc
automation: perform tasks on remote machines...
r42191 DIST_PATH = SOURCE_ROOT / 'dist'
Augie Fackler
formatting: blacken the codebase...
r43346 def bootstrap_linux_dev(
hga: HGAutomation, aws_region, distros=None, parallel=False
):
Gregory Szorc
automation: initial support for running Linux tests...
r42471 c = hga.aws_connection(aws_region)
if distros:
distros = distros.split(',')
else:
distros = sorted(linux.DISTROS)
# TODO There is a wonky interaction involving KeyboardInterrupt whereby
# the context manager that is supposed to terminate the temporary EC2
# instance doesn't run. Until we fix this, make parallel building opt-in
# so we don't orphan instances.
if parallel:
fs = []
with futures.ThreadPoolExecutor(len(distros)) as e:
for distro in distros:
fs.append(e.submit(aws.ensure_linux_dev_ami, c, distro=distro))
for f in fs:
f.result()
else:
for distro in distros:
aws.ensure_linux_dev_ami(c, distro=distro)
Gregory Szorc
automation: make Windows base image name configurable...
r42871 def bootstrap_windows_dev(hga: HGAutomation, aws_region, base_image_name):
Gregory Szorc
automation: perform tasks on remote machines...
r42191 c = hga.aws_connection(aws_region)
Gregory Szorc
automation: make Windows base image name configurable...
r42871 image = aws.ensure_windows_dev_ami(c, base_image_name=base_image_name)
Gregory Szorc
automation: perform tasks on remote machines...
r42191 print('Windows development AMI available as %s' % image.id)
Augie Fackler
formatting: blacken the codebase...
r43346 def build_inno(
hga: HGAutomation, aws_region, arch, revision, version, base_image_name
):
Gregory Szorc
automation: perform tasks on remote machines...
r42191 c = hga.aws_connection(aws_region)
Gregory Szorc
automation: make Windows base image name configurable...
r42871 image = aws.ensure_windows_dev_ami(c, base_image_name=base_image_name)
Gregory Szorc
automation: perform tasks on remote machines...
r42191 DIST_PATH.mkdir(exist_ok=True)
with aws.temporary_windows_dev_instances(c, image, 't3.medium') as insts:
instance = insts[0]
windows.synchronize_hg(SOURCE_ROOT, revision, instance)
for a in arch:
Augie Fackler
formatting: blacken the codebase...
r43346 windows.build_inno_installer(
instance.winrm_client, a, DIST_PATH, version=version
)
Gregory Szorc
automation: perform tasks on remote machines...
r42191
Augie Fackler
formatting: blacken the codebase...
r43346 def build_wix(
hga: HGAutomation, aws_region, arch, revision, version, base_image_name
):
Gregory Szorc
automation: perform tasks on remote machines...
r42191 c = hga.aws_connection(aws_region)
Gregory Szorc
automation: make Windows base image name configurable...
r42871 image = aws.ensure_windows_dev_ami(c, base_image_name=base_image_name)
Gregory Szorc
automation: perform tasks on remote machines...
r42191 DIST_PATH.mkdir(exist_ok=True)
with aws.temporary_windows_dev_instances(c, image, 't3.medium') as insts:
instance = insts[0]
windows.synchronize_hg(SOURCE_ROOT, revision, instance)
for a in arch:
Augie Fackler
formatting: blacken the codebase...
r43346 windows.build_wix_installer(
instance.winrm_client, a, DIST_PATH, version=version
)
Gregory Szorc
automation: perform tasks on remote machines...
r42191
Augie Fackler
formatting: blacken the codebase...
r43346 def build_windows_wheel(
hga: HGAutomation, aws_region, arch, revision, base_image_name
):
Gregory Szorc
automation: perform tasks on remote machines...
r42191 c = hga.aws_connection(aws_region)
Gregory Szorc
automation: make Windows base image name configurable...
r42871 image = aws.ensure_windows_dev_ami(c, base_image_name=base_image_name)
Gregory Szorc
automation: perform tasks on remote machines...
r42191 DIST_PATH.mkdir(exist_ok=True)
with aws.temporary_windows_dev_instances(c, image, 't3.medium') as insts:
instance = insts[0]
windows.synchronize_hg(SOURCE_ROOT, revision, instance)
for a in arch:
windows.build_wheel(instance.winrm_client, a, DIST_PATH)
Augie Fackler
formatting: blacken the codebase...
r43346 def build_all_windows_packages(
hga: HGAutomation, aws_region, revision, version, base_image_name
):
Gregory Szorc
automation: perform tasks on remote machines...
r42191 c = hga.aws_connection(aws_region)
Gregory Szorc
automation: make Windows base image name configurable...
r42871 image = aws.ensure_windows_dev_ami(c, base_image_name=base_image_name)
Gregory Szorc
automation: perform tasks on remote machines...
r42191 DIST_PATH.mkdir(exist_ok=True)
with aws.temporary_windows_dev_instances(c, image, 't3.medium') as insts:
instance = insts[0]
winrm_client = instance.winrm_client
windows.synchronize_hg(SOURCE_ROOT, revision, instance)
for arch in ('x86', 'x64'):
windows.purge_hg(winrm_client)
windows.build_wheel(winrm_client, arch, DIST_PATH)
windows.purge_hg(winrm_client)
Augie Fackler
formatting: blacken the codebase...
r43346 windows.build_inno_installer(
winrm_client, arch, DIST_PATH, version=version
)
Gregory Szorc
automation: perform tasks on remote machines...
r42191 windows.purge_hg(winrm_client)
Augie Fackler
formatting: blacken the codebase...
r43346 windows.build_wix_installer(
winrm_client, arch, DIST_PATH, version=version
)
Gregory Szorc
automation: perform tasks on remote machines...
r42191
def terminate_ec2_instances(hga: HGAutomation, aws_region):
Gregory Szorc
automation: don't create resources when deleting things...
r42463 c = hga.aws_connection(aws_region, ensure_ec2_state=False)
Gregory Szorc
automation: perform tasks on remote machines...
r42191 aws.terminate_ec2_instances(c.ec2resource)
def purge_ec2_resources(hga: HGAutomation, aws_region):
Gregory Szorc
automation: don't create resources when deleting things...
r42463 c = hga.aws_connection(aws_region, ensure_ec2_state=False)
Gregory Szorc
automation: perform tasks on remote machines...
r42191 aws.remove_resources(c)
Augie Fackler
formatting: blacken the codebase...
r43346 def run_tests_linux(
hga: HGAutomation,
aws_region,
instance_type,
python_version,
test_flags,
distro,
filesystem,
):
Gregory Szorc
automation: initial support for running Linux tests...
r42471 c = hga.aws_connection(aws_region)
image = aws.ensure_linux_dev_ami(c, distro=distro)
t_start = time.time()
ensure_extra_volume = filesystem not in ('default', 'tmpfs')
with aws.temporary_linux_dev_instances(
Augie Fackler
formatting: blacken the codebase...
r43346 c, image, instance_type, ensure_extra_volume=ensure_extra_volume
) as insts:
Gregory Szorc
automation: initial support for running Linux tests...
r42471
instance = insts[0]
Augie Fackler
formatting: blacken the codebase...
r43346 linux.prepare_exec_environment(
instance.ssh_client, filesystem=filesystem
)
Gregory Szorc
automation: initial support for running Linux tests...
r42471 linux.synchronize_hg(SOURCE_ROOT, instance, '.')
t_prepared = time.time()
Augie Fackler
formatting: blacken the codebase...
r43346 linux.run_tests(instance.ssh_client, python_version, test_flags)
Gregory Szorc
automation: initial support for running Linux tests...
r42471 t_done = time.time()
t_setup = t_prepared - t_start
t_all = t_done - t_start
print(
'total time: %.1fs; setup: %.1fs; tests: %.1fs; setup overhead: %.1f%%'
Augie Fackler
formatting: blacken the codebase...
r43346 % (t_all, t_setup, t_done - t_prepared, t_setup / t_all * 100.0)
)
Gregory Szorc
automation: initial support for running Linux tests...
r42471
Augie Fackler
formatting: blacken the codebase...
r43346 def run_tests_windows(
hga: HGAutomation,
aws_region,
instance_type,
python_version,
arch,
test_flags,
base_image_name,
):
Gregory Szorc
automation: perform tasks on remote machines...
r42191 c = hga.aws_connection(aws_region)
Gregory Szorc
automation: make Windows base image name configurable...
r42871 image = aws.ensure_windows_dev_ami(c, base_image_name=base_image_name)
Gregory Szorc
automation: perform tasks on remote machines...
r42191
Augie Fackler
formatting: blacken the codebase...
r43346 with aws.temporary_windows_dev_instances(
c, image, instance_type, disable_antivirus=True
) as insts:
Gregory Szorc
automation: perform tasks on remote machines...
r42191 instance = insts[0]
windows.synchronize_hg(SOURCE_ROOT, '.', instance)
Augie Fackler
formatting: blacken the codebase...
r43346 windows.run_tests(
instance.winrm_client, python_version, arch, test_flags
)
Gregory Szorc
automation: perform tasks on remote machines...
r42191
Augie Fackler
formatting: blacken the codebase...
r43346 def publish_windows_artifacts(
hg: HGAutomation,
aws_region,
version: str,
pypi: bool,
mercurial_scm_org: bool,
ssh_username: str,
):
windows.publish_artifacts(
DIST_PATH,
version,
pypi=pypi,
mercurial_scm_org=mercurial_scm_org,
ssh_username=ssh_username,
)
Gregory Szorc
automation: implement "publish-windows-artifacts" command...
r43177
Gregory Szorc
automation: add a command to submit to a Try server...
r43327 def run_try(hga: HGAutomation, aws_region: str, rev: str):
c = hga.aws_connection(aws_region, ensure_ec2_state=False)
try_server.trigger_try(c, rev=rev)
Gregory Szorc
automation: perform tasks on remote machines...
r42191 def get_parser():
parser = argparse.ArgumentParser()
parser.add_argument(
'--state-path',
default='~/.hgautomation',
help='Path for local state files',
)
parser.add_argument(
Augie Fackler
formatting: blacken the codebase...
r43346 '--aws-region', help='AWS region to use', default='us-west-2',
Gregory Szorc
automation: perform tasks on remote machines...
r42191 )
subparsers = parser.add_subparsers()
sp = subparsers.add_parser(
Augie Fackler
formatting: blacken the codebase...
r43346 'bootstrap-linux-dev', help='Bootstrap Linux development environments',
Gregory Szorc
automation: initial support for running Linux tests...
r42471 )
sp.add_argument(
Augie Fackler
formatting: blacken the codebase...
r43346 '--distros', help='Comma delimited list of distros to bootstrap',
Gregory Szorc
automation: initial support for running Linux tests...
r42471 )
sp.add_argument(
'--parallel',
action='store_true',
Augie Fackler
formatting: blacken the codebase...
r43346 help='Generate AMIs in parallel (not CTRL-c safe)',
Gregory Szorc
automation: initial support for running Linux tests...
r42471 )
sp.set_defaults(func=bootstrap_linux_dev)
sp = subparsers.add_parser(
Gregory Szorc
automation: perform tasks on remote machines...
r42191 'bootstrap-windows-dev',
help='Bootstrap the Windows development environment',
)
Gregory Szorc
automation: make Windows base image name configurable...
r42871 sp.add_argument(
'--base-image-name',
help='AMI name of base image',
default=aws.WINDOWS_BASE_IMAGE_NAME,
)
Gregory Szorc
automation: perform tasks on remote machines...
r42191 sp.set_defaults(func=bootstrap_windows_dev)
sp = subparsers.add_parser(
Augie Fackler
formatting: blacken the codebase...
r43346 'build-all-windows-packages', help='Build all Windows packages',
Gregory Szorc
automation: perform tasks on remote machines...
r42191 )
sp.add_argument(
Augie Fackler
formatting: blacken the codebase...
r43346 '--revision', help='Mercurial revision to build', default='.',
Gregory Szorc
automation: perform tasks on remote machines...
r42191 )
Gregory Szorc
automation: add --version argument to build-all-windows-packages...
r42469 sp.add_argument(
Augie Fackler
formatting: blacken the codebase...
r43346 '--version', help='Mercurial version string to use',
Gregory Szorc
automation: add --version argument to build-all-windows-packages...
r42469 )
Gregory Szorc
automation: make Windows base image name configurable...
r42871 sp.add_argument(
'--base-image-name',
help='AMI name of base image',
default=aws.WINDOWS_BASE_IMAGE_NAME,
)
Gregory Szorc
automation: perform tasks on remote machines...
r42191 sp.set_defaults(func=build_all_windows_packages)
sp = subparsers.add_parser(
Augie Fackler
formatting: blacken the codebase...
r43346 'build-inno', help='Build Inno Setup installer(s)',
Gregory Szorc
automation: perform tasks on remote machines...
r42191 )
sp.add_argument(
'--arch',
help='Architecture to build for',
choices={'x86', 'x64'},
nargs='*',
default=['x64'],
)
sp.add_argument(
Augie Fackler
formatting: blacken the codebase...
r43346 '--revision', help='Mercurial revision to build', default='.',
Gregory Szorc
automation: perform tasks on remote machines...
r42191 )
sp.add_argument(
Augie Fackler
formatting: blacken the codebase...
r43346 '--version', help='Mercurial version string to use in installer',
Gregory Szorc
automation: perform tasks on remote machines...
r42191 )
Gregory Szorc
automation: make Windows base image name configurable...
r42871 sp.add_argument(
'--base-image-name',
help='AMI name of base image',
default=aws.WINDOWS_BASE_IMAGE_NAME,
)
Gregory Szorc
automation: perform tasks on remote machines...
r42191 sp.set_defaults(func=build_inno)
sp = subparsers.add_parser(
Augie Fackler
formatting: blacken the codebase...
r43346 'build-windows-wheel', help='Build Windows wheel(s)',
Gregory Szorc
automation: perform tasks on remote machines...
r42191 )
sp.add_argument(
'--arch',
help='Architecture to build for',
choices={'x86', 'x64'},
nargs='*',
default=['x64'],
)
sp.add_argument(
Augie Fackler
formatting: blacken the codebase...
r43346 '--revision', help='Mercurial revision to build', default='.',
Gregory Szorc
automation: perform tasks on remote machines...
r42191 )
Gregory Szorc
automation: make Windows base image name configurable...
r42871 sp.add_argument(
'--base-image-name',
help='AMI name of base image',
default=aws.WINDOWS_BASE_IMAGE_NAME,
)
Gregory Szorc
automation: perform tasks on remote machines...
r42191 sp.set_defaults(func=build_windows_wheel)
Augie Fackler
formatting: blacken the codebase...
r43346 sp = subparsers.add_parser('build-wix', help='Build WiX installer(s)')
Gregory Szorc
automation: perform tasks on remote machines...
r42191 sp.add_argument(
'--arch',
help='Architecture to build for',
choices={'x86', 'x64'},
nargs='*',
default=['x64'],
)
sp.add_argument(
Augie Fackler
formatting: blacken the codebase...
r43346 '--revision', help='Mercurial revision to build', default='.',
Gregory Szorc
automation: perform tasks on remote machines...
r42191 )
sp.add_argument(
Augie Fackler
formatting: blacken the codebase...
r43346 '--version', help='Mercurial version string to use in installer',
Gregory Szorc
automation: perform tasks on remote machines...
r42191 )
Gregory Szorc
automation: make Windows base image name configurable...
r42871 sp.add_argument(
'--base-image-name',
help='AMI name of base image',
default=aws.WINDOWS_BASE_IMAGE_NAME,
)
Gregory Szorc
automation: perform tasks on remote machines...
r42191 sp.set_defaults(func=build_wix)
sp = subparsers.add_parser(
'terminate-ec2-instances',
help='Terminate all active EC2 instances managed by us',
)
sp.set_defaults(func=terminate_ec2_instances)
sp = subparsers.add_parser(
Augie Fackler
formatting: blacken the codebase...
r43346 'purge-ec2-resources', help='Purge all EC2 resources managed by us',
Gregory Szorc
automation: perform tasks on remote machines...
r42191 )
sp.set_defaults(func=purge_ec2_resources)
Augie Fackler
formatting: blacken the codebase...
r43346 sp = subparsers.add_parser('run-tests-linux', help='Run tests on Linux',)
Gregory Szorc
automation: initial support for running Linux tests...
r42471 sp.add_argument(
'--distro',
help='Linux distribution to run tests on',
choices=linux.DISTROS,
Gregory Szorc
automation: support and use Debian Buster by default...
r43288 default='debian10',
Gregory Szorc
automation: initial support for running Linux tests...
r42471 )
sp.add_argument(
'--filesystem',
help='Filesystem type to use',
choices={'btrfs', 'default', 'ext3', 'ext4', 'jfs', 'tmpfs', 'xfs'},
default='default',
)
sp.add_argument(
'--instance-type',
help='EC2 instance type to use',
default='c5.9xlarge',
)
sp.add_argument(
'--python-version',
help='Python version to use',
Augie Fackler
formatting: blacken the codebase...
r43346 choices={
'system2',
'system3',
'2.7',
'3.5',
'3.6',
'3.7',
'3.8',
'pypy',
'pypy3.5',
'pypy3.6',
},
Gregory Szorc
automation: initial support for running Linux tests...
r42471 default='system2',
)
sp.add_argument(
'test_flags',
help='Extra command line flags to pass to run-tests.py',
nargs='*',
)
sp.set_defaults(func=run_tests_linux)
sp = subparsers.add_parser(
Augie Fackler
formatting: blacken the codebase...
r43346 'run-tests-windows', help='Run tests on Windows',
Gregory Szorc
automation: perform tasks on remote machines...
r42191 )
sp.add_argument(
Augie Fackler
formatting: blacken the codebase...
r43346 '--instance-type', help='EC2 instance type to use', default='t3.medium',
Gregory Szorc
automation: perform tasks on remote machines...
r42191 )
sp.add_argument(
'--python-version',
help='Python version to use',
choices={'2.7', '3.5', '3.6', '3.7', '3.8'},
default='2.7',
)
sp.add_argument(
'--arch',
help='Architecture to test',
choices={'x86', 'x64'},
default='x64',
)
sp.add_argument(
Augie Fackler
formatting: blacken the codebase...
r43346 '--test-flags', help='Extra command line flags to pass to run-tests.py',
Gregory Szorc
automation: perform tasks on remote machines...
r42191 )
Gregory Szorc
automation: make Windows base image name configurable...
r42871 sp.add_argument(
'--base-image-name',
help='AMI name of base image',
default=aws.WINDOWS_BASE_IMAGE_NAME,
)
Gregory Szorc
automation: perform tasks on remote machines...
r42191 sp.set_defaults(func=run_tests_windows)
Gregory Szorc
automation: implement "publish-windows-artifacts" command...
r43177 sp = subparsers.add_parser(
'publish-windows-artifacts',
Augie Fackler
formatting: blacken the codebase...
r43346 help='Publish built Windows artifacts (wheels, installers, etc)',
Gregory Szorc
automation: implement "publish-windows-artifacts" command...
r43177 )
sp.add_argument(
'--no-pypi',
dest='pypi',
action='store_false',
default=True,
help='Skip uploading to PyPI',
)
sp.add_argument(
'--no-mercurial-scm-org',
dest='mercurial_scm_org',
action='store_false',
default=True,
help='Skip uploading to www.mercurial-scm.org',
)
sp.add_argument(
Augie Fackler
formatting: blacken the codebase...
r43346 '--ssh-username', help='SSH username for mercurial-scm.org',
Gregory Szorc
automation: implement "publish-windows-artifacts" command...
r43177 )
sp.add_argument(
Augie Fackler
formatting: blacken the codebase...
r43346 'version', help='Mercurial version string to locate local packages',
Gregory Szorc
automation: implement "publish-windows-artifacts" command...
r43177 )
sp.set_defaults(func=publish_windows_artifacts)
Gregory Szorc
automation: add a command to submit to a Try server...
r43327 sp = subparsers.add_parser(
Augie Fackler
formatting: blacken the codebase...
r43346 'try', help='Run CI automation against a custom changeset'
Gregory Szorc
automation: add a command to submit to a Try server...
r43327 )
Augie Fackler
formatting: blacken the codebase...
r43346 sp.add_argument('-r', '--rev', default='.', help='Revision to run CI on')
Gregory Szorc
automation: add a command to submit to a Try server...
r43327 sp.set_defaults(func=run_try)
Gregory Szorc
automation: perform tasks on remote machines...
r42191 return parser
def main():
parser = get_parser()
args = parser.parse_args()
local_state_path = pathlib.Path(os.path.expanduser(args.state_path))
automation = HGAutomation(local_state_path)
if not hasattr(args, 'func'):
parser.print_help()
return
kwargs = dict(vars(args))
del kwargs['func']
del kwargs['state_path']
args.func(automation, **kwargs)