Now that zulip_bots is fully Python3, it makes sense to only generate a Python3 wheel dist for it. zulip and zulip_botserver are still distributed as a py2/py3 universal wheel.
		
			
				
	
	
		
			253 lines
		
	
	
	
		
			9 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			253 lines
		
	
	
	
		
			9 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
#!/usr/bin/env python3
 | 
						|
 | 
						|
from __future__ import print_function
 | 
						|
from contextlib import contextmanager
 | 
						|
import os
 | 
						|
import argparse
 | 
						|
import glob
 | 
						|
import shutil
 | 
						|
import tempfile
 | 
						|
 | 
						|
import crayons
 | 
						|
import twine.commands.upload
 | 
						|
import setuptools.sandbox
 | 
						|
 | 
						|
REPO_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 | 
						|
 | 
						|
@contextmanager
 | 
						|
def cd(newdir):
 | 
						|
    prevdir = os.getcwd()
 | 
						|
    os.chdir(os.path.expanduser(newdir))
 | 
						|
    try:
 | 
						|
        yield
 | 
						|
    finally:
 | 
						|
        os.chdir(prevdir)
 | 
						|
 | 
						|
def _generate_dist(dist_type, setup_file, package_name, setup_args):
 | 
						|
    message = 'Generating {dist_type} for {package_name}.'.format(
 | 
						|
        dist_type=dist_type,
 | 
						|
        package_name=package_name,
 | 
						|
    )
 | 
						|
    print(crayons.white(message, bold=True))
 | 
						|
 | 
						|
    setup_dir = os.path.dirname(setup_file)
 | 
						|
    with cd(setup_dir):
 | 
						|
        setuptools.sandbox.run_setup(setup_file, setup_args)
 | 
						|
 | 
						|
    message = '{dist_type} for {package_name} generated under {dir}.\n'.format(
 | 
						|
        dist_type=dist_type,
 | 
						|
        package_name=package_name,
 | 
						|
        dir=setup_dir,
 | 
						|
    )
 | 
						|
    print(crayons.green(message, bold=True))
 | 
						|
 | 
						|
def generate_bdist_wheel(setup_file, package_name, universal=False):
 | 
						|
    if universal:
 | 
						|
        _generate_dist('bdist_wheel', setup_file, package_name,
 | 
						|
                       ['bdist_wheel', '--universal'])
 | 
						|
    else:
 | 
						|
        _generate_dist('bdist_wheel', setup_file, package_name,
 | 
						|
                       ['bdist_wheel'])
 | 
						|
 | 
						|
def twine_upload(dist_dirs):
 | 
						|
    message = 'Uploading distributions under the following directories:'
 | 
						|
    print(crayons.green(message, bold=True))
 | 
						|
    for dist_dir in dist_dirs:
 | 
						|
        print(crayons.yellow(dist_dir))
 | 
						|
    twine.commands.upload.main(dist_dirs)
 | 
						|
 | 
						|
def cleanup(package_dir):
 | 
						|
    build_dir = os.path.join(package_dir, 'build')
 | 
						|
    temp_dir = os.path.join(package_dir, 'temp')
 | 
						|
    dist_dir = os.path.join(package_dir, 'dist')
 | 
						|
    egg_info = os.path.join(
 | 
						|
        package_dir,
 | 
						|
        '{}.egg-info'.format(os.path.basename(package_dir))
 | 
						|
    )
 | 
						|
 | 
						|
    def _rm_if_it_exists(directory):
 | 
						|
        if os.path.isdir(directory):
 | 
						|
            print(crayons.green('Removing {}/*'.format(directory), bold=True))
 | 
						|
            shutil.rmtree(directory)
 | 
						|
 | 
						|
    _rm_if_it_exists(build_dir)
 | 
						|
    _rm_if_it_exists(temp_dir)
 | 
						|
    _rm_if_it_exists(dist_dir)
 | 
						|
    _rm_if_it_exists(egg_info)
 | 
						|
 | 
						|
def set_variable(fp, variable, value):
 | 
						|
    fh, temp_abs_path = tempfile.mkstemp()
 | 
						|
    with os.fdopen(fh, 'w') as new_file, open(fp) as old_file:
 | 
						|
        for line in old_file:
 | 
						|
            if line.startswith(variable):
 | 
						|
                if isinstance(value, bool):
 | 
						|
                    template = '{variable} = {value}\n'
 | 
						|
                else:
 | 
						|
                    template = '{variable} = "{value}"\n'
 | 
						|
                new_file.write(template.format(variable=variable, value=value))
 | 
						|
            else:
 | 
						|
                new_file.write(line)
 | 
						|
 | 
						|
    os.remove(fp)
 | 
						|
    shutil.move(temp_abs_path, fp)
 | 
						|
 | 
						|
    message = 'Set {variable} in {fp} to {value}.'.format(
 | 
						|
        fp=fp, variable=variable, value=value)
 | 
						|
    print(crayons.white(message, bold=True))
 | 
						|
 | 
						|
