Exemplo n.º 1
0
def buildvm(name):
    """
    Build a virtual machine. Eg.: buildvm ubuntu
    """
    build_dir = path('target/%s-docker-image' % name)
    if exists(build_dir):
        rmtree(build_dir)
    src_root = 'src/build/docker'
    available_vms = set(listdir(_defaults.path(src_root)))
    if exists(path(src_root)):
        available_vms.update(listdir(path(src_root)))
    if name not in available_vms:
        raise FbsError('Could not find %s. Available VMs are:%s' %
                       (name, ''.join(['\n * ' + vm for vm in available_vms])))
    src_dir = src_root + '/' + name
    for path_fn in _defaults.path, path:
        _copy(path_fn, src_dir, build_dir)
    settings = SETTINGS['docker_images'].get(name, {})
    for path_fn in _defaults.path, path:
        for p in settings.get('build_files', []):
            _copy(path_fn, p, build_dir)
    args = ['build', '--pull', '-t', _get_docker_id(name), build_dir]
    for arg, value in settings.get('build_args', {}).items():
        args.extend(['--build-arg', '%s=%s' % (arg, value)])
    try:
        _run_docker(args, check=True, stdout=PIPE, universal_newlines=True)
    except CalledProcessError as e:
        raise FbsError(e.stdout)
    _LOG.info('Done. You can now execute:\n    fbs runvm ' + name)
Exemplo n.º 2
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))
Exemplo n.º 3
0
def sign_windows():
    if not exists(path(_CERTIFICATE_PATH)):
        raise FbsError('Could not find a code signing certificate at:\n    ' +
                       _CERTIFICATE_PATH)
    if 'windows_sign_pass' not in SETTINGS:
        raise FbsError(
            "Please set 'windows_sign_pass' to the password of %s in either "
            "src/build/settings/secret.json, .../windows.json or .../base.json."
            % _CERTIFICATE_PATH)
    for subdir, _, files in os.walk(path('${freeze_dir}')):
        for file_ in files:
            extension = splitext(file_)[1]
            if extension in _TO_SIGN:
                sign_file(join(subdir, file_))
Exemplo n.º 4
0
def _get_cmdline_parser():
    # Were we invoked with `python -m fbs`?
    is_python_m_fbs = splitext(basename(sys.argv[0]))[0] == '__main__'
    if is_python_m_fbs:
        prog = '%s -m fbs' % basename(sys.executable)
    else:
        prog = None
    parser = ArgumentParser(prog=prog, description='fbs')
    subparsers = parser.add_subparsers()
    for cmd_name, cmd_fn in COMMANDS.items():
        cmd_parser = subparsers.add_parser(cmd_name, help=cmd_fn.__doc__)
        argspec = getfullargspec(cmd_fn)
        args = argspec.args or []
        defaults = argspec.defaults or ()
        args_without_defaults = args[:1 - len(defaults)]
        args_with_defaults = args[-len(defaults):]
        for arg in args_without_defaults:
            cmd_parser.add_argument(arg)
        for arg, default in zip(args_with_defaults, defaults):
            if not isinstance(default, bool):
                raise FbsError(
                    'Error in command %r: Only booleans are currently '
                    'supported as optional arguments.' % cmd_name)
            cmd_parser.add_argument('--' + arg,
                                    action='store_' + str(not default).lower())
        cmd_parser.set_defaults(fn=cmd_fn, args=args, defaults=defaults)
    return parser
Exemplo n.º 5
0
def require_existing_project():
    if not exists(path('src')):
        raise FbsError(
            "Could not find the src/ directory. Are you in the right folder?\n"
            "If yes, did you already run\n"
            "    fbs startproject ?"
        )
Exemplo n.º 6
0
def require_installer():
    installer = path('target/${installer}')
    if not exists(installer):
        raise FbsError(
            'Installer does not exist. Maybe you need to run:\n'
            '    fbs installer'
        )
Exemplo n.º 7
0
def _get_name():
    if sys.platform in ('win32', 'cygwin'):
        return 'Windows'
    if sys.platform == 'darwin':
        return 'Mac'
    if sys.platform.startswith('linux'):
        return 'Linux'
    raise FbsError('Unknown operating system.')
