Exemple #1
0
    def test_upload_non_interactive(self):
        pkgname = 'new_pkg'
        env = Env.read_envfile()

        self.assertTrue(
            os.environ.get('KECHAIN_URL'),
            "KECHAIN_URL is not set in environment, cannot perform this test")

        with temp_chdir() as d:
            runner = CliRunner()
            result = runner.invoke(kecpkg, ['new', pkgname, '--no-venv'])
            package_dir = get_package_dir(pkgname)
            self.assertTrue(os.path.exists(package_dir))

            os.chdir(package_dir)

            result = runner.invoke(kecpkg, ['build', pkgname])
            self.assertEqual(result.exit_code, 0)
            self.assertExists(os.path.join(package_dir, 'dist'))
            pkgpath = os.path.join(package_dir, 'dist',
                                   '{}-0.0.1-py3.5.kecpkg'.format(pkgname))
            self.assertExists(pkgpath)

            result = runner.invoke(
                kecpkg,
                [
                    'upload',
                    pkgname,
                    '--url',
                    os.environ.get('KECHAIN_URL'),
                    '--token',
                    os.environ.get('KECHAIN_TOKEN'),
                    '--scope-id',
                    os.environ.get('KECHAIN_SCOPE_ID'),
                    '--kecpkg',
                    pkgpath,
                    '--store'  # store the service_id in the settings (for teardown)
                ])
            self.assertEqual(result.exit_code, 0)

            # teardown the just uploaded service
            from kecpkg.settings import load_settings
            settings = load_settings(package_dir=get_package_dir(pkgname))

            from pykechain import get_project
            scope = get_project(url=os.environ.get('KECHAIN_URL'),
                                token=os.environ.get('KECHAIN_TOKEN'),
                                scope_id=os.environ.get('KECHAIN_SCOPE_ID'))
            service = scope.service(pk=settings.get('service_id'))
            service.delete()
Exemple #2
0
    def test_build_with_alternate_config(self):
        pkgname = 'new_pkg'
        alt_settings = 'alt-settings.json'

        with temp_chdir() as d:
            runner = CliRunner()
            result = runner.invoke(kecpkg, ['new', pkgname, '--no-venv'])
            package_dir = get_package_dir(pkgname)
            self.assertTrue(os.path.exists(package_dir))

            # set alternative settings path
            settings = copy_default_settings()
            settings["package_name"] = pkgname
            save_settings(settings,
                          package_dir=package_dir,
                          settings_filename=alt_settings)

            os.chdir(package_dir)

            result = runner.invoke(
                kecpkg, ['build', pkgname, '--config', alt_settings])
            self.assertEqual(
                result.exit_code, 0,
                "Results of the run were: \n---\n{}\n---".format(
                    result.output))
            self.assertExists(os.path.join(package_dir, 'dist'))

            dist_dir_contents = os.listdir(os.path.join(package_dir, 'dist'))
            self.assertTrue(len(dist_dir_contents), 1)
            self.assertTrue(
                pkgname in dist_dir_contents[0],
                "the name of the pkg `{}` should be in the name of "
                "the built kecpkg `{}`".format(pkgname, dist_dir_contents[0]))
Exemple #3
0
    def test_build_with_prune(self):
        pkgname = 'new_pkg'

        with temp_chdir() as d:
            runner = CliRunner()
            result = runner.invoke(kecpkg, ['new', pkgname, '--no-venv'])
            package_dir = get_package_dir(pkgname)
            self.assertTrue(os.path.exists(package_dir))

            os.chdir(package_dir)

            result = runner.invoke(kecpkg, ['build', pkgname])
            self.assertEqual(
                result.exit_code, 0,
                "Results of the run were: \n---\n{}\n---".format(
                    result.output))
            self.assertExists(os.path.join(package_dir, 'dist'))

            # check if dist is filled
            package_dir_contents = os.listdir(os.path.join(
                package_dir, 'dist'))
            self.assertTrue(len(package_dir_contents), 1)

            # restart the build, with prune and check if dist still has 1
            result = runner.invoke(kecpkg, ['build', pkgname, '--prune'])
            self.assertEqual(
                result.exit_code, 0,
                "Results of the run were: \n---\n{}\n---".format(
                    result.output))
            self.assertExists(os.path.join(package_dir, 'dist'))

            # check if dist is filled
            package_dir_contents = os.listdir(os.path.join(
                package_dir, 'dist'))
            self.assertTrue(len(package_dir_contents), 1)
