def build_osx():
    """Build OS X .dmg/.app."""
    utils.print_title("Updating 3rdparty content")
    update_3rdparty.update_pdfjs()
    utils.print_title("Building .app via pyinstaller")
    call_tox('pyinstaller', '-r')
    utils.print_title("Building .dmg")
    subprocess.check_call(['make', '-f', 'scripts/dev/Makefile-dmg'])
    utils.print_title("Cleaning up...")
    for f in ['wc.dmg', 'template.dmg']:
        os.remove(f)
    for d in ['dist', 'build']:
        shutil.rmtree(d)

    dmg_name = 'qutebrowser-{}.dmg'.format(qutebrowser.__version__)
    os.rename('qutebrowser.dmg', dmg_name)

    utils.print_title("Running smoke test")
    with tempfile.TemporaryDirectory() as tmpdir:
        subprocess.check_call(['hdiutil', 'attach', dmg_name,
                               '-mountpoint', tmpdir])
        try:
            binary = os.path.join(tmpdir, 'qutebrowser.app', 'Contents',
                                  'MacOS', 'qutebrowser')
            smoke_test(binary)
        finally:
            subprocess.check_call(['hdiutil', 'detach', tmpdir])

    return [(dmg_name, 'application/x-apple-diskimage', 'OS X .dmg')]
def main():
    """Re-compile the given (or all) requirement files."""
    names = sys.argv[1:] if len(sys.argv) > 1 else sorted(get_all_names())

    for name in names:
        utils.print_title(name)
        filename = os.path.join(REQ_DIR,
                                'requirements-{}.txt-raw'.format(name))
        if name == 'qutebrowser':
            outfile = os.path.join(REPO_DIR, 'requirements.txt')
        else:
            outfile = os.path.join(REQ_DIR, 'requirements-{}.txt'.format(name))

        with tempfile.TemporaryDirectory() as tmpdir:
            pip_bin = os.path.join(tmpdir, 'bin', 'pip')
            subprocess.run(['virtualenv', tmpdir], check=True)
            subprocess.run([pip_bin, 'install', '-r', filename], check=True)
            reqs = subprocess.run([pip_bin, 'freeze'], check=True,
                                  stdout=subprocess.PIPE
                                  ).stdout.decode('utf-8')

        with open(filename, 'r', encoding='utf-8') as f:
            comments = read_comments(f)

        with open(outfile, 'w', encoding='utf-8') as f:
            f.write("# This file is automatically generated by "
                    "scripts/dev/recompile_requirements.py\n\n")
            for line in reqs.splitlines():
                f.write(convert_line(line, comments) + '\n')
def main_check():
    """Check coverage after a test run."""
    try:
        with open('coverage.xml', encoding='utf-8') as f:
            messages = check(f, PERFECT_FILES)
    except Skipped as e:
        print(e)
        messages = []

    if messages:
        print()
        print()
        utils.print_title("Coverage check failed")
        for msg in messages:
            print(msg.text)
        print()
        filters = ','.join(msg.filename for msg in messages)
        subprocess.check_call([sys.executable, '-m', 'coverage', 'report',
                               '--show-missing', '--include', filters])
        print()
        print("To debug this, run 'tox -e py35-cov' (or py34-cov) locally and "
              "check htmlcov/index.html")
        print("or check https://codecov.io/github/The-Compiler/qutebrowser")
        print()

    if 'CI' in os.environ:
        print("Keeping coverage.xml on CI.")
    else:
        os.remove('coverage.xml')
    return 1 if messages else 0
Example #4
0
def main_check():
    """Check coverage after a test run."""
    try:
        with open('coverage.xml', encoding='utf-8') as f:
            messages = check(f, PERFECT_FILES)
    except Skipped as e:
        print(e)
        messages = []

    if messages:
        print()
        print()
        utils.print_title("Coverage check failed")
        for msg in messages:
            print(msg.text)
        print()
        print("You can run 'tox -e py35-cov' (or py34-cov) locally and check "
              "htmlcov/index.html to debug this.")
        print()

    if 'CI' in os.environ:
        print("Keeping coverage.xml on CI.")
    else:
        os.remove('coverage.xml')
    return 1 if messages else 0
Example #5
0
def github_upload(artifacts, tag):
    """Upload the given artifacts to GitHub.

    Args:
        artifacts: A list of (filename, mimetype, description) tuples
        tag: The name of the release tag
    """
    import github3
    utils.print_title("Uploading to github...")

    token = read_github_token()
    gh = github3.login(token=token)
    repo = gh.repository('qutebrowser', 'qutebrowser')

    release = None  # to satisfy pylint
    for release in repo.releases():
        if release.tag_name == tag:
            break
    else:
        raise Exception("No release found for {!r}!".format(tag))

    for filename, mimetype, description in artifacts:
        with open(filename, 'rb') as f:
            basename = os.path.basename(filename)
            asset = release.upload_asset(mimetype, basename, f)
        asset.edit(basename, description)
Example #6
0
def link_pyqt():
    """Symlink the systemwide PyQt/sip into the virtualenv."""
    if os.name == 'nt':
        return
    utils.print_title("Softlinking PyQt5")
    sys_path = distutils.sysconfig.get_python_lib()
    venv_path = venv_python(
        '-c', 'from distutils.sysconfig import get_python_lib\n'
              'print(get_python_lib())', output=True).rstrip()
    globbed_sip = (glob.glob(os.path.join(sys_path, 'sip*.so')) +
                   glob.glob(os.path.join(sys_path, 'sip*.pyd')))
    if not globbed_sip:
        print("Did not find sip in {}!".format(sys_path), file=sys.stderr)
        sys.exit(1)
    files = [
        'PyQt5',
    ]
    files += [os.path.basename(e) for e in globbed_sip]
    for fn in files:
        source = os.path.join(sys_path, fn)
        link_name = os.path.join(venv_path, fn)
        if not os.path.exists(source):
            raise FileNotFoundError(source)
        print('{} -> {}'.format(source, link_name))
        os.symlink(source, link_name)
Example #7
0
def build_sdist():
    """Build an sdist and list the contents."""
    utils.print_title("Building sdist")

    _maybe_remove('dist')

    subprocess.check_call([sys.executable, 'setup.py', 'sdist'])
    dist_files = os.listdir(os.path.abspath('dist'))
    assert len(dist_files) == 1

    dist_file = os.path.join('dist', dist_files[0])
    subprocess.check_call(['gpg', '--detach-sign', '-a', dist_file])

    tar = tarfile.open(dist_file)
    by_ext = collections.defaultdict(list)

    for tarinfo in tar.getmembers():
        if not tarinfo.isfile():
            continue
        name = os.sep.join(tarinfo.name.split(os.sep)[1:])
        _base, ext = os.path.splitext(name)
        by_ext[ext].append(name)

    assert '.pyc' not in by_ext

    utils.print_title("sdist contents")

    for ext, files in sorted(by_ext.items()):
        utils.print_subtitle(ext)
        print('\n'.join(files))
Example #8
0
def run_asciidoc2html(args):
    """Common buildsteps used for all OS'."""
    utils.print_title("Running asciidoc2html.py")
    if args.asciidoc is not None:
        a2h_args = ['--asciidoc'] + args.asciidoc
    else:
        a2h_args = []
    call_script('asciidoc2html.py', *a2h_args)
Example #9
0
def create_venv():
    """Create a new virtualenv."""
    utils.print_title("Creating virtualenv")
    if os.name == 'nt':
        sys_site = ['--system-site-packages']
    else:
        sys_site = []
    subprocess.check_call(['virtualenv'] + sys_site +
                          ['-p', sys.executable, g_path])
