Пример #1
0
def freeze(debug=False):
    """
    Compile your application to a standalone executable
    """
    # Import respective functions late to avoid circular import
    # fbs <-> fbs.freeze.X.
    app_name = SETTINGS['app_name']
    if is_mac():
        from fbs.freeze.mac import freeze_mac
        freeze_mac(debug=debug)
        executable = 'target/%s.app/Contents/MacOS/%s' % (app_name, app_name)
    else:
        executable = join('target', app_name, app_name)
        if is_windows():
            from fbs.freeze.windows import freeze_windows
            freeze_windows(debug=debug)
            executable += '.exe'
        elif is_linux():
            if is_ubuntu():
                from fbs.freeze.ubuntu import freeze_ubuntu
                freeze_ubuntu(debug=debug)
            elif is_arch_linux():
                from fbs.freeze.arch import freeze_arch
                freeze_arch(debug=debug)
            elif is_fedora():
                from fbs.freeze.fedora import freeze_fedora
                freeze_fedora(debug=debug)
            else:
                from fbs.freeze.linux import freeze_linux
                freeze_linux(debug=debug)
        else:
            raise RuntimeError('Unsupported OS')
    _LOG.info(
        "Done. You can now run `%s`. If that doesn't work, see "
        "https://build-system.fman.io/troubleshooting.", executable)
Пример #2
0
def release():
    """
    Bump version and run clean,freeze,...,upload
    """
    require_existing_project()
    version = SETTINGS['version']
    next_version = _get_next_version(version)
    release_version = prompt_for_value('Release version', default=next_version)
    activate_profile('release')
    SETTINGS['version'] = release_version
    log_level = _LOG.level
    if log_level == logging.NOTSET:
        _LOG.setLevel(logging.WARNING)
    try:
        clean()
        freeze()
        if is_windows() and _has_windows_codesigning_certificate():
            sign()
        installer()
        if (is_windows() and _has_windows_codesigning_certificate()) or \
            is_arch_linux() or is_fedora():
            sign_installer()
        repo()
    finally:
        _LOG.setLevel(log_level)
    upload()
    base_json = 'src/build/settings/base.json'
    update_json(path(base_json), {'version': release_version})
    _LOG.info('Also, %s was updated with the new version.', base_json)
Пример #3
0
def freeze(debug=False):
    """
    Compile your application to a standalone executable
    """
    # Import respective functions late to avoid circular import
    # fbs <-> fbs.freeze.X:
    if is_windows():
        from fbs.freeze.windows import freeze_windows
        freeze_windows(debug=debug)
    elif is_mac():
        from fbs.freeze.mac import freeze_mac
        freeze_mac(debug=debug)
    elif is_linux():
        if is_ubuntu():
            from fbs.freeze.ubuntu import freeze_ubuntu
            freeze_ubuntu(debug=debug)
        elif is_arch_linux():
            from fbs.freeze.arch import freeze_arch
            freeze_arch(debug=debug)
        elif is_fedora():
            from fbs.freeze.fedora import freeze_fedora
            freeze_fedora(debug=debug)
        else:
            from fbs.freeze.linux import freeze_linux
            freeze_linux(debug=debug)
    else:
        raise RuntimeError('Unsupported OS')