Exemplo n.º 8
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)
Exemplo n.º 9
0
def get_project_dir():
    result = Path(os.getcwd())
    while result != result.parent:
        if (result / 'src' / 'main' / 'python').is_dir():
            return str(result)
        result = result.parent
    raise FbsError(
        'Could not determine the project base directory. '
        'Was expecting src/main/python.'
    )
Exemplo n.º 10
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
    )
Exemplo n.º 11
0
def get_project_dir(appctxt_cls):
    class_file = inspect.getfile(appctxt_cls)
    p = PurePath(class_file)
    while p != p.parent:
        parent_names = [p.parents[2].name, p.parents[1].name, p.parent.name]
        if parent_names == ['src', 'main', 'python']:
            return str(p.parents[3])
        p = p.parent
    raise FbsError(
        'Could not determine project base directory for %s. Is it in '
        'src/main/python?' % appctxt_cls)
Exemplo n.º 12
0
def init(project_dir):
    """
    Call this if you are invoking neither `fbs` on the command line nor
    fbs.cmdline.main() from Python.
    """
    if sys.version_info[0] != 3 or sys.version_info[1] not in (5, 6):
        raise FbsError(
            'The free version of fbs only supports Python 3.5 and 3.6.\n'
            'Please obtain fbs Pro from https://build-system.fman.io/pro.')
    SETTINGS.update(get_core_settings(abspath(project_dir)))
    for profile in get_default_profiles():
        activate_profile(profile)
Exemplo n.º 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))
Exemplo n.º 14
0
def gengpgkey():
    """
    Generate a GPG key for code signing on Linux
    """
    require_existing_project()
    if exists(_DEST_DIR):
        raise FbsError('The %s folder already exists. Aborting.' % _DEST_DIR)
    try:
        email = prompt_for_value('Email address')
        name = prompt_for_value('Real name', default=SETTINGS['author'])
        passphrase = prompt_for_value('Key password', password=True)
    except KeyboardInterrupt:
        print('')
        return
    _LOG.info('Generating the GPG key. This can take a little...')
    _init_docker()
    args = ['run', '-t']
    if exists('/dev/urandom'):
        # Give the key generator more entropy on Posix:
        args.extend(['-v', '/dev/urandom:/dev/random'])
    args.extend([_DOCKER_IMAGE, '/root/genkey.sh', name, email, passphrase])
    result = _run_docker(args, check=True, stdout=PIPE, universal_newlines=True)
    key = _snip(
        result.stdout,
        "revocation certificate stored as '/root/.gnupg/openpgp-revocs.d/",
        ".rev'",
        include_bounds=False
    )
    pubkey = _snip(result.stdout,
                   '-----BEGIN PGP PUBLIC KEY BLOCK-----\n',
                   '-----END PGP PUBLIC KEY BLOCK-----\n')
    privkey = _snip(result.stdout,
                    '-----BEGIN PGP PRIVATE KEY BLOCK-----\n',
                    '-----END PGP PRIVATE KEY BLOCK-----\n')
    makedirs(path(_DEST_DIR), exist_ok=True)
    pubkey_dest = _DEST_DIR + '/' + _PUBKEY_NAME
    with open(path(pubkey_dest), 'w') as f:
        f.write(pubkey)
    privkey_dest = _DEST_DIR + '/' + _PRIVKEY_NAME
    with open(path(privkey_dest), 'w') as f:
        f.write(privkey)
    with open(path(_BASE_JSON)) as f:
        base_contents = f.read()
    new_base_contents = _extend_json(base_contents, {
        'gpg_key': key, 'gpg_name': name, 'gpg_pass': passphrase
    })
    with open(path(_BASE_JSON), 'w') as f:
        f.write(new_base_contents)
    _LOG.info(
        'Done. Created %s and ...%s. Also updated %s with the values you '
        'entered.', pubkey_dest, _PRIVKEY_NAME, _BASE_JSON
    )