Example #10
0
def test_toolchain():
    """Test if imports work properly."""
    utils.print_title("Checking toolchain")
    packages = ['sip', 'PyQt5.QtCore', 'PyQt5.QtWebKit', 'qutebrowser.app']
    if g_args.dev:
        packages += get_dev_packages(short=True)
    for pkg in packages:
        if pkg == 'beautifulsoup4':
            pkg = 'bs4'
        print("Importing {}".format(pkg))
        venv_python('-c', 'import {}'.format(pkg))
def dump_infos(parsed):
    """Dump all possible infos for the given crash."""
    if not parsed.present:
        info = get_info(parsed.pid)
        print("{}: Signal {} with no coredump: {}".format(
            parsed.time, info.get('Signal', None),
            info.get('Command Line', None)))
    else:
        print('\n\n\n')
        utils.print_title('{} - {}'.format(parsed.time, parsed.pid))
        sys.stdout.flush()
        dump_infos_gdb(parsed)
Example #12
0
def main():
    """Main entry point."""
    utils.change_cwd()
    read_files = config.read('.run_checks')
    if not read_files:
        raise OSError("Could not read config!")
    exit_status = collections.OrderedDict()
    exit_status_bool = {}

    args = _parse_args()
    checkers = _get_checkers()

    groups = ['global']
    groups += config.get('DEFAULT', 'targets').split(',')
    groups.append('setup')

    for group in groups:
        print()
        utils.print_title(group)
        for name, func in checkers[group].items():
            if _checker_enabled(args, group, name):
                utils.print_subtitle(name)
                status = func()
                key = '{}_{}'.format(group, name)
                exit_status[key] = status
                if name == 'flake8':
                    # pyflakes uses True for errors and False for ok.
                    exit_status_bool[key] = not status
                elif isinstance(status, bool):
                    exit_status_bool[key] = status
                else:
                    # sys.exit(0) means no problems -> True, anything != 0
                    # means problems.
                    exit_status_bool[key] = (status == 0)
            elif not args.quiet:
                utils.print_subtitle(name)
                utils.print_col("Checker disabled.", 'blue')
    print()
    utils.print_col("Exit status values:", 'yellow')
    for (k, v) in exit_status.items():
        ok = exit_status_bool[k]
        color = 'green' if ok else 'red'
        utils.print_col(
            '    {} - {} ({})'.format(k, 'ok' if ok else 'FAIL', v), color)
    if all(exit_status_bool.values()):
        return 0
    else:
        return 1
Example #13
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--asciidoc', help="Full path to python and "
                        "asciidoc.py. If not given, it's searched in PATH.",
                        nargs=2, required=False,
                        metavar=('PYTHON', 'ASCIIDOC'))
    parser.add_argument('--upload', help="Tag to upload the release for",
                        nargs=1, required=False, metavar='TAG')
    args = parser.parse_args()
    utils.change_cwd()

    upload_to_pypi = False

    if args.upload is not None:
        # Fail early when trying to upload without github3 installed
        # or without API token
        import github3  # pylint: disable=unused-variable
        read_github_token()

    run_asciidoc2html(args)
    if os.name == 'nt':
        if sys.maxsize > 2**32:
            # WORKAROUND
            print("Due to a python/Windows bug, this script needs to be run ")
            print("with a 32bit Python.")
            print()
            print("See http://bugs.python.org/issue24493 and ")
            print("https://github.com/pypa/virtualenv/issues/774")
            sys.exit(1)
        artifacts = build_windows()
    elif sys.platform == 'darwin':
        artifacts = build_mac()
    else:
        test_makefile()
        artifacts = build_sdist()
        upload_to_pypi = True

    if args.upload is not None:
        utils.print_title("Press enter to release...")
        input()
        github_upload(artifacts, args.upload[0])
        if upload_to_pypi:
            pypi_upload(artifacts)
    else:
        print()
        utils.print_title("Artifacts")
        for artifact in artifacts:
            print(artifact)
Example #14
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--no-asciidoc', action='store_true',
                        help="Don't generate docs")
    parser.add_argument('--asciidoc', help="Full path to python and "
                        "asciidoc.py. If not given, it's searched in PATH.",
                        nargs=2, required=False,
                        metavar=('PYTHON', 'ASCIIDOC'))
    parser.add_argument('--upload', help="Tag to upload the release for",
                        nargs=1, required=False, metavar='TAG')
    args = parser.parse_args()
    utils.change_cwd()

    upload_to_pypi = False

    if args.upload is not None:
        # Fail early when trying to upload without github3 installed
        # or without API token
        import github3  # pylint: disable=unused-variable
        read_github_token()

    if args.no_asciidoc:
        os.makedirs(os.path.join('qutebrowser', 'html', 'doc'), exist_ok=True)
    else:
        run_asciidoc2html(args)

    if os.name == 'nt':
        artifacts = build_windows()
    elif sys.platform == 'darwin':
        artifacts = build_mac()
    else:
        test_makefile()
        artifacts = build_sdist()
        upload_to_pypi = True

    if args.upload is not None:
        utils.print_title("Press enter to release...")
        input()
        github_upload(artifacts, args.upload[0])
        if upload_to_pypi:
            pypi_upload(artifacts)
    else:
        print()
        utils.print_title("Artifacts")
        for artifact in artifacts:
            print(artifact)
Example #15
0
def main():
    """Main entry point."""
    global g_path, g_args
    g_args = parse_args()
    if not g_args.path:
        print("Refusing to run with empty path!", file=sys.stderr)
        sys.exit(1)
    g_path = os.path.abspath(g_args.path)
    check_exists()
    create_venv()
    utils.print_title("Calling setup.py")
    venv_python('setup.py', 'develop')
    if g_args.dev:
        utils.print_title("Installing developer packages")
        install_dev_packages()
    link_pyqt()
    test_toolchain()
Example #16
0
def build_osx():
    """Build OS X .dmg/.app."""
    utils.print_title("Updating 3rdparty content")
    update_3rdparty.update_pdfjs()
    utils.print_title("Building .app via pyinstaller")
    call_tox('pyinstaller')
    utils.print_title("Building .dmg")
    subprocess.check_call(['make', '-f', 'scripts/dev/Makefile-dmg'])
    utils.print_title("Cleaning up...")
    for f in ['wc.dmg', 'template.dmg']:
        os.remove(f)
    for d in ['dist', 'build']:
        shutil.rmtree(d)
Example #17
0
def build_sdist():
    """Build an sdist and list the contents."""
    utils.print_title("Building sdist")

    _maybe_remove('dist')

    subprocess.run([sys.executable, 'setup.py', 'sdist'], check=True)
    dist_files = os.listdir(os.path.abspath('dist'))
    assert len(dist_files) == 1

    dist_file = os.path.join('dist', dist_files[0])
    subprocess.run(['gpg', '--detach-sign', '-a', dist_file], check=True)

    tar = tarfile.open(dist_file)
    by_ext = collections.defaultdict(list)

    for tarinfo in tar.getmembers():
        if not tarinfo.isfile():
            continue
        name = os.sep.join(tarinfo.name.split(os.sep)[1:])
        _base, ext = os.path.splitext(name)
        by_ext[ext].append(name)

    assert '.pyc' not in by_ext

    utils.print_title("sdist contents")

    for ext, files in sorted(by_ext.items()):
        utils.print_subtitle(ext)
        print('\n'.join(files))

    filename = 'qutebrowser-{}.tar.gz'.format(qutebrowser.__version__)
    artifacts = [
        (os.path.join('dist', filename), 'application/gzip', 'Source release'),
        (os.path.join('dist', filename + '.asc'), 'application/pgp-signature',
         'Source release - PGP signature'),
    ]

    return artifacts