Пример #4
0
def run_fpm(output_type):
    dest = path('target/${installer}')
    if exists(dest):
        remove(dest)
    # Lower-case the name to avoid the following fpm warning:
    #  > Debian tools (dpkg/apt) don't do well with packages that use capital
    #  > letters in the name. In some cases it will automatically downcase
    #  > them, in others it will not. It is confusing. Best to not use any
    #  > capital letters at all.
    name = SETTINGS['app_name'].lower()
    args = [
        'fpm',
        '-s',
        'dir',
        # We set the log level to error because fpm prints the following warning
        # even if we don't have anything in /etc:
        #  > Debian packaging tools generally labels all files in /etc as config
        #  > files, as mandated by policy, so fpm defaults to this behavior for
        #  > deb packages. You can disable this default behavior with
        #  > --deb-no-default-config-files flag
        '--log',
        'error',
        '-C',
        path('target/installer'),
        '-n',
        name,
        '-v',
        SETTINGS['version'],
        '--vendor',
        SETTINGS['author'],
        '-t',
        output_type,
        '-p',
        dest
    ]
    if SETTINGS['description']:
        args.extend(['--description', SETTINGS['description']])
    if SETTINGS['author_email']:
        args.extend(
            ['-m',
             '%s <%s>' % (SETTINGS['author'], SETTINGS['author_email'])])
    if SETTINGS['url']:
        args.extend(['--url', SETTINGS['url']])
    for dependency in SETTINGS['depends']:
        args.extend(['-d', dependency])
    if is_arch_linux():
        for opt_dependency in SETTINGS['depends_opt']:
            args.extend(['--pacman-optional-depends', opt_dependency])
    try:
        run(args, check=True, stdout=DEVNULL)
    except FileNotFoundError:
        raise FileNotFoundError(
            "fbs could not find executable 'fpm'. Please install fpm using the "
            "instructions at "
            "https://fpm.readthedocs.io/en/latest/installing.html.") from None
Пример #5
0
def installer():
    """
    Create an installer for your app
    """
    require_existing_project()
    if not exists(path('${freeze_dir}')):
        raise FbsError(
            'It seems your app has not yet been frozen. Please run:\n'
            '    fbs freeze')
    linux_distribution_not_supported_msg = \
        "Your Linux distribution is not supported, sorry. " \
        "You can run `fbs buildvm` followed by `fbs runvm` to start a Docker " \
        "VM of a supported distribution."
    try:
        installer_fname = SETTINGS['installer']
    except KeyError:
        if is_linux():
            raise FbsError(linux_distribution_not_supported_msg)
        raise
    out_file = join('target', installer_fname)
    msg_parts = ['Created %s.' % out_file]
    if is_windows():
        from fbs.installer.windows import create_installer_windows
        create_installer_windows()
    elif is_mac():
        from fbs.installer.mac import create_installer_mac
        create_installer_mac()
    elif is_linux():
        app_name = SETTINGS['app_name']
        if is_ubuntu():
            from fbs.installer.ubuntu import create_installer_ubuntu
            create_installer_ubuntu()
            install_cmd = 'sudo dpkg -i ' + out_file
            remove_cmd = 'sudo dpkg --purge ' + app_name
        elif is_arch_linux():
            from fbs.installer.arch import create_installer_arch
            create_installer_arch()
            install_cmd = 'sudo pacman -U ' + out_file
            remove_cmd = 'sudo pacman -R ' + app_name
        elif is_fedora():
            from fbs.installer.fedora import create_installer_fedora
            create_installer_fedora()
            install_cmd = 'sudo dnf install ' + out_file
            remove_cmd = 'sudo dnf remove ' + app_name
        else:
            raise FbsError(linux_distribution_not_supported_msg)
        msg_parts.append(
            'You can for instance install it via the following command:\n'
            '    %s\n'
            'This places it in /opt/%s. To uninstall it again, you can use:\n'
            '    %s' % (install_cmd, app_name, remove_cmd))
    else:
        raise FbsError('Unsupported OS')
    _LOG.info(' '.join(msg_parts))
Пример #6
0
def sign_installer():
    """
    Sign installer, so the user's OS trusts it
    """
    require_existing_project()
    if is_arch_linux():
        from fbs.sign_installer.arch import sign_installer_arch
        sign_installer_arch()
    elif is_fedora():
        from fbs.sign_installer.fedora import sign_installer_fedora
        sign_installer_fedora()
    else:
        _LOG.info('This command is not (yet) supported on this platform.')