def update_requirements_in_zulip_repo(zulip_repo_dir, version, hash_or_tag):
 | 
						|
    common = os.path.join(zulip_repo_dir, 'requirements', 'common.in')
 | 
						|
    prod = os.path.join(zulip_repo_dir, 'requirements', 'prod.txt')
 | 
						|
    dev = os.path.join(zulip_repo_dir, 'requirements', 'dev.txt')
 | 
						|
 | 
						|
    def _edit_reqs_file(reqs, zulip_bots_line, zulip_line):
 | 
						|
        fh, temp_abs_path = tempfile.mkstemp()
 | 
						|
        with os.fdopen(fh, 'w') as new_file, open(reqs) as old_file:
 | 
						|
            for line in old_file:
 | 
						|
                if 'python-zulip-api' in line and 'zulip==' in line:
 | 
						|
                    new_file.write(zulip_line)
 | 
						|
                elif 'python-zulip-api' in line and 'zulip_bots' in line:
 | 
						|
                    new_file.write(zulip_bots_line)
 | 
						|
                else:
 | 
						|
                    new_file.write(line)
 | 
						|
 | 
						|
        os.remove(reqs)
 | 
						|
        shutil.move(temp_abs_path, reqs)
 | 
						|
 | 
						|
    url_zulip = 'git+https://github.com/zulip/python-zulip-api.git@{tag}#egg={name}=={version}_git&subdirectory={name}\n'
 | 
						|
    url_zulip_bots = 'git+https://github.com/zulip/python-zulip-api.git@{tag}#egg={name}=={version}+git&subdirectory={name}\n'
 | 
						|
    zulip_bots_line = url_zulip_bots.format(tag=hash_or_tag, name='zulip_bots',
 | 
						|
                                            version=version)
 | 
						|
    zulip_line = url_zulip.format(tag=hash_or_tag, name='zulip',
 | 
						|
                                  version=version)
 | 
						|
 | 
						|
    _edit_reqs_file(prod, zulip_bots_line, zulip_line)
 | 
						|
    _edit_reqs_file(dev, zulip_bots_line, zulip_line)
 | 
						|
 | 
						|
    editable_zulip = '-e "{}"\n'.format(url_zulip.rstrip())
 | 
						|
    editable_zulip_bots = '-e "{}"\n'.format(url_zulip_bots.rstrip())
 | 
						|
 | 
						|
    _edit_reqs_file(
 | 
						|
        common,
 | 
						|
        editable_zulip_bots.format(tag=hash_or_tag, name='zulip_bots', version=version),
 | 
						|
        editable_zulip.format(tag=hash_or_tag, name='zulip', version=version),
 | 
						|
    )
 | 
						|
 | 
						|
    message = 'Updated zulip API package requirements in the main repo.'
 | 
						|
    print(crayons.white(message, bold=True))
 | 
						|
 | 
						|