def main():
    """Re-compile the given (or all) requirement files."""
    names = sys.argv[1:] if len(sys.argv) > 1 else sorted(get_all_names())

    utils.print_title('pip')
    pip_requirements = get_requirements(None)

    for name in names:
        utils.print_title(name)

        if name == 'qutebrowser':
            outfile = os.path.join(REPO_DIR, 'requirements.txt')
        else:
            outfile = os.path.join(REQ_DIR, 'requirements-{}.txt'.format(name))

        if name == 'pip':
            requirements = [req for req in pip_requirements
                            if not req.startswith('pip==')]
            comments = {
                'filter': {},
                'comment': {},
                'ignore': [],
                'replace': {},
            }
        else:
            filename = os.path.join(REQ_DIR,
                                    'requirements-{}.txt-raw'.format(name))
            requirements = get_requirements(filename, exclude=pip_requirements)

            with open(filename, 'r', encoding='utf-8') as f:
                comments = read_comments(f)

        with open(outfile, 'w', encoding='utf-8') as f:
            f.write("# This file is automatically generated by "
                    "scripts/dev/recompile_requirements.py\n\n")
            for line in requirements:
                converted = convert_line(line, comments)
                f.write(converted + '\n')
Example #19
0
def apply_xcb_util_workaround(
    venv_dir: pathlib.Path,
    pyqt_type: str,
    pyqt_version: str,
) -> None:
    """If needed (Debian Stable), symlink libxcb-util.so.0 -> .1.

    WORKAROUND for https://bugreports.qt.io/browse/QTBUG-88688
    """
    utils.print_title("Running xcb-util workaround")

    if not sys.platform.startswith('linux'):
        print("Workaround not needed: Not on Linux.")
        return
    if pyqt_type != 'binary':
        print("Workaround not needed: Not installing from PyQt binaries.")
        return
    if pyqt_version not in ['auto', '5.15']:
        print("Workaround not needed: Not installing Qt 5.15.")
        return

    try:
        libs = _find_libs()
    except subprocess.CalledProcessError as e:
        utils.print_error(
            f'Workaround failed: ldconfig exited with status {e.returncode}')
        return

    abi_type = 'libc6,x86-64'  # the only one PyQt wheels are available for

    if ('libxcb-util.so.1', abi_type) in libs:
        print("Workaround not needed: libxcb-util.so.1 found.")
        return

    try:
        libxcb_util_libs = libs['libxcb-util.so.0', abi_type]
    except KeyError:
        utils.print_error('Workaround failed: libxcb-util.so.0 not found.')
        return

    if len(libxcb_util_libs) > 1:
        utils.print_error(
            f'Workaround failed: Multiple matching libxcb-util found: '
            f'{libxcb_util_libs}')
        return

    libxcb_util_path = pathlib.Path(libxcb_util_libs[0])

    code = [
        'from PyQt5.QtCore import QLibraryInfo',
        'print(QLibraryInfo.location(QLibraryInfo.LibrariesPath))',
    ]
    proc = run_venv(venv_dir,
                    'python',
                    '-c',
                    '; '.join(code),
                    capture_output=True)
    venv_lib_path = pathlib.Path(proc.stdout.strip())

    link_path = venv_lib_path / libxcb_util_path.with_suffix('.1').name

    # This gives us a nicer path to print, and also conveniently makes sure we
    # didn't accidentally end up with a path outside the venv.
    rel_link_path = venv_dir / link_path.relative_to(venv_dir.resolve())
    print_command('ln -s', libxcb_util_path, rel_link_path, venv=False)

    link_path.symlink_to(libxcb_util_path)
Example #20
0
def build_windows():
    """Build windows executables/setups."""
    parts = str(sys.version_info.major), str(sys.version_info.minor)
    ver = ''.join(parts)
    dotver = '.'.join(parts)
    python_x86 = r'C:\Python{}_x32\python.exe'.format(ver)
    python_x64 = r'C:\Python{}\python.exe'.format(ver)

    utils.print_title("Running 32bit freeze.py build_exe")
    call_script('freeze.py', 'build_exe', python=python_x86)
    utils.print_title("Running 64bit freeze.py build_exe")
    call_script('freeze.py', 'build_exe', python=python_x64)
    utils.print_title("Running 32bit freeze.py bdist_msi")
    call_script('freeze.py', 'bdist_msi', python=python_x86)
    utils.print_title("Running 64bit freeze.py bdist_msi")
    call_script('freeze.py', 'bdist_msi', python=python_x64)

    destdir = os.path.join('dist', 'zip')
    _maybe_remove(destdir)
    os.makedirs(destdir)

    basedirname = 'qutebrowser-{}'.format(qutebrowser.__version__)
    builddir = os.path.join('build', basedirname)
    _maybe_remove(builddir)

    utils.print_title("Zipping 32bit standalone...")
    name = 'qutebrowser-{}-windows-standalone-win32'.format(
        qutebrowser.__version__)
    origin = os.path.join('build', 'exe.win32-{}'.format(dotver))
    os.rename(origin, builddir)
    shutil.make_archive(os.path.join(destdir, name), 'zip', 'build',
                        basedirname)
    shutil.rmtree(builddir)

    utils.print_title("Zipping 64bit standalone...")
    name = 'qutebrowser-{}-windows-standalone-amd64'.format(
        qutebrowser.__version__)
    origin = os.path.join('build', 'exe.win-amd64-{}'.format(dotver))
    os.rename(origin, builddir)
    shutil.make_archive(os.path.join(destdir, name), 'zip', 'build',
                        basedirname)
    shutil.rmtree(builddir)

    utils.print_title("Creating final zip...")
    shutil.move(
        os.path.join(
            'dist',
            'qutebrowser-{}-amd64.msi'.format(qutebrowser.__version__)),
        os.path.join('dist', 'zip'))
    shutil.move(
        os.path.join(
            'dist',
            'qutebrowser-{}-win32.msi'.format(qutebrowser.__version__)),
        os.path.join('dist', 'zip'))
    shutil.make_archive(
        'qutebrowser-{}-windows'.format(qutebrowser.__version__), 'zip',
        destdir)
def build_windows():
    """Build windows executables/setups."""
    utils.print_title("Updating 3rdparty content")
    update_3rdparty.update_pdfjs()

    utils.print_title("Building Windows binaries")
    parts = str(sys.version_info.major), str(sys.version_info.minor)
    ver = ''.join(parts)
    dotver = '.'.join(parts)
    python_x86 = r'C:\Python{}_x32'.format(ver)
    python_x64 = r'C:\Python{}'.format(ver)

    artifacts = []

    utils.print_title("Rebuilding tox environment")
    call_tox('cxfreeze-windows', '-r', '--notest')
    utils.print_title("Running 32bit freeze.py build_exe")
    call_tox('cxfreeze-windows', 'build_exe', python=python_x86)
    utils.print_title("Running 32bit freeze.py bdist_msi")
    call_tox('cxfreeze-windows', 'bdist_msi', python=python_x86)
    utils.print_title("Running 64bit freeze.py build_exe")
    call_tox('cxfreeze-windows', 'build_exe', python=python_x64)
    utils.print_title("Running 64bit freeze.py bdist_msi")
    call_tox('cxfreeze-windows', 'bdist_msi', python=python_x64)

    name_32 = 'qutebrowser-{}-win32.msi'.format(qutebrowser.__version__)
    name_64 = 'qutebrowser-{}-amd64.msi'.format(qutebrowser.__version__)

    artifacts += [
        (os.path.join('dist', name_32), 'application/x-msi',
         'Windows 32bit installer'),
        (os.path.join('dist', name_64), 'application/x-msi',
         'Windows 64bit installer'),
    ]

    utils.print_title("Running 32bit smoke test")
    smoke_test('build/exe.win32-{}/qutebrowser.exe'.format(dotver))
    utils.print_title("Running 64bit smoke test")
    smoke_test('build/exe.win-amd64-{}/qutebrowser.exe'.format(dotver))

    basedirname = 'qutebrowser-{}'.format(qutebrowser.__version__)
    builddir = os.path.join('build', basedirname)
    _maybe_remove(builddir)

    utils.print_title("Zipping 32bit standalone...")
    name = 'qutebrowser-{}-windows-standalone-win32'.format(
        qutebrowser.__version__)
    origin = os.path.join('build', 'exe.win32-{}'.format(dotver))
    os.rename(origin, builddir)
    shutil.make_archive(name, 'zip', 'build', basedirname)
    shutil.rmtree(builddir)
    artifacts.append(('{}.zip'.format(name),
                      'application/zip',
                      'Windows 32bit standalone'))

    utils.print_title("Zipping 64bit standalone...")
    name = 'qutebrowser-{}-windows-standalone-amd64'.format(
        qutebrowser.__version__)
    origin = os.path.join('build', 'exe.win-amd64-{}'.format(dotver))
    os.rename(origin, builddir)
    shutil.make_archive(name, 'zip', 'build', basedirname)
    shutil.rmtree(builddir)
    artifacts.append(('{}.zip'.format(name),
                      'application/zip',
                      'Windows 64bit standalone'))

    return artifacts