Пример #7
0
def init(project_dir):
    """
    Call this if you are not invoking `python -m fbs` or fbs.cmdline.main().
    """
    SETTINGS['project_dir'] = abspath(project_dir)
    activate_profile('base')
    activate_profile(platform.name().lower())
    if is_linux():
        if is_ubuntu():
            activate_profile('ubuntu')
        elif is_arch_linux():
            activate_profile('arch')
        elif is_fedora():
            activate_profile('fedora')
Пример #8
0
def get_default_profiles():
    result = ['base']
    # The "secret" profile lets the user store sensitive settings such as
    # passwords in src/build/settings/secret.json. When using Git, the user can
    # exploit this by adding secret.json to .gitignore, thus preventing it from
    # being uploaded to services such as GitHub.
    result.append('secret')
    result.append(platform.name().lower())
    if is_linux():
        if is_ubuntu():
            result.append('ubuntu')
        elif is_arch_linux():
            result.append('arch')
        elif is_fedora():
            result.append('fedora')
    return result
Пример #9
0
def freeze(debug=False):
    """
    Compile your code to a standalone executable
    """
    require_existing_project()
    if not _has_module('PyInstaller'):
        raise FbsError("Could not find PyInstaller. Maybe you need to:\n"
                       "    pip install PyInstaller==3.4")
    version = SETTINGS['version']
    if not is_valid_version(version):
        raise FbsError(
            'Invalid version detected in settings. It should be three\n'
            'numbers separated by dots, such as "1.2.3". You have:\n\t"%s".\n'
            'Usually, this can be fixed in src/build/settings/base.json.' %
            version)
    # Import respective functions late to avoid circular import
    # fbs <-> fbs.freeze.X.
    app_name = SETTINGS['app_name']
    if is_mac():
        from fbs.freeze.mac import freeze_mac
        freeze_mac(debug=debug)
        executable = 'target/%s.app/Contents/MacOS/%s' % (app_name, app_name)
    else:
        executable = join('target', app_name, app_name)
        if is_windows():
            from fbs.freeze.windows import freeze_windows
            freeze_windows(debug=debug)
            executable += '.exe'
        elif is_linux():
            if is_ubuntu():
                from fbs.freeze.ubuntu import freeze_ubuntu
                freeze_ubuntu(debug=debug)
            elif is_arch_linux():
                from fbs.freeze.arch import freeze_arch
                freeze_arch(debug=debug)
            elif is_fedora():
                from fbs.freeze.fedora import freeze_fedora
                freeze_fedora(debug=debug)
            else:
                from fbs.freeze.linux import freeze_linux
                freeze_linux(debug=debug)
        else:
            raise FbsError('Unsupported OS')
    _LOG.info(
        "Done. You can now run `%s`. If that doesn't work, see "
        "https://build-system.fman.io/troubleshooting.", executable)
Пример #10
0
def release(version=None):
    """
    Bump version and run clean,freeze,...,upload
    """
    require_existing_project()
    if version is None:
        curr_version = SETTINGS['version']
        next_version = _get_next_version(curr_version)
        release_version = prompt_for_value('Release version',
                                           default=next_version)
    elif version == 'current':
        release_version = SETTINGS['version']
    else:
        release_version = version
    if not is_valid_version(release_version):
        if not is_valid_version(version):
            raise FbsError(
                'The release version of your app is invalid. It should be '
                'three\nnumbers separated by dots, such as "1.2.3". '
                'You have: "%s".' % release_version)
    activate_profile('release')
    SETTINGS['version'] = release_version
    log_level = _LOG.level
    if log_level == logging.NOTSET:
        _LOG.setLevel(logging.WARNING)
    try:
        clean()
        freeze()
        if is_windows() and _has_windows_codesigning_certificate():
            sign()
        installer()
        if (is_windows() and _has_windows_codesigning_certificate()) or \
            is_arch_linux() or is_fedora():
            sign_installer()
        if _repo_is_supported():
            repo()
    finally:
        _LOG.setLevel(log_level)
    upload()
    base_json = 'src/build/settings/base.json'
    update_json(path(base_json), {'version': release_version})
    _LOG.info('Also, %s was updated with the new version.', base_json)