Exemplo n.º 15
0
def buildvm(name):
    """
    Build a Linux VM. Eg.: buildvm ubuntu
    """
    require_existing_project()
    build_dir = path('target/%s-docker-image' % name)
    if exists(build_dir):
        rmtree(build_dir)
    src_root = 'src/build/docker'
    available_vms = set(listdir(default_path(src_root)))
    if exists(path(src_root)):
        available_vms.update(listdir(path(src_root)))
    if name not in available_vms:
        raise FbsError('Could not find %s. Available VMs are:%s' %
                       (name, ''.join(['\n * ' + vm for vm in available_vms])))
    src_dir = src_root + '/' + name
    for path_fn in default_path, path:
        _copy(path_fn, src_dir, build_dir)
    settings = SETTINGS['docker_images'].get(name, {})
    for path_fn in default_path, path:
        for p in settings.get('build_files', []):
            _copy(path_fn, p, build_dir)
    args = ['build', '--pull', '-t', _get_docker_id(name), build_dir]
    for arg, value in settings.get('build_args', {}).items():
        args.extend(['--build-arg', '%s=%s' % (arg, value)])
    try:
        _run_docker(args,
                    check=True,
                    stdout=PIPE,
                    stderr=PIPE,
                    universal_newlines=True)
    except CalledProcessError as e:
        if '/private-key.gpg: no such file or directory' in e.stderr:
            message = 'Could not find private-key.gpg. Maybe you want to ' \
                      'run:\n    fbs gengpgkey'
        else:
            message = e.stdout + '\n' + e.stderr
        raise FbsError(message)
    _LOG.info('Done. You can now execute:\n    fbs runvm ' + name)
Exemplo n.º 16
0
def sign_installer_arch():
    installer = path('target/${installer}')
    if not exists(installer):
        raise FbsError(
            'Installer does not exist. Maybe you need to run:\n'
            '    fbs installer'
        )
    # Prevent GPG from prompting us for the passphrase when signing:
    preset_gpg_passphrase()
    check_call(
        ['gpg', '--batch', '--yes', '-u', SETTINGS['gpg_key'],
        '--output', installer + '.sig', '--detach-sig', installer],
        stdout=DEVNULL
    )
Exemplo n.º 17
0
def path(path_str):
    """
    Return the absolute path of the given file in the project directory. For
    instance: path('src/main/python'). The `path_str` argument should always use
    forward slashes `/`, even on Windows. You can use placeholders to refer to
    settings. For example: path('${freeze_dir}/foo').
    """
    path_str = expand_placeholders(path_str, SETTINGS)
    try:
        project_dir = SETTINGS['project_dir']
    except KeyError:
        error_message = "Cannot call path(...) until fbs.init(...) has been " \
                        "called."
        raise FbsError(error_message) from None
    return _source.path(project_dir, path_str)
Exemplo n.º 18
0
def run():
    """
    Run your app from source
    """
    require_existing_project()
    if not _has_module('PyQt5') and not _has_module('PySide2'):
        raise FbsError("Couldn't find PyQt5 or PySide2. Maybe you need to:\n"
                       "    pip install PyQt5==5.9.2")
    env = dict(os.environ)
    pythonpath = path('src/main/python')
    old_pythonpath = env.get('PYTHONPATH', '')
    if old_pythonpath:
        pythonpath += os.pathsep + old_pythonpath
    env['PYTHONPATH'] = pythonpath
    subprocess.run([sys.executable, path(SETTINGS['main_module'])], env=env)
Exemplo n.º 19
0
def get_icons():
    """
    Return a list [(size, scale, path)] of available app icons for the current
    platform.
    """
    result = {}
    for profile in LOADED_PROFILES:
        icons_dir = 'src/main/icons/' + profile
        for icon_path in glob(path(icons_dir + '/*.png')):
            name = splitext(basename(icon_path))[0]
            match = re.match('(\d+)(?:@(\d+)x)?', name)
            if not match:
                raise FbsError('Invalid icon name: ' % icon_path)
            size, scale = int(match.group(1)), int(match.group(2) or '1')
            result[(size, scale)] = icon_path
    return [(size, scale, path) for (size, scale), path in result.items()]
Exemplo n.º 20
0
def runvm(name):
    """
    Run a Linux VM. Eg.: runvm ubuntu
    """
    args = ['run', '-it']
    for item in _get_docker_mounts(name).items():
        args.extend(['-v', '%s:%s' % item])
    docker_id = _get_docker_id(name)
    args.append(docker_id)
    try:
        _run_docker(args, stderr=PIPE, universal_newlines=True, check=True)
    except CalledProcessError as e:
        if 'Unable to find image' in e.stderr:
            raise FbsError(
                'Docker could not find image %s. You may want to run:\n'
                '    fbs buildvm %s' % (docker_id, name))