Example #22
0
def test_makefile():
    """Make sure the Makefile works correctly."""
    utils.print_title("Testing makefile")
    with tempfile.TemporaryDirectory() as tmpdir:
        subprocess.run(['make', '-f', 'misc/Makefile',
                        'DESTDIR={}'.format(tmpdir), 'install'], check=True)
Example #23
0
def test_makefile():
    """Make sure the Makefile works correctly."""
    utils.print_title("Testing makefile")
    with tempfile.TemporaryDirectory() as tmpdir:
        subprocess.run(['make', '-f', 'misc/Makefile',
                        'DESTDIR={}'.format(tmpdir), 'install'], check=True)
Example #24
0
def pypi_upload(artifacts):
    """Upload the given artifacts to PyPI using twine."""
    utils.print_title("Uploading to PyPI...")
    run_twine('upload', artifacts)
Example #25
0
def build_windows():
    """Build windows executables/setups."""
    utils.print_title("Updating 3rdparty content")
    update_3rdparty.run(ace=False, pdfjs=True, fancy_dmg=False)

    utils.print_title("Building Windows binaries")
    parts = str(sys.version_info.major), str(sys.version_info.minor)
    ver = ''.join(parts)
    dot_ver = '.'.join(parts)

    # Get python path from registry if possible
    try:
        reg64_key = winreg.OpenKeyEx(winreg.HKEY_LOCAL_MACHINE,
                                     r'SOFTWARE\Python\PythonCore'
                                     r'\{}\InstallPath'.format(dot_ver))
        python_x64 = winreg.QueryValueEx(reg64_key, 'ExecutablePath')[0]
    except FileNotFoundError:
        python_x64 = r'C:\Python{}\python.exe'.format(ver)

    out_pyinstaller = os.path.join('dist', 'qutebrowser')
    out_64 = os.path.join('dist',
                          'qutebrowser-{}-x64'.format(qutebrowser.__version__))

    artifacts = []

    from scripts.dev import gen_versioninfo
    utils.print_title("Updating VersionInfo file")
    gen_versioninfo.main()

    utils.print_title("Running pyinstaller 64bit")
    _maybe_remove(out_64)
    call_tox('pyinstaller', '-r', python=python_x64)
    shutil.move(out_pyinstaller, out_64)

    utils.print_title("Running 64bit smoke test")
    smoke_test(os.path.join(out_64, 'qutebrowser.exe'))

    utils.print_title("Building installers")
    subprocess.run(['makensis.exe',
                    '/DX64',
                    '/DVERSION={}'.format(qutebrowser.__version__),
                    'misc/qutebrowser.nsi'], check=True)

    name_64 = 'qutebrowser-{}-amd64.exe'.format(qutebrowser.__version__)

    artifacts += [
        (os.path.join('dist', name_64),
         'application/vnd.microsoft.portable-executable',
         'Windows 64bit installer'),
    ]

    utils.print_title("Zipping 64bit standalone...")
    name = 'qutebrowser-{}-windows-standalone-amd64'.format(
        qutebrowser.__version__)
    shutil.make_archive(name, 'zip', 'dist', os.path.basename(out_64))
    artifacts.append(('{}.zip'.format(name),
                      'application/zip',
                      'Windows 64bit standalone'))

    return artifacts
Example #26
0
def upgrade_pip(venv_dir: pathlib.Path) -> None:
    """Upgrade pip inside a virtualenv."""
    utils.print_title("Upgrading pip")
    pip_install(venv_dir, '-U', 'pip')
def build_windows():
    """Build windows executables/setups."""
    utils.print_title("Updating 3rdparty content")
    # Currently disabled because QtWebEngine has no pdfjs support
    # update_3rdparty.run(ace=False, pdfjs=True, fancy_dmg=False)

    utils.print_title("Building Windows binaries")
    parts = str(sys.version_info.major), str(sys.version_info.minor)
    ver = ''.join(parts)
    python_x86 = r'C:\Python{}-32\python.exe'.format(ver)
    python_x64 = r'C:\Python{}\python.exe'.format(ver)
    out_pyinstaller = os.path.join('dist', 'qutebrowser')
    out_32 = os.path.join('dist',
                          'qutebrowser-{}-x86'.format(qutebrowser.__version__))
    out_64 = os.path.join('dist',
                          'qutebrowser-{}-x64'.format(qutebrowser.__version__))

    artifacts = []

    utils.print_title("Running pyinstaller 32bit")
    _maybe_remove(out_32)
    call_tox('pyinstaller', '-r', python=python_x86)
    shutil.move(out_pyinstaller, out_32)
    patch_windows(out_32)

    utils.print_title("Running pyinstaller 64bit")
    _maybe_remove(out_64)
    call_tox('pyinstaller', '-r', python=python_x64)
    shutil.move(out_pyinstaller, out_64)
    patch_windows(out_64)

    utils.print_title("Building installers")
    subprocess.check_call([
        'makensis.exe', '/DVERSION={}'.format(qutebrowser.__version__),
        'misc/qutebrowser.nsi'
    ])
    subprocess.check_call([
        'makensis.exe', '/DX64',
        '/DVERSION={}'.format(qutebrowser.__version__), 'misc/qutebrowser.nsi'
    ])

    name_32 = 'qutebrowser-{}-win32.exe'.format(qutebrowser.__version__)
    name_64 = 'qutebrowser-{}-amd64.exe'.format(qutebrowser.__version__)

    artifacts += [
        (os.path.join('dist', name_32),
         'application/vnd.microsoft.portable-executable',
         'Windows 32bit installer'),
        (os.path.join('dist', name_64),
         'application/vnd.microsoft.portable-executable',
         'Windows 64bit installer'),
    ]

    utils.print_title("Running 32bit smoke test")
    smoke_test(os.path.join(out_32, 'qutebrowser.exe'))
    utils.print_title("Running 64bit smoke test")
    smoke_test(os.path.join(out_64, 'qutebrowser.exe'))

    utils.print_title("Zipping 32bit standalone...")
    name = 'qutebrowser-{}-windows-standalone-win32'.format(
        qutebrowser.__version__)
    shutil.make_archive(name, 'zip', 'dist', os.path.basename(out_32))
    artifacts.append(
        ('{}.zip'.format(name), 'application/zip', 'Windows 32bit standalone'))

    utils.print_title("Zipping 64bit standalone...")
    name = 'qutebrowser-{}-windows-standalone-amd64'.format(
        qutebrowser.__version__)
    shutil.make_archive(name, 'zip', 'dist', os.path.basename(out_64))
    artifacts.append(
        ('{}.zip'.format(name), 'application/zip', 'Windows 64bit standalone'))

    return artifacts