Пример #11
0
def freeze(debug=False):
    """
    Compile your code to a standalone executable
    """
    require_existing_project()
    if not _has_module('PyInstaller'):
        raise FbsError(
            "Could not find PyInstaller. Maybe you need to:\n"
            "    pip install PyInstaller==3.4"
        )
    # Import respective functions late to avoid circular import
    # fbs <-> fbs.freeze.X.
    app_name = SETTINGS['app_name']
    if is_mac():
        from fbs.freeze.mac import freeze_mac
        freeze_mac(debug=debug)
        executable = 'target/%s.app/Contents/MacOS/%s' % (app_name, app_name)
    else:
        executable = join('target', app_name, app_name)
        if is_windows():
            from fbs.freeze.windows import freeze_windows
            freeze_windows(debug=debug)
            executable += '.exe'
        elif is_linux():
            if is_ubuntu():
                from fbs.freeze.ubuntu import freeze_ubuntu
                freeze_ubuntu(debug=debug)
            elif is_arch_linux():
                from fbs.freeze.arch import freeze_arch
                freeze_arch(debug=debug)
            elif is_fedora():
                from fbs.freeze.fedora import freeze_fedora
                freeze_fedora(debug=debug)
            else:
                from fbs.freeze.linux import freeze_linux
                freeze_linux(debug=debug)
        else:
            raise FbsError('Unsupported OS')
    _LOG.info(
        "Done. You can now run `%s`. If that doesn't work, see "
        "https://build-system.fman.io/troubleshooting.", executable
    )
Пример #12
0
def sign_installer():
    """
    Sign installer, so the user's OS trusts it
    """
    if is_mac():
        _LOG.info('fbs does not yet implement `sign_installer` on macOS.')
        return
    if is_ubuntu():
        _LOG.info('Ubuntu does not support signing installers.')
        return
    require_installer()
    if is_windows():
        from fbs.sign_installer.windows import sign_installer_windows
        sign_installer_windows()
    elif is_arch_linux():
        from fbs.sign_installer.arch import sign_installer_arch
        sign_installer_arch()
    elif is_fedora():
        from fbs.sign_installer.fedora import sign_installer_fedora
        sign_installer_fedora()
    _LOG.info('Signed %s.', join('target', SETTINGS['installer']))
Пример #13
0
def installer():
    """
    Create an installer for your app
    """
    require_existing_project()
    out_file = join('target', SETTINGS['installer'])
    msg_parts = ['Created %s.' % out_file]
    if is_windows():
        from fbs.installer.windows import create_installer_windows
        create_installer_windows()
    elif is_mac():
        from fbs.installer.mac import create_installer_mac
        create_installer_mac()
    elif is_linux():
        app_name = SETTINGS['app_name']
        if is_ubuntu():
            from fbs.installer.ubuntu import create_installer_ubuntu
            create_installer_ubuntu()
            install_cmd = 'sudo dpkg -i ' + out_file
            remove_cmd = 'sudo dpkg --purge ' + app_name
        elif is_arch_linux():
            from fbs.installer.arch import create_installer_arch
            create_installer_arch()
            install_cmd = 'sudo pacman -U ' + out_file
            remove_cmd = 'sudo pacman -R ' + app_name
        elif is_fedora():
            from fbs.installer.fedora import create_installer_fedora
            create_installer_fedora()
            install_cmd = 'sudo dnf install ' + out_file
            remove_cmd = 'sudo dnf remove ' + app_name
        else:
            raise FbsError('Unsupported Linux distribution')
        msg_parts.append(
            'You can for instance install it via the following command:\n'
            '    %s\n'
            'This places it in /opt/%s. To uninstall it again, you can use:\n'
            '    %s' % (install_cmd, app_name, remove_cmd))
    else:
        raise FbsError('Unsupported OS')
    _LOG.info(' '.join(msg_parts))