Exemplo n.º 21
0
def startproject():
    """
    Start a new project in the current directory
    """
    if exists('src'):
        raise FbsError('The src/ directory already exists. Aborting.')
    app = prompt_for_value('App name', default='MyApp')
    user = getuser().title()
    author = prompt_for_value('Author', default=user)
    has_pyqt = _has_module('PyQt5')
    has_pyside = _has_module('PySide2')
    if has_pyqt and not has_pyside:
        python_bindings = 'PyQt5'
    elif not has_pyqt and has_pyside:
        python_bindings = 'PySide2'
    else:
        python_bindings = prompt_for_value(
            'Qt bindings', choices=('PyQt5', 'PySide2'), default='PyQt5'
        )
    eg_bundle_id = 'com.%s.%s' % (
        author.lower().split()[0], ''.join(app.lower().split())
    )
    mac_bundle_identifier = prompt_for_value(
        'Mac bundle identifier (eg. %s, optional)' % eg_bundle_id,
        optional=True
    )
    mkdir('src')
    template_dir = join(dirname(__file__), 'project_template')
    template_path = lambda relpath: join(template_dir, *relpath.split('/'))
    copy_with_filtering(
        template_dir, '.', {
            'app_name': app,
            'author': author,
            'mac_bundle_identifier': mac_bundle_identifier,
            'python_bindings': python_bindings
        },
        files_to_filter=[
            template_path('src/build/settings/base.json'),
            template_path('src/build/settings/mac.json'),
            template_path('src/main/python/main.py')
        ]
    )
    print('')
    _LOG.info(
        "Created the src/ directory. If you have %s installed, you can now "
        "do:\n\n    fbs run", python_bindings
    )
Exemplo n.º 22
0
def startproject():
    """
    Start a new project in the current directory
    """
    if exists('src'):
        raise FbsError('The src/ directory already exists. Aborting.')
    app = prompt_for_value('App name', default='MyApp')
    while ' ' in app:
        print('Sorry, spaces in the app name are not yet supported.')
        app = prompt_for_value('App name', default='MyApp')
    user = getuser().title()
    author = prompt_for_value('Author', default=user)
    python_bindings = prompt_for_value('Qt bindings (PyQt5 or PySide2)', default='PyQt5')
    while python_bindings.lower() not in ["pyqt5", "pyside2"]:
        print('Please select between "PyQt5" or "PySide2" only')
        python_bindings = prompt_for_value('Qt bindings (PyQt5 or PySide2)', default='PyQt5')
    eg_bundle_id = 'com.%s.%s' % (
        author.lower().split()[0], ''.join(app.lower().split())
    )
    mac_bundle_identifier = prompt_for_value(
        'Mac bundle identifier (eg. %s, optional)' % eg_bundle_id,
        optional=True
    )
    mkdir('src')
    template_dir = join(dirname(__file__), 'project_template')
    template_path = lambda relpath: join(template_dir, *relpath.split('/'))
    copy_with_filtering(
        template_dir, '.', {
            'app_name': app,
            'author': author,
            'mac_bundle_identifier': mac_bundle_identifier,
            'python_bindings': python_bindings
        },
        files_to_filter=[
            template_path('src/build/settings/base.json'),
            template_path('src/build/settings/mac.json'),
            template_path('src/main/python/main.py')
        ]
    )
    print('')
    _LOG.info(
        "Created the src/ directory. If you have %s installed, you can now "
        "do:\n\n    fbs run", python_bindings
    )
Exemplo n.º 23
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)
Exemplo n.º 24
0
def create_repo_arch():
    if not exists(path('target/${installer}.sig')):
        raise FbsError(
            'Installer does not exist or is not signed. Maybe you need to '
            'run:\n'
            '    fbs signinst')
    dest_dir = path('target/repo')
    if exists(dest_dir):
        rmtree(dest_dir)
    makedirs(dest_dir)
    app_name = SETTINGS['app_name']
    pkg_file = path('target/${installer}')
    pkg_file_versioned = '%s-%s.pkg.tar.xz' % (app_name, SETTINGS['version'])
    copy(pkg_file, join(dest_dir, pkg_file_versioned))
    copy(pkg_file + '.sig', join(dest_dir, pkg_file_versioned + '.sig'))
    check_call(
        ['repo-add', '%s.db.tar.gz' % app_name, pkg_file_versioned],
        cwd=dest_dir,
        stdout=DEVNULL)
    # Ensure the permissions are correct if uploading to a server:
    check_call(['chmod', 'g-w', '-R', dest_dir])