def build_windows():
    """Build windows executables/setups."""
    utils.print_title("Updating 3rdparty content")
    update_3rdparty.main()

    utils.print_title("Building Windows binaries")
    parts = str(sys.version_info.major), str(sys.version_info.minor)
    ver = "".join(parts)
    dotver = ".".join(parts)
    python_x86 = r"C:\Python{}_x32".format(ver)
    python_x64 = r"C:\Python{}".format(ver)

    utils.print_title("Running 32bit freeze.py build_exe")
    call_freeze("build_exe", python=python_x86)
    utils.print_title("Running 32bit freeze.py bdist_msi")
    call_freeze("bdist_msi", python=python_x86)
    utils.print_title("Running 64bit freeze.py build_exe")
    call_freeze("build_exe", python=python_x64)
    utils.print_title("Running 64bit freeze.py bdist_msi")
    call_freeze("bdist_msi", python=python_x64)

    utils.print_title("Running 32bit smoke test")
    smoke_test("build/exe.win32-{}/qutebrowser.exe".format(dotver))
    utils.print_title("Running 64bit smoke test")
    smoke_test("build/exe.win-amd64-{}/qutebrowser.exe".format(dotver))

    destdir = os.path.join("dist", "zip")
    _maybe_remove(destdir)
    os.makedirs(destdir)

    basedirname = "qutebrowser-{}".format(qutebrowser.__version__)
    builddir = os.path.join("build", basedirname)
    _maybe_remove(builddir)

    utils.print_title("Zipping 32bit standalone...")
    name = "qutebrowser-{}-windows-standalone-win32".format(qutebrowser.__version__)
    origin = os.path.join("build", "exe.win32-{}".format(dotver))
    os.rename(origin, builddir)
    shutil.make_archive(os.path.join(destdir, name), "zip", "build", basedirname)
    shutil.rmtree(builddir)

    utils.print_title("Zipping 64bit standalone...")
    name = "qutebrowser-{}-windows-standalone-amd64".format(qutebrowser.__version__)
    origin = os.path.join("build", "exe.win-amd64-{}".format(dotver))
    os.rename(origin, builddir)
    shutil.make_archive(os.path.join(destdir, name), "zip", "build", basedirname)
    shutil.rmtree(builddir)

    utils.print_title("Creating final zip...")
    shutil.move(
        os.path.join("dist", "qutebrowser-{}-amd64.msi".format(qutebrowser.__version__)), os.path.join("dist", "zip")
    )
    shutil.move(
        os.path.join("dist", "qutebrowser-{}-win32.msi".format(qutebrowser.__version__)), os.path.join("dist", "zip")
    )
    shutil.make_archive("qutebrowser-{}-windows".format(qutebrowser.__version__), "zip", destdir)
Example #29
0
def install_qutebrowser(venv_dir: pathlib.Path) -> None:
    """Install qutebrowser itself as an editable install."""
    utils.print_title("Installing qutebrowser")
    pip_install(venv_dir, '-e', str(REPO_ROOT))
Example #30
0
def build_windows():
    """Build windows executables/setups."""
    utils.print_title("Updating 3rdparty content")
    update_3rdparty.run(nsis=True, ace=False, pdfjs=True, fancy_dmg=False)

    utils.print_title("Building Windows binaries")

    python_x64 = _get_windows_python_path(x64=True)
    python_x86 = _get_windows_python_path(x64=False)

    out_pyinstaller = os.path.join('dist', 'qutebrowser')
    out_32 = os.path.join('dist',
                          'qutebrowser-{}-x86'.format(qutebrowser.__version__))
    out_64 = os.path.join('dist',
                          'qutebrowser-{}-x64'.format(qutebrowser.__version__))

    artifacts = []

    from scripts.dev import gen_versioninfo
    utils.print_title("Updating VersionInfo file")
    gen_versioninfo.main()

    utils.print_title("Running pyinstaller 32bit")
    _maybe_remove(out_32)
    call_tox('pyinstaller', '-r', python=python_x86)
    shutil.move(out_pyinstaller, out_32)
    patch_windows(out_32, x64=False)

    utils.print_title("Running pyinstaller 64bit")
    _maybe_remove(out_64)
    call_tox('pyinstaller', '-r', python=python_x64)
    shutil.move(out_pyinstaller, out_64)
    patch_windows(out_64, x64=True)

    utils.print_title("Running 32bit smoke test")
    smoke_test(os.path.join(out_32, 'qutebrowser.exe'))
    utils.print_title("Running 64bit smoke test")
    smoke_test(os.path.join(out_64, 'qutebrowser.exe'))

    utils.print_title("Building installers")
    subprocess.run(['makensis.exe',
                    '/DVERSION={}'.format(qutebrowser.__version__),
                    'misc/nsis/qutebrowser.nsi'], check=True)
    subprocess.run(['makensis.exe',
                    '/DX86',
                    '/DVERSION={}'.format(qutebrowser.__version__),
                    'misc/nsis/qutebrowser.nsi'], check=True)

    name_32 = 'qutebrowser-{}-win32.exe'.format(qutebrowser.__version__)
    name_64 = 'qutebrowser-{}-amd64.exe'.format(qutebrowser.__version__)

    artifacts += [
        (os.path.join('dist', name_32),
         'application/vnd.microsoft.portable-executable',
         'Windows 32bit installer'),
        (os.path.join('dist', name_64),
         'application/vnd.microsoft.portable-executable',
         'Windows 64bit installer'),
    ]

    utils.print_title("Zipping 32bit standalone...")
    name = 'qutebrowser-{}-windows-standalone-win32'.format(
        qutebrowser.__version__)
    shutil.make_archive(name, 'zip', 'dist', os.path.basename(out_32))
    artifacts.append(('{}.zip'.format(name),
                      'application/zip',
                      'Windows 32bit standalone'))

    utils.print_title("Zipping 64bit standalone...")
    name = 'qutebrowser-{}-windows-standalone-amd64'.format(
        qutebrowser.__version__)
    shutil.make_archive(name, 'zip', 'dist', os.path.basename(out_64))
    artifacts.append(('{}.zip'.format(name),
                      'application/zip',
                      'Windows 64bit standalone'))

    return artifacts
Example #31
0
def build_mac():
    """Build macOS .dmg/.app."""
    utils.print_title("Cleaning up...")
    for f in ['wc.dmg', 'template.dmg']:
        try:
            os.remove(f)
        except FileNotFoundError:
            pass
    for d in ['dist', 'build']:
        shutil.rmtree(d, ignore_errors=True)
    utils.print_title("Updating 3rdparty content")
    update_3rdparty.run(ace=False, pdfjs=True, fancy_dmg=False)
    utils.print_title("Building .app via pyinstaller")
    call_tox('pyinstaller', '-r')
    utils.print_title("Patching .app")
    patch_mac_app()
    utils.print_title("Building .dmg")
    subprocess.run(['make', '-f', 'scripts/dev/Makefile-dmg'], check=True)

    dmg_name = 'qutebrowser-{}.dmg'.format(qutebrowser.__version__)
    os.rename('qutebrowser.dmg', dmg_name)

    utils.print_title("Running smoke test")

    try:
        with tempfile.TemporaryDirectory() as tmpdir:
            subprocess.run(['hdiutil', 'attach', dmg_name,
                            '-mountpoint', tmpdir], check=True)
            try:
                binary = os.path.join(tmpdir, 'qutebrowser.app', 'Contents',
                                      'MacOS', 'qutebrowser')
                smoke_test(binary)
            finally:
                time.sleep(5)
                subprocess.run(['hdiutil', 'detach', tmpdir], check=False)
    except PermissionError as e:
        print("Failed to remove tempdir: {}".format(e))

    return [(dmg_name, 'application/x-apple-diskimage', 'macOS .dmg')]