Пример #14
0
def installer():
    """
    Create an installer for your app
    """
    if is_windows():
        from fbs.installer.windows import create_installer_windows
        create_installer_windows()
    elif is_mac():
        from fbs.installer.mac import create_installer_mac
        create_installer_mac()
    elif is_linux():
        if is_ubuntu():
            from fbs.installer.ubuntu import create_installer_ubuntu
            create_installer_ubuntu()
        elif is_arch_linux():
            from fbs.installer.arch import create_installer_arch
            create_installer_arch()
        elif is_fedora():
            from fbs.installer.fedora import create_installer_fedora
            create_installer_fedora()
        else:
            raise RuntimeError('Unsupported Linux distribution')
    else:
        raise RuntimeError('Unsupported OS')
Пример #15
0
def upload():
    """
    Upload installer and repository to fbs.sh
    """
    require_existing_project()
    try:
        username = SETTINGS['fbs_user']
        password = SETTINGS['fbs_pass']
    except KeyError as e:
        raise FbsError(
            'Could not find setting "%s". You may want to invoke one of the '
            'following:\n'
            ' * fbs register\n'
            ' * fbs login'
            % (e.args[0],)
        ) from None
    _upload_repo(username, password)
    app_name = SETTINGS['app_name']
    url = lambda p: 'https://fbs.sh/%s/%s/%s' % (username, app_name, p)
    message = 'Done! '
    pkg_name = app_name.lower()
    installer_url = url(SETTINGS['installer'])
    if is_linux():
        message += 'Your users can now install your app via the following ' \
                   'commands:\n'
        format_commands = lambda *cmds: '\n'.join('    ' + c for c in cmds)
        repo_url = url(SETTINGS['repo_subdir'])
        if is_ubuntu():
            message += format_commands(
                "sudo apt-get install apt-transport-https",
                "wget -qO - %s | sudo apt-key add -" % url('public-key.gpg'),
                "echo 'deb [arch=amd64] %s stable main' | " % repo_url +
                "sudo tee /etc/apt/sources.list.d/%s.list" % pkg_name,
                "sudo apt-get update",
                "sudo apt-get install " + pkg_name
            )
            message += '\nIf they already have your app installed, they can ' \
                       'force an immediate update via:\n'
            message += format_commands(
                'sudo apt-get update '
                '-o Dir::Etc::sourcelist="/etc/apt/sources.list.d/%s.list" '
                '-o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0"'
                % pkg_name,
                'sudo apt-get install --only-upgrade ' + pkg_name
            )
        elif is_arch_linux():
            message += format_commands(
                "curl -O %s && " % url('public-key.gpg') +
                "sudo pacman-key --add public-key.gpg && " +
                "sudo pacman-key --lsign-key %s && " % SETTINGS['gpg_key'] +
                "rm public-key.gpg",
                "echo -e '\\n[%s]\\nServer = %s' | sudo tee -a /etc/pacman.conf"
                % (app_name, repo_url),
                "sudo pacman -Syu " + pkg_name
            )
            message += '\nIf they already have your app installed, they can ' \
                       'force an immediate update via:\n'
            message += format_commands('sudo pacman -Syu --needed ' + pkg_name)
        elif is_fedora():
            message += format_commands(
                "sudo rpm -v --import " + url('public-key.gpg'),
                "sudo dnf config-manager --add-repo %s/%s.repo"
                % (repo_url, app_name),
                "sudo dnf install " + pkg_name
            )
            message += "\n(On CentOS, replace 'dnf' by 'yum' and " \
                       "'dnf config-manager' by 'yum-config-manager'.)"
            message += '\nIf they already have your app installed, they can ' \
                       'force an immediate update via:\n'
            message += \
                format_commands('sudo dnf upgrade %s --refresh' % pkg_name)
            message += '\nThis is for Fedora. For CentOS, use:\n'
            message += format_commands(
                'sudo yum clean all && sudo yum upgrade ' + pkg_name
            )
        else:
            raise FbsError('This Linux distribution is not supported.')
        message += '\nFinally, your users can also install without automatic ' \
                   'updates by downloading:\n    ' + installer_url
        extra = {'wrap': False}
    else:
        message += 'Your users can now download and install %s.' % installer_url
        extra = None
    _LOG.info(message, extra=extra)