def parse_args():
 | 
						|
    usage = """
 | 
						|
Script to automate the PyPA release of the zulip, zulip_bots and
 | 
						|
zulip_botserver packages.
 | 
						|
 | 
						|
For example, to make a release for version 0.4.0, execute the
 | 
						|
following steps in order:
 | 
						|
 | 
						|
1. Run ./tools/provision
 | 
						|
 | 
						|
2. Activate the virtualenv created by tools/provision
 | 
						|
 | 
						|
3. To make a release for version 0.4.0, run the
 | 
						|
   following command:
 | 
						|
 | 
						|
     ./tools/release-packages --build 0.4.0 --release
 | 
						|
 | 
						|
4. After Step 3, commit the outstanding changes in your python-zulip-api
 | 
						|
   repo.
 | 
						|
 | 
						|
5. Create a release tag "0.4.0".
 | 
						|
 | 
						|
6. Push the commit and the release tag.
 | 
						|
 | 
						|
7. To update the zulip/requirements/* in the main zulip repo, run (this
 | 
						|
   will update the requirements to install the packages off of the release
 | 
						|
   tag "0.4.0"):
 | 
						|
 | 
						|
     ./tools/release-packages update-main-repo PATH_TO_ZULIP_DIR 0.4.0
 | 
						|
 | 
						|
   You can also update the requirements to install the packages from a
 | 
						|
   specific commit, like so:
 | 
						|
 | 
						|
     ./tools/release-packages update-main-repo PATH_TO_ZULIP_DIR 0.4.0 --hash abcedef
 | 
						|
 | 
						|
8. Commit and push the outstanding changes in your zulip/ repo.
 | 
						|
 | 
						|
And you're done! Congrats!
 | 
						|
"""
 | 
						|
    parser = argparse.ArgumentParser(usage=usage)
 | 
						|
 | 
						|
    parser.add_argument('--cleanup', '-c',
 | 
						|
                        action='store_true',
 | 
						|
                        default=False,
 | 
						|
                        help='Remove build directories (dist/, build/, egg-info/, etc).')
 | 
						|
 | 
						|
    parser.add_argument('--build', '-b',
 | 
						|
                        metavar='VERSION_NUM',
 | 
						|
                        help=('Build sdists and wheels for all packages with the'
 | 
						|
                              'specified version number.'
 | 
						|
                              ' sdists and wheels are stored in <package_name>/dist/*.'))
 | 
						|
 | 
						|
    parser.add_argument('--release', '-r',
 | 
						|
                        action='store_true',
 | 
						|
                        default=False,
 | 
						|
                        help='Upload the packages to PyPA using twine.')
 | 
						|
 | 
						|
    subparsers = parser.add_subparsers(dest='subcommand')
 | 
						|
    parser_main_repo = subparsers.add_parser(
 | 
						|
        'update-main-repo',
 | 
						|
        help='Update the zulip/requirements/* in the main zulip repo.'
 | 
						|
    )
 | 
						|
    parser_main_repo.add_argument('repo', metavar='PATH_TO_ZULIP_DIR')
 | 
						|
    parser_main_repo.add_argument('version', metavar='version number of the packages')
 | 
						|
    parser_main_repo.add_argument('--hash', metavar='COMMIT_HASH')
 | 
						|
 | 
						|
    return parser.parse_args()
 | 
						|
 | 
						|
def main():
 | 
						|
    options = parse_args()
 | 
						|
 | 
						|
    glob_pattern = os.path.join(REPO_DIR, '*', 'setup.py')
 | 
						|
    setup_py_files = glob.glob(glob_pattern)
 | 
						|
 | 
						|
    if options.cleanup:
 | 
						|
        package_dirs = map(os.path.dirname, setup_py_files)
 | 
						|
        for package_dir in package_dirs:
 | 
						|
            cleanup(package_dir)
 | 
						|
 | 
						|
    if options.build:
 | 
						|
        package_dirs = map(os.path.dirname, setup_py_files)
 | 
						|
        for package_dir in package_dirs:
 | 
						|
            cleanup(package_dir)
 | 
						|
 | 
						|
        zulip_init = os.path.join(REPO_DIR, 'zulip', 'zulip', '__init__.py')
 | 
						|
        set_variable(zulip_init, '__version__', options.build)
 | 
						|
        bots_setup = os.path.join(REPO_DIR, 'zulip_bots', 'setup.py')
 | 
						|
        set_variable(bots_setup, 'ZULIP_BOTS_VERSION', options.build)
 | 
						|
        set_variable(bots_setup, 'IS_PYPA_PACKAGE', True)
 | 
						|
        botserver_setup = os.path.join(REPO_DIR, 'zulip_botserver', 'setup.py')
 | 
						|
        set_variable(botserver_setup, 'ZULIP_BOTSERVER_VERSION', options.build)
 | 
						|
 | 
						|
        for setup_file in setup_py_files:
 | 
						|
            package_name = os.path.basename(os.path.dirname(setup_file))
 | 
						|
            if package_name == 'zulip_bots':
 | 
						|
                generate_bdist_wheel(setup_file, package_name)
 | 
						|
            else:
 | 
						|
                generate_bdist_wheel(setup_file, package_name, universal=True)
 | 
						|
 | 
						|
        set_variable(bots_setup, 'IS_PYPA_PACKAGE', False)
 | 
						|
 | 
						|
    if options.release:
 | 
						|
        dist_dirs = glob.glob(os.path.join(REPO_DIR, '*', 'dist', '*'))
 | 
						|
        twine_upload(dist_dirs)
 | 
						|
 | 
						|
    if options.subcommand == 'update-main-repo':
 | 
						|
        if options.hash:
 | 
						|
            update_requirements_in_zulip_repo(options.repo, options.version,
 | 
						|
                                              options.hash)
 | 
						|
        else:
 | 
						|
            update_requirements_in_zulip_repo(options.repo, options.version,
 | 
						|
                                              options.version)
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
    main()
 |