Example #32
0
def pypi_upload(artifacts):
    """Upload the given artifacts to PyPI using twine."""
    utils.print_title("Uploading to PyPI...")
    filenames = [a[0] for a in artifacts]
    subprocess.run([sys.executable, '-m', 'twine', 'upload'] + filenames,
                   check=True)
Example #33
0
def build_windows():
    """Build windows executables/setups."""
    utils.print_title("Updating 3rdparty content")
    # Currently disabled because QtWebEngine has no pdfjs support
    # update_3rdparty.run(ace=False, pdfjs=True, fancy_dmg=False)

    utils.print_title("Building Windows binaries")
    parts = str(sys.version_info.major), str(sys.version_info.minor)
    ver = ''.join(parts)
    dot_ver = '.'.join(parts)

    # Get python path from registry if possible
    try:
        reg64_key = winreg.OpenKeyEx(
            winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\Python\PythonCore'
            r'\{}\InstallPath'.format(dot_ver))
        python_x64 = winreg.QueryValueEx(reg64_key, 'ExecutablePath')[0]
    except FileNotFoundError:
        python_x64 = r'C:\Python{}\python.exe'.format(ver)

    try:
        reg32_key = winreg.OpenKeyEx(
            winreg.HKEY_LOCAL_MACHINE,
            r'SOFTWARE\WOW6432Node\Python\PythonCore'
            r'\{}-32\InstallPath'.format(dot_ver))
        python_x86 = winreg.QueryValueEx(reg32_key, 'ExecutablePath')[0]
    except FileNotFoundError:
        python_x86 = r'C:\Python{}-32\python.exe'.format(ver)

    out_pyinstaller = os.path.join('dist', 'qutebrowser')
    out_32 = os.path.join('dist',
                          'qutebrowser-{}-x86'.format(qutebrowser.__version__))
    out_64 = os.path.join('dist',
                          'qutebrowser-{}-x64'.format(qutebrowser.__version__))

    artifacts = []

    utils.print_title("Updating VersionInfo file")
    gen_versioninfo.main()

    utils.print_title("Running pyinstaller 32bit")
    _maybe_remove(out_32)
    call_tox('pyinstaller', '-r', python=python_x86)
    shutil.move(out_pyinstaller, out_32)
    patch_windows(out_32)

    utils.print_title("Running pyinstaller 64bit")
    _maybe_remove(out_64)
    call_tox('pyinstaller', '-r', python=python_x64)
    shutil.move(out_pyinstaller, out_64)
    patch_windows(out_64)

    utils.print_title("Building installers")
    subprocess.run([
        'makensis.exe', '/DVERSION={}'.format(qutebrowser.__version__),
        'misc/qutebrowser.nsi'
    ],
                   check=True)
    subprocess.run([
        'makensis.exe', '/DX64', '/DVERSION={}'.format(
            qutebrowser.__version__), 'misc/qutebrowser.nsi'
    ],
                   check=True)

    name_32 = 'qutebrowser-{}-win32.exe'.format(qutebrowser.__version__)
    name_64 = 'qutebrowser-{}-amd64.exe'.format(qutebrowser.__version__)

    artifacts += [
        (os.path.join('dist', name_32),
         'application/vnd.microsoft.portable-executable',
         'Windows 32bit installer'),
        (os.path.join('dist', name_64),
         'application/vnd.microsoft.portable-executable',
         'Windows 64bit installer'),
    ]

    utils.print_title("Running 32bit smoke test")
    smoke_test(os.path.join(out_32, 'qutebrowser.exe'))
    utils.print_title("Running 64bit smoke test")
    smoke_test(os.path.join(out_64, 'qutebrowser.exe'))

    utils.print_title("Zipping 32bit standalone...")
    name = 'qutebrowser-{}-windows-standalone-win32'.format(
        qutebrowser.__version__)
    shutil.make_archive(name, 'zip', 'dist', os.path.basename(out_32))
    artifacts.append(
        ('{}.zip'.format(name), 'application/zip', 'Windows 32bit standalone'))

    utils.print_title("Zipping 64bit standalone...")
    name = 'qutebrowser-{}-windows-standalone-amd64'.format(
        qutebrowser.__version__)
    shutil.make_archive(name, 'zip', 'dist', os.path.basename(out_64))
    artifacts.append(
        ('{}.zip'.format(name), 'application/zip', 'Windows 64bit standalone'))

    return artifacts
Example #34
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--skip-docs', action='store_true',
                        help="Don't generate docs")
    parser.add_argument('--asciidoc', help="Full path to asciidoc.py. "
                        "If not given, it's searched in PATH.",
                        nargs='?')
    parser.add_argument('--asciidoc-python', help="Python to use for asciidoc."
                        "If not given, the current Python interpreter is used.",
                        nargs='?')
    parser.add_argument('--gh-token', help="GitHub token to use.",
                        nargs='?')
    parser.add_argument('--upload', action='store_true', required=False,
                        help="Toggle to upload the release to GitHub.")
    parser.add_argument('--no-confirm', action='store_true', required=False,
                        help="Skip confirmation before uploading.")
    parser.add_argument('--skip-packaging', action='store_true', required=False,
                        help="Skip Windows installer/zip generation.")
    parser.add_argument('--32bit', action='store_true', required=False,
                        help="Skip Windows 64 bit build.", dest='only_32bit')
    parser.add_argument('--64bit', action='store_true', required=False,
                        help="Skip Windows 32 bit build.", dest='only_64bit')
    parser.add_argument('--debug', action='store_true', required=False,
                        help="Build a debug build.")
    args = parser.parse_args()
    utils.change_cwd()

    upload_to_pypi = False

    if args.upload:
        # Fail early when trying to upload without github3 installed
        # or without API token
        import github3  # pylint: disable=unused-import
        gh_token = read_github_token(args.gh_token)
    else:
        gh_token = read_github_token(args.gh_token, optional=True)

    if not misc_checks.check_git():
        utils.print_error("Refusing to do a release with a dirty git tree")
        sys.exit(1)

    if args.skip_docs:
        os.makedirs(os.path.join('qutebrowser', 'html', 'doc'), exist_ok=True)
    else:
        run_asciidoc2html(args)

    if os.name == 'nt':
        artifacts = build_windows(
            gh_token=gh_token,
            skip_packaging=args.skip_packaging,
            only_32bit=args.only_32bit,
            only_64bit=args.only_64bit,
            debug=args.debug,
        )
    elif sys.platform == 'darwin':
        artifacts = build_mac(gh_token=gh_token, debug=args.debug)
    else:
        upgrade_sdist_dependencies()
        test_makefile()
        artifacts = build_sdist()
        upload_to_pypi = True

    if args.upload:
        version_tag = "v" + qutebrowser.__version__

        if not args.no_confirm:
            utils.print_title("Press enter to release {}...".format(version_tag))
            input()

        github_upload(artifacts, version_tag, gh_token=gh_token)
        if upload_to_pypi:
            pypi_upload(artifacts)
    else:
        print()
        utils.print_title("Artifacts")
        for artifact in artifacts:
            print(artifact)