Exemple #4
0
def build(package=None, **options):
    """Build the package and create a kecpkg file."""
    echo_info('Locating package ``'.format(package))
    package_dir = get_package_dir(package_name=package)
    package_name = os.path.basename(package_dir)
    echo_info('Package `{}` has been selected'.format(package_name))
    settings = load_settings(
        package_dir=package_dir,
        settings_filename=options.get('settings_filename'))

    # ensure build directory is there
    build_dir = settings.get('build_dir', 'dist')
    build_path = os.path.join(package_dir, build_dir)

    if options.get('update_package_info'):
        render_package_info(settings, package_dir=package_dir, backup=True)

    if options.get('clean_first'):
        remove_path(build_path)
    ensure_dir_exists(build_path)

    # do package building
    build_package(package_dir,
                  build_path,
                  settings,
                  options=options,
                  verbose=options.get('verbose'))

    echo_success('Complete')
Exemple #5
0
    def test_purge_non_interactive(self):
        pkgname = 'new_pkg'

        with temp_chdir() as d:
            runner = CliRunner()
            result = runner.invoke(kecpkg, ['new', pkgname, '--no-venv'])
            package_dir = get_package_dir(pkgname)
            self.assertTrue(os.path.exists(package_dir))

            result = runner.invoke(kecpkg, ['purge', pkgname, '--force'])
            self.assertFalse(os.path.exists(package_dir))
Exemple #6
0
def save_settings(settings, package_dir=None, settings_filename=None):
    """
    Save settings in path (in the package).

    :param settings: settings to save
    :param settings_filename: (optional) pathname of the file where the settings are stored
    :param package_dir: (optional) package_dir to save to
    :return: None
    """
    if settings.get('package_name') and not package_dir:
        package_dir = get_package_dir(settings.get('package_name'))
    settings_filepath = get_settings_filepath(package_dir, settings_filename)

    ensure_dir_exists(os.path.dirname(settings_filepath))
    with atomic_write(settings_filepath, overwrite=True) as f:
        f.write(json.dumps(settings, indent=4))
Exemple #7
0
    def test_build_with_extra_ignores(self):
        pkgname = 'new_pkg'

        with temp_chdir() as d:
            runner = CliRunner()
            result = runner.invoke(kecpkg, ['new', pkgname, '--no-venv'])
            package_dir = get_package_dir(pkgname)
            self.assertTrue(os.path.exists(package_dir))
            ensure_dir_exists(os.path.join(package_dir, 'data'))

            # add additional files (to exclude for building later)
            touch_file(os.path.join(package_dir, 'data', 'somefile.txt'))
            touch_file(
                os.path.join(package_dir, 'local_extra_file.someext.txt'))

            os.chdir(package_dir)

            # check if those files exists
            package_dir_contents = os.listdir(os.path.join(package_dir))
            self.assertTrue(
                'local_extra_file.someext.txt' in package_dir_contents)
            self.assertTrue('data' in package_dir_contents)

            # set exclude_paths in settings
            settings = copy_default_settings()
            settings["exclude_paths"] = ["data", "local_extra_file.*"]
            save_settings(settings, package_dir=package_dir)

            # run the builder
            result = runner.invoke(kecpkg, ['build', pkgname, '--verbose'])
            self.assertEqual(
                result.exit_code, 0,
                "Results of the run were: \n---\n{}\n---".format(
                    result.output))
            self.assertExists(os.path.join(package_dir, 'dist'))

            # check the zip such that the extra files are not packaged
            dist_list = os.listdir(os.path.join(package_dir, 'dist'))
            zipfile = ZipFile(os.path.join(package_dir, 'dist', dist_list[0]),
                              'r')
            contents = zipfile.namelist()

            self.assertFalse('local_extra_file.someext.txt' in contents)
            self.assertFalse('data' in contents)
Exemple #8
0
def prune(package, **options):
    """Remove a project's build artifacts."""
    package_name = package or get_package_name() or click.prompt('Provide package name')
    package_dir = get_package_dir(package_name)

    settings = load_settings(package_name)
    # ensure build directory is there
    build_dir = settings.get('build_dir', 'dist')
    build_path = os.path.join(package_dir, build_dir)

    if os.path.exists(build_path):
        if options.get('force') or click.confirm(
                "Do you want to prune build artifacts for package '{}'?".format(package_name)):
            remove_path(build_path)
            if os.path.exists(build_path):
                echo_failure('Something went wrong pruning pacakage `{}`'.format(package_name))
        else:
            echo_warning('Package `{}` will not be pruned'.format(package_name))
    else:
        echo_failure('Package `{}` does not exist'.format(package_name))