Пример #16
0
def _repo_is_supported():
    return is_ubuntu() or is_arch_linux() or is_fedora()
Пример #17
0
def repo():
    """
    Generate files for automatic updates
    """
    require_existing_project()
    if not _repo_is_supported():
        raise FbsError('This command is not supported on this platform.')
    app_name = SETTINGS['app_name']
    pkg_name = app_name.lower()
    try:
        gpg_key = SETTINGS['gpg_key']
    except KeyError:
        raise FbsError(
            'GPG key for code signing is not configured. You might want to '
            'either\n'
            '    1) run `fbs gengpgkey` or\n'
            '    2) set "gpg_key" and "gpg_pass" in src/build/settings/.'
        )
    if is_ubuntu():
        from fbs.repo.ubuntu import create_repo_ubuntu
        if not SETTINGS['description']:
            _LOG.info(
                'Hint: Your app\'s "description" is empty. Consider setting it '
                'in src/build/settings/linux.json.'
            )
        create_repo_ubuntu()
        _LOG.info(
            'Done. You can test the repository with the following commands:\n'
            '    echo "deb [arch=amd64] file://%s stable main" '
                '| sudo tee /etc/apt/sources.list.d/%s.list\n'
            '    sudo apt-key add %s\n'
            '    sudo apt-get update\n'
            '    sudo apt-get install %s\n'
            'To revert these changes:\n'
            '    sudo dpkg --purge %s\n'
            '    sudo apt-key del %s\n'
            '    sudo rm /etc/apt/sources.list.d/%s.list\n'
            '    sudo apt-get update',
            path('target/repo'), pkg_name,
            path('src/sign/linux/public-key.gpg'), pkg_name, pkg_name, gpg_key,
            pkg_name,
            extra={'wrap': False}
        )
    elif is_arch_linux():
        from fbs.repo.arch import create_repo_arch
        create_repo_arch()
        _LOG.info(
            "Done. You can test the repository with the following commands:\n"
            "    sudo cp /etc/pacman.conf /etc/pacman.conf.bu\n"
            "    echo -e '\\n[%s]\\nServer = file://%s' "
                "| sudo tee -a /etc/pacman.conf\n"
            "    sudo pacman-key --add %s\n"
            "    sudo pacman-key --lsign-key %s\n"
            "    sudo pacman -Syu %s\n"
            "To revert these changes:\n"
            "    sudo pacman -R %s\n"
            "    sudo pacman-key --delete %s\n"
            "    sudo mv /etc/pacman.conf.bu /etc/pacman.conf",
            app_name, path('target/repo'),
            path('src/sign/linux/public-key.gpg'), gpg_key, pkg_name, pkg_name,
            gpg_key,
            extra={'wrap': False}
        )
    else:
        assert is_fedora()
        from fbs.repo.fedora import create_repo_fedora
        create_repo_fedora()
        _LOG.info(
            "Done. You can test the repository with the following commands:\n"
            "    sudo rpm -v --import %s\n"
            "    sudo dnf config-manager --add-repo file://%s/target/repo\n"
            "    sudo dnf install %s\n"
            "To revert these changes:\n"
            "    sudo dnf remove %s\n"
            "    sudo rm /etc/yum.repos.d/*%s*.repo\n"
            "    sudo rpm --erase gpg-pubkey-%s",
            path('src/sign/linux/public-key.gpg'), SETTINGS['project_dir'],
            pkg_name, pkg_name, app_name, gpg_key[-8:].lower(),
            extra={'wrap': False}
        )