def build_windows():
    """Build windows executables/setups."""
    parts = str(sys.version_info.major), str(sys.version_info.minor)
    ver = ''.join(parts)
    dotver = '.'.join(parts)
    python_x86 = r'C:\Python{}_x32'.format(ver)
    python_x64 = r'C:\Python{}'.format(ver)

    utils.print_title("Running 32bit freeze.py build_exe")
    call_freeze('build_exe', python=python_x86)
    utils.print_title("Running 32bit freeze.py bdist_msi")
    call_freeze('bdist_msi', python=python_x86)
    utils.print_title("Running 64bit freeze.py build_exe")
    call_freeze('build_exe', python=python_x64)
    utils.print_title("Running 64bit freeze.py bdist_msi")
    call_freeze('bdist_msi', python=python_x64)

    utils.print_title("Running 32bit smoke test")
    smoke_test('build/exe.win32-{}/qutebrowser.exe'.format(dotver))
    utils.print_title("Running 64bit smoke test")
    smoke_test('build/exe.win-amd64-{}/qutebrowser.exe'.format(dotver))

    destdir = os.path.join('dist', 'zip')
    _maybe_remove(destdir)
    os.makedirs(destdir)

    basedirname = 'qutebrowser-{}'.format(qutebrowser.__version__)
    builddir = os.path.join('build', basedirname)
    _maybe_remove(builddir)

    utils.print_title("Zipping 32bit standalone...")
    name = 'qutebrowser-{}-windows-standalone-win32'.format(
        qutebrowser.__version__)
    origin = os.path.join('build', 'exe.win32-{}'.format(dotver))
    os.rename(origin, builddir)
    shutil.make_archive(os.path.join(destdir, name), 'zip', 'build',
                        basedirname)
    shutil.rmtree(builddir)

    utils.print_title("Zipping 64bit standalone...")
    name = 'qutebrowser-{}-windows-standalone-amd64'.format(
        qutebrowser.__version__)
    origin = os.path.join('build', 'exe.win-amd64-{}'.format(dotver))
    os.rename(origin, builddir)
    shutil.make_archive(os.path.join(destdir, name), 'zip', 'build',
                        basedirname)
    shutil.rmtree(builddir)

    utils.print_title("Creating final zip...")
    shutil.move(os.path.join('dist', 'qutebrowser-{}-amd64.msi'.format(
        qutebrowser.__version__)), os.path.join('dist', 'zip'))
    shutil.move(os.path.join('dist', 'qutebrowser-{}-win32.msi'.format(
        qutebrowser.__version__)), os.path.join('dist', 'zip'))
    shutil.make_archive('qutebrowser-{}-windows'.format(
        qutebrowser.__version__), 'zip', destdir)
Example #36
0
def install_requirements(venv_dir: pathlib.Path) -> None:
    """Install qutebrowser's requirement.txt."""
    utils.print_title("Installing other qutebrowser dependencies")
    requirements_file = REPO_ROOT / 'requirements.txt'
    pip_install(venv_dir, '-r', str(requirements_file))
Example #37
0
def twine_check(artifacts):
    """Check packages using 'twine check'."""
    utils.print_title("Running twine check...")
    run_twine('check', artifacts, '--strict')
Example #38
0
def build_osx():
    """Build OS X .dmg/.app."""
    utils.print_title("Updating 3rdparty content")
    # update_3rdparty.run(ace=False, pdfjs=True, fancy_dmg=False)
    utils.print_title("Building .app via pyinstaller")
    call_tox('pyinstaller', '-r')
    utils.print_title("Patching .app")
    patch_osx_app()
    utils.print_title("Building .dmg")
    subprocess.check_call(['make', '-f', 'scripts/dev/Makefile-dmg'])
    utils.print_title("Cleaning up...")
    for f in ['wc.dmg', 'template.dmg']:
        os.remove(f)
    for d in ['dist', 'build']:
        shutil.rmtree(d)

    dmg_name = 'qutebrowser-{}.dmg'.format(qutebrowser.__version__)
    os.rename('qutebrowser.dmg', dmg_name)

    utils.print_title("Running smoke test")
    with tempfile.TemporaryDirectory() as tmpdir:
        subprocess.check_call(
            ['hdiutil', 'attach', dmg_name, '-mountpoint', tmpdir])
        try:
            binary = os.path.join(tmpdir, 'qutebrowser.app', 'Contents',
                                  'MacOS', 'qutebrowser')
            smoke_test(binary)
        finally:
            subprocess.check_call(['hdiutil', 'detach', tmpdir])

    return [(dmg_name, 'application/x-apple-diskimage', 'OS X .dmg')]
Example #39
0
def build_mac():
    """Build macOS .dmg/.app."""
    utils.print_title("Cleaning up...")
    for f in ['wc.dmg', 'template.dmg']:
        try:
            os.remove(f)
        except FileNotFoundError:
            pass
    for d in ['dist', 'build']:
        shutil.rmtree(d, ignore_errors=True)
    utils.print_title("Updating 3rdparty content")
    update_3rdparty.run(ace=False, pdfjs=True, fancy_dmg=False)
    utils.print_title("Building .app via pyinstaller")
    call_tox('pyinstaller', '-r')
    utils.print_title("Patching .app")
    patch_mac_app()
    utils.print_title("Building .dmg")
    subprocess.run(['make', '-f', 'scripts/dev/Makefile-dmg'], check=True)

    dmg_name = 'qutebrowser-{}.dmg'.format(qutebrowser.__version__)
    os.rename('qutebrowser.dmg', dmg_name)

    utils.print_title("Running smoke test")

    try:
        with tempfile.TemporaryDirectory() as tmpdir:
            subprocess.run(['hdiutil', 'attach', dmg_name,
                            '-mountpoint', tmpdir], check=True)
            try:
                binary = os.path.join(tmpdir, 'qutebrowser.app', 'Contents',
                                      'MacOS', 'qutebrowser')
                smoke_test(binary)
            finally:
                time.sleep(5)
                subprocess.run(['hdiutil', 'detach', tmpdir])
    except PermissionError as e:
        print("Failed to remove tempdir: {}".format(e))

    return [(dmg_name, 'application/x-apple-diskimage', 'macOS .dmg')]
Example #40
0
def install_pyqt_link(venv_dir: pathlib.Path) -> None:
    """Install PyQt by linking a system-wide install."""
    utils.print_title("Linking system-wide PyQt")
    lib_path = link_pyqt.get_venv_lib_path(str(venv_dir))
    link_pyqt.link_pyqt(sys.executable, lib_path)
Example #41
0
def install_pyqt_source(venv_dir: pathlib.Path, version: str) -> None:
    """Install PyQt from the source tarball."""
    utils.print_title("Installing PyQt from sources")
    pip_install(venv_dir, '-r', pyqt_requirements_file(version), '--verbose',
                '--no-binary', 'PyQt5,PyQtWebEngine')