Exemple #9
0
def purge(package, **options):
    """
    Purge and clean a package directory structure.

    :param package: Name of the kecpkg package
    :param options:
    :return:
    """
    package_name = package or click.prompt('Provide package name')
    package_dir = get_package_dir(package_name)

    if os.path.exists(package_dir):
        if options.get('force') or click.confirm(
                "Do you want to purge and completely remove '{}'?".format(package_name)):
            remove_path(package_dir)
            if not os.path.exists(package_dir):
                echo_success('Package `{}` is purged and removed from disk'.format(package_name))
            else:
                echo_failure('Something went wrong pruning pacakage `{}`'.format(package_name))
        else:
            echo_warning('Package `{}` will not be purged'.format(package_name))
    else:
        echo_failure('Package `{}` does not exist'.format(package_name))
Exemple #10
0
    def _do_create_key(gpg, options):
        echo_info(
            "Will create a secret key and store it into the KECPKG keyring.")
        package_dir = get_package_dir(package_name=package, fail=False)
        settings = DEFAULT_SETTINGS
        if package_dir is not None:
            package_name = os.path.basename(package_dir)
            echo_info('Package `{}` has been selected'.format(package_name))
            settings = load_settings(
                package_dir=package_dir,
                settings_filename=options.get('settings_filename'))

        key_info = {
            'name_real':
            click.prompt("Name", default=settings.get('name')),
            'name_comment':
            click.prompt("Comment", default="KECPKG SIGNING KEY"),
            'name_email':
            click.prompt("Email", default=settings.get('email')),
            'expire_date':
            click.prompt("Expiration in months",
                         default=12,
                         value_proc=lambda i: "{}m".format(i)),
            'key_type':
            'RSA',
            'key_length':
            4096,
            'key_usage':
            '',
            'subkey_type':
            'RSA',
            'subkey_length':
            4096,
            'subkey_usage':
            'encrypt,sign,auth',
            'passphrase':
            ''
        }

        passphrase = click.prompt("Passphrase", hide_input=True)
        passphrase_confirmed = click.prompt("Confirm passphrase",
                                            hide_input=True)
        if passphrase == passphrase_confirmed:
            key_info['passphrase'] = passphrase
        else:
            raise ValueError("The passphrases did not match.")

        echo_info(
            "Creating the secret key '{name_real} ({name_comment}) <{name_email}>'"
            .format(**key_info))
        echo_info(
            "Please move around mouse or generate other activity to introduce sufficient entropy. "
            "This might take a minute...")
        result = gpg.gen_key(gpg.gen_key_input(**key_info))
        pprint(result.__dict__)
        if result and result.stderr.find('KEY_CREATED'):
            echo_success("The key is succesfully created")
            _do_list(gpg=gpg)
            sys.exit(0)

        echo_failure("Could not generate the key due to an error: '{}'".format(
            result.stderr))
        sys.exit(1)
Exemple #11
0
def config(package, **options):
    """Manage the configuration (or settings) of the package.

    The various settings in the .kecpkg-settings.json file are:

    package_name:   name of the package
    version:        version number of the package
    description:    longer description of the package
    name:           name of the author of the package
    email:          email of the author of the package
    python_version: python version on which the kecpkg will run, corresponds
                    with an executable KE-crunch environment
    entrypoint_script: the name of the script that will be executed first
    entrypoint_func: function name inside the script that will be executed.
                    Ensure that it takes *args, **kwargs.
    venv_dir:       python virtual environment directory in the development environment
    requirements_filename: name of the requirements file with list of package that
                    will be installed before running
    build_dir:      directory where the built kecpkg will be stored
    exclude_paths:  list of paths that will be excluded from the package, next to
                    the build in excludes
    url:            url where the package will be uploaded
    token:          token of the user under which the package is uploaded
    scope_id:       identification of the scope under which the package is uploaded
    service_id:     identification under which the package is re-uploaded
                    (or recently uploaded)
    last_upload:    date and time of the last upload
    """
    echo_info('Locating package ``'.format(package))
    package_dir = get_package_dir(package_name=package)
    package_name = os.path.basename(package_dir)
    echo_info('Package `{}` has been selected'.format(package_name))

    if options.get('init'):
        if os.path.exists(os.path.join(package_dir, options.get('settings_filename'))) and \
                click.confirm('Are you sure you want to overwrite the current settingsfile '
                              '(old settings will be a backup)?'):
            copy_path(
                os.path.join(package_dir, options.get('settings_filename')),
                os.path.join(
                    package_dir,
                    "{}-backup".format(options.get('settings_filename'))))
        echo_info('Creating new settingsfile')
        settings = copy_default_settings()
        settings['package_name'] = package_name
        save_settings(settings,
                      package_dir=package_dir,
                      settings_filename=options.get('settings_filename'))

    settings = load_settings(package_dir=package_dir)
    if options.get('interactive'):
        settings['version'] = click.prompt('Version',
                                           default=settings.get(
                                               'version', '0.0.1'))
        settings['description'] = click.prompt('Description',
                                               default=settings.get(
                                                   'description', ''))
        settings['name'] = click.prompt('Author',
                                        default=settings.get(
                                            'name', os.environ.get('USER',
                                                                   '')))
        settings['email'] = click.prompt('Author\'s email',
                                         default=settings.get('email', ''))
        settings['python_version'] = click.prompt(
            'Python version (choose from: {})'.format(
                settings.get('pyversions')),
            default='3.5')
        settings['exclude_paths'] = click.prompt(
            "Exclude additional paths from kecpkg (eg. 'data, input')",
            default=settings.get('exclude_paths', ''),
            value_proc=process_additional_exclude_paths)
        save_settings(settings,
                      package_dir=package_dir,
                      settings_filename=options.get('settings_filename'))

    if options.get('set_key'):
        k, v = options.get('set_key')
        if options.get('verbose'):
            echo_info("Set the key '{}' to value '{}'".format(k, v))
        settings[k] = v
        save_settings(settings,
                      package_dir=package_dir,
                      settings_filename=options.get('settings_filename'))

    if options.get('get_key'):
        echo_info(
            tabulate([
                (options.get('get_key'), settings.get(options.get('get_key')))
            ],
                     headers=("key", "value")))
        return

    if options.get('verbose'):
        echo_info(tabulate(settings.items(), headers=("key", "value")))

    if not options.get('interactive'):
        echo_success('Settings file identified and correct')