Exemplo n.º 25
0
def _get_keygrip(pubkey_id):
    try:
        output = check_output(['gpg2', '--with-keygrip', '-K', pubkey_id],
                              universal_newlines=True,
                              stderr=PIPE)
    except CalledProcessError as e:
        if 'invalid option "--with-keygrip"' in e.stderr:
            raise GpgDoesNotSupportKeygrip() from None
        elif 'No secret key' in e.stderr:
            raise FbsError(
                "GPG could not read your key for code signing. Perhaps you "
                "don't want\nto run this command here, but after:\n"
                "    fbs runvm {ubuntu|fedora|arch}")
        raise
    pure_signing_subkey = _find_keygrip(output, 'S')
    if pure_signing_subkey:
        return pure_signing_subkey
    any_signing_key = _find_keygrip(output, '[^]]*S[^]]*')
    if any_signing_key:
        return any_signing_key
    raise RuntimeError('Keygrip not found. Output was:\n' + output)
Exemplo n.º 26
0
def startproject():
    """
    Start a new project in the current directory
    """
    if exists('src'):
        raise FbsError('The src/ directory already exists. Aborting.')
    try:
        app = prompt_for_value('App name', default='MyApp')
        user = getuser().title()
        author = prompt_for_value('Author', default=user)
        version = prompt_for_value('Initial version', default='0.0.1')
        eg_bundle_id = 'com.%s.%s' % (author.lower().split()[0], ''.join(
            app.lower().split()))
        mac_bundle_identifier = prompt_for_value(
            'Mac bundle identifier (eg. %s, optional)' % eg_bundle_id,
            optional=True)
    except KeyboardInterrupt:
        print('')
        return
    print('')
    mkdir('src')
    template_dir = join(dirname(__file__), 'project_template')
    template_path = lambda relpath: join(template_dir, *relpath.split('/'))
    python_bindings = _get_python_bindings()
    copy_with_filtering(template_dir,
                        '.', {
                            'app_name': app,
                            'author': author,
                            'version': version,
                            'mac_bundle_identifier': mac_bundle_identifier,
                            'python_bindings': python_bindings
                        },
                        files_to_filter=[
                            template_path('src/build/settings/base.json'),
                            template_path('src/build/settings/mac.json'),
                            template_path('src/main/python/main.py')
                        ])
    _LOG.info(
        "Created the src/ directory. If you have %s installed, you can now "
        "do:\n    fbs run", python_bindings)
Exemplo n.º 27
0
def _upload_repo(username, password):
    status, response = _server.post_json('start_upload', {
        'username': username,
        'password': password
    })
    unexpected_response = lambda: FbsError(
        'Received unexpected server response %d:\n%s' % (status, response))
    if status // 2 != 100:
        raise unexpected_response()
    try:
        data = json.loads(response)
    except ValueError:
        raise unexpected_response()
    try:
        credentials = data['bucket'], data['key'], data['secret']
    except KeyError:
        raise unexpected_response()
    dest_path = lambda p: username + '/' + SETTINGS['app_name'] + '/' + p
    installer = path('target/${installer}')
    installer_dest = dest_path(basename(installer))
    upload_file(installer, installer_dest, *credentials)
    uploaded = [installer_dest]
    if is_linux():
        repo_dest = dest_path(SETTINGS['repo_subdir'])
        uploaded.extend(
            upload_folder_contents(path('target/repo'), repo_dest,
                                   *credentials))
        pubkey_dest = dest_path('public-key.gpg')
        upload_file(path('src/sign/linux/public-key.gpg'), pubkey_dest,
                    *credentials)
        uploaded.append(pubkey_dest)
    status, response = _server.post_json('complete_upload', {
        'username': username,
        'password': password,
        'files': uploaded
    })
    if status != 201:
        raise unexpected_response()
Exemplo n.º 28
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)
Exemplo n.º 29
0
def _run_docker(args, **kwargs):
    try:
        run(['docker'] + args, **kwargs)
    except FileNotFoundError:
        raise FbsError(
            'fbs could not find Docker. Is it installed and on your PATH?')
Exemplo n.º 30
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}
        )