def build_windows():
    """Build windows executables/setups."""
    utils.print_title("Updating 3rdparty content")
    # Currently disabled because QtWebEngine has no pdfjs support
    # update_3rdparty.run(ace=False, pdfjs=True, fancy_dmg=False)

    utils.print_title("Building Windows binaries")
    parts = str(sys.version_info.major), str(sys.version_info.minor)
    ver = ''.join(parts)
    python_x86 = r'C:\Python{}-32\python.exe'.format(ver)
    python_x64 = r'C:\Python{}\python.exe'.format(ver)
    out_pyinstaller = os.path.join('dist', 'qutebrowser')
    out_32 = os.path.join('dist',
                          'qutebrowser-{}-x86'.format(qutebrowser.__version__))
    out_64 = os.path.join('dist',
                          'qutebrowser-{}-x64'.format(qutebrowser.__version__))

    artifacts = []

    utils.print_title("Running pyinstaller 32bit")
    _maybe_remove(out_32)
    call_tox('pyinstaller', '-r', python=python_x86)
    shutil.move(out_pyinstaller, out_32)
    patch_windows(out_32)

    utils.print_title("Running pyinstaller 64bit")
    _maybe_remove(out_64)
    call_tox('pyinstaller', '-r', python=python_x64)
    shutil.move(out_pyinstaller, out_64)
    patch_windows(out_64)

    utils.print_title("Building installers")
    subprocess.check_call(['makensis.exe',
                           '/DVERSION={}'.format(qutebrowser.__version__),
                           'misc/qutebrowser.nsi'])
    subprocess.check_call(['makensis.exe',
                           '/DX64',
                           '/DVERSION={}'.format(qutebrowser.__version__),
                           'misc/qutebrowser.nsi'])

    name_32 = 'qutebrowser-{}-win32.exe'.format(qutebrowser.__version__)
    name_64 = 'qutebrowser-{}-amd64.exe'.format(qutebrowser.__version__)

    artifacts += [
        (os.path.join('dist', name_32),
         'application/vnd.microsoft.portable-executable',
         'Windows 32bit installer'),
        (os.path.join('dist', name_64),
         'application/vnd.microsoft.portable-executable',
         'Windows 64bit installer'),
    ]

    utils.print_title("Running 32bit smoke test")
    smoke_test(os.path.join(out_32, 'qutebrowser.exe'))
    utils.print_title("Running 64bit smoke test")
    smoke_test(os.path.join(out_64, 'qutebrowser.exe'))

    utils.print_title("Zipping 32bit standalone...")
    name = 'qutebrowser-{}-windows-standalone-win32'.format(
        qutebrowser.__version__)
    shutil.make_archive(name, 'zip', 'dist', os.path.basename(out_32))
    artifacts.append(('{}.zip'.format(name),
                      'application/zip',
                      'Windows 32bit standalone'))

    utils.print_title("Zipping 64bit standalone...")
    name = 'qutebrowser-{}-windows-standalone-amd64'.format(
        qutebrowser.__version__)
    shutil.make_archive(name, 'zip', 'dist', os.path.basename(out_64))
    artifacts.append(('{}.zip'.format(name),
                      'application/zip',
                      'Windows 64bit standalone'))

    return artifacts
Example #43
0
def install_pyqt_wheels(venv_dir: pathlib.Path,
                        wheels_dir: pathlib.Path) -> None:
    """Install PyQt from the wheels/ directory."""
    utils.print_title("Installing PyQt wheels")
    wheels = [str(wheel) for wheel in wheels_dir.glob('*.whl')]
    pip_install(venv_dir, *wheels)
Example #44
0
def build_mac(*, gh_token, debug):
    """Build macOS .dmg/.app."""
    utils.print_title("Cleaning up...")
    for f in ['wc.dmg', 'template.dmg']:
        try:
            os.remove(f)
        except FileNotFoundError:
            pass
    for d in ['dist', 'build']:
        shutil.rmtree(d, ignore_errors=True)
    utils.print_title("Updating 3rdparty content")
    update_3rdparty.run(ace=False, pdfjs=True, fancy_dmg=False, gh_token=gh_token)
    utils.print_title("Building .app via pyinstaller")
    # call_tox('pyinstaller-64', '-r', debug=debug)
    env = os.environ.copy()
    subprocess.run(
        "pyinstaller --noconfirm misc/qutebrowser.spec".split(" "),
        env=env, check=True)
    utils.print_title("Patching .app")
    patch_mac_app()
    utils.print_title("Building .dmg")
    subprocess.run(['make', '-f', 'scripts/dev/Makefile-dmg'], check=True)

    suffix = "-debug" if debug else ""
    dmg_path = f'dist/qutebrowser-{qutebrowser.__version__}{suffix}.dmg'
    os.rename('qutebrowser.dmg', dmg_path)

    utils.print_title("Running smoke test")

    try:
        with tempfile.TemporaryDirectory() as tmpdir:
            subprocess.run(['hdiutil', 'attach', dmg_path,
                            '-mountpoint', tmpdir], check=True)
            try:
                binary = os.path.join(tmpdir, 'qutebrowser.app', 'Contents',
                                      'MacOS', 'qutebrowser')
                smoke_test(binary, debug=debug)
            finally:
                print("Waiting 10s for dmg to be detachable...")
                time.sleep(10)
                subprocess.run(['hdiutil', 'detach', tmpdir], check=False)
    except PermissionError as e:
        print("Failed to remove tempdir: {}".format(e))

    return [(dmg_path, 'application/x-apple-diskimage', 'macOS .dmg')]
Example #45
0
def build_windows():
    """Build windows executables/setups."""
    utils.print_title("Updating 3rdparty content")
    update_3rdparty.update_pdfjs()

    utils.print_title("Building Windows binaries")
    parts = str(sys.version_info.major), str(sys.version_info.minor)
    ver = ''.join(parts)
    dotver = '.'.join(parts)
    python_x86 = r'C:\Python{}_x32'.format(ver)
    python_x64 = r'C:\Python{}'.format(ver)

    artifacts = []

    utils.print_title("Rebuilding tox environment")
    call_tox('cxfreeze-windows', '-r', '--notest')
    utils.print_title("Running 32bit freeze.py build_exe")
    call_tox('cxfreeze-windows', 'build_exe', python=python_x86)
    utils.print_title("Running 32bit freeze.py bdist_msi")
    call_tox('cxfreeze-windows', 'bdist_msi', python=python_x86)
    utils.print_title("Running 64bit freeze.py build_exe")
    call_tox('cxfreeze-windows', 'build_exe', python=python_x64)
    utils.print_title("Running 64bit freeze.py bdist_msi")
    call_tox('cxfreeze-windows', 'bdist_msi', python=python_x64)

    name_32 = 'qutebrowser-{}-win32.msi'.format(qutebrowser.__version__)
    name_64 = 'qutebrowser-{}-amd64.msi'.format(qutebrowser.__version__)

    artifacts += [
        (os.path.join('dist', name_32), 'application/x-msi',
         'Windows 32bit installer'),
        (os.path.join('dist', name_64), 'application/x-msi',
         'Windows 64bit installer'),
    ]

    utils.print_title("Running 32bit smoke test")
    smoke_test('build/exe.win32-{}/qutebrowser.exe'.format(dotver))
    utils.print_title("Running 64bit smoke test")
    smoke_test('build/exe.win-amd64-{}/qutebrowser.exe'.format(dotver))

    basedirname = 'qutebrowser-{}'.format(qutebrowser.__version__)
    builddir = os.path.join('build', basedirname)
    _maybe_remove(builddir)

    utils.print_title("Zipping 32bit standalone...")
    name = 'qutebrowser-{}-windows-standalone-win32'.format(
        qutebrowser.__version__)
    origin = os.path.join('build', 'exe.win32-{}'.format(dotver))
    os.rename(origin, builddir)
    shutil.make_archive(name, 'zip', 'build', basedirname)
    shutil.rmtree(builddir)
    artifacts.append(('{}.zip'.format(name),
                      'application/zip',
                      'Windows 32bit standalone'))

    utils.print_title("Zipping 64bit standalone...")
    name = 'qutebrowser-{}-windows-standalone-amd64'.format(
        qutebrowser.__version__)
    origin = os.path.join('build', 'exe.win-amd64-{}'.format(dotver))
    os.rename(origin, builddir)
    shutil.make_archive(name, 'zip', 'build', basedirname)
    shutil.rmtree(builddir)
    artifacts.append(('{}.zip'.format(name),
                      'application/zip',
                      'Windows 64bit standalone'))

    return artifacts
Example #46
0
def install_dev_requirements(venv_dir: pathlib.Path) -> None:
    """Install development dependencies."""
    utils.print_title("Installing dev dependencies")
    pip_install(venv_dir, '-r', str(requirements_file('dev')), '-r',
                requirements_file('tests'))