Exemple #12
0
def upload(package=None,
           url=None,
           username=None,
           password=None,
           token=None,
           scope=None,
           scope_id=None,
           kecpkg=None,
           **options):
    """
    Upload built kecpkg to KE-chain.

    If no options are provided, the interactive mode is triggered.
    """
    package_name = package or get_package_name() or click.prompt(
        'Package name')
    settings = load_settings(
        package_dir=get_package_dir(package_name),
        settings_filename=options.get('settings_filename'))

    if not url or not ((username and password) or token):
        url = click.prompt('Url (incl http(s)://)',
                           default=settings.get('url') or url)
        username = click.prompt('Username',
                                default=settings.get('username') or username)
        password = click.prompt('Password', hide_input=True)
        # set the interactive world to True for continuation sake
        options['interactive'] = True
    elif not options.get('interactive'):
        url = url or settings.get('url')
        username = username or settings.get('username')
        token = token or settings.get('token')
        scope_id = scope_id or settings.get('scope_id')

    client = Client(url)
    client.login(username=username, password=password, token=token)

    # scope finder
    if not scope_id and settings.get('scope_id') and \
            click.confirm("Do you wish to use the stored `scope_id` in settings: `{}`".format(
                settings.get('scope_id')), default=True):
        scope_id = settings.get('scope_id')

    if not scope_id:
        scopes = client.scopes()
        scope_matcher = [
            dict(number=i, scope_id=scope.id, scope=scope.name)
            for i, scope in zip(range(1, len(scopes)), scopes)
        ]

        # nice UI
        echo_info('Choose from following scopes:')
        for match_dict in scope_matcher:
            echo_info(
                "{number} | {scope_id:.8} | {scope}".format(**match_dict))

        scope_match = None
        while not scope_match:
            scope_guess = click.prompt('Row number, part of Id or Scope')
            scope_match = validate_scopes(scope_guess, scope_matcher)

        echo_success(
            "Scope selected: '{scope}' ({scope_id})".format(**scope_match))
        scope_id = scope_match['scope_id']

    scope_to_upload = get_project(url,
                                  username,
                                  password,
                                  token,
                                  scope_id=scope_id)

    # service reupload
    service_id = options.get('service_id') or settings.get('service_id')
    if options.get('reupload') and not service_id:
        echo_failure('Please provide a service id to reupload to.')
    elif service_id and not options.get('reupload') and options.get(
            'interactive'):
        if click.confirm(
                "Do you wish to *replace* the previously uploaded service: `{}`"
                .format(service_id),
                default=True):
            service_id = service_id
        else:
            service_id = None

    # store to settings
    if options.get('store'):
        settings.update(
            dict(url=url, username=username, scope_id=str(scope_id)))
        if service_id:
            settings['service_id'] = str(service_id)
        save_settings(settings,
                      settings_filename=options.get('settings_filename'))

    # do upload
    build_path = os.path.join(get_package_dir(package_name),
                              settings.get('build_dir'))
    if not os.path.exists(build_path):
        echo_failure('Cannot find build path, please do `kecpkg build` first')
        sys.exit(400)

    upload_package(scope_to_upload,
                   build_path,
                   kecpkg,
                   service_id=service_id,
                   settings=settings,
                   store_settings=options.get('store'),
                   settings_filename=options.get('settings_filename'))