示例#1
0
def test_save(tmpdir):
    temp_dir = tmpdir.mkdir('mazer_collectio_info_unit_test')

    file_name = "example_collection_info1.yml"

    temp_file = temp_dir.join(file_name)

    test_data_path = os.path.join(os.path.dirname(__file__), '%s' % file_name)
    with open(test_data_path, 'r') as data_fd:
        res = collection_info.load(data_fd)

        log.debug('temp_file.strpath: %s', temp_file.strpath)
        yaml_persist.save(res, temp_file.strpath)

        # open the save()'ed file and load a new collection_artifact_manifest from it
        with open(temp_file.strpath, 'r') as read_fd:
            reloaded = collection_info.load(read_fd)

            log.debug('reloaded: %s', reloaded)

            # verify the object loaded from known example matches the example after
            # a save()/load() cycle
            assert reloaded == res

            # read the file again and log the file contents
            read_fd.seek(0)
            buf = read_fd.read()
            log.debug('buf: %s', buf)
示例#2
0
def test_parse_error(tmpdir):
    test_data = {
        'name': 'foo.foo',
        'authors': ['chouseknecht'],
        'license': 'GPL-3.0-or-later',
        'version': '0.0.1',
        'description': 'unit testing thing',
        'foo': 'foo',
    }
    collection_yaml = yaml.safe_dump(test_data, stream=None)
    with pytest.raises(exceptions.GalaxyClientError):
        collection_info.load(collection_yaml)
示例#3
0
def test_load():
    file_name = "example_collection_info1.yml"
    test_data_path = os.path.join(os.path.dirname(__file__), '%s' % file_name)
    expected = {
        'namespace': 'some_namespace',
        'name': 'some_name',
        'version': '11.11.11',
        'authors': ['Carlos Boozer'],
        'description': 'something',
        'license': 'GPL-3.0-or-later',
        'tags': [],
        'readme': None,
        'documentation': None,
        'homepage': None,
        'issues': None,
        'repository': None,
        'dependencies': {}
    }

    with open(test_data_path, 'r') as data_fd:
        res = collection_info.load(data_fd)
        log.debug('res: %s', res)

        assert isinstance(res, CollectionInfo)
        res_dict = attr.asdict(res)
        assert res_dict == expected

        for key in res_dict:
            assert getattr(res, key) == res_dict[key] == expected[key]
            assert isinstance(getattr(res, key), type(expected[key]))
示例#4
0
def _build(galaxy_context, build_context, display_callback=None):

    results = {}

    log.debug('build_context: %s', build_context)

    collection_path = build_context.collection_path
    collection_info_file_path = os.path.join(
        collection_path, collection_info.COLLECTION_INFO_FILENAME)

    results['collection_path'] = collection_path
    results['info_file_path'] = collection_info_file_path
    results['errors'] = []

    info = None

    try:
        with open(collection_info_file_path, 'r') as info_fd:
            info = collection_info.load(info_fd)

            log.debug('info: %s', info)
    except IOError as e:
        log.error('Error loading the %s at %s: %s',
                  collection_info.COLLECTION_INFO_FILENAME,
                  collection_info_file_path, e)
        results['errors'].append('Error loading the %s at %s: %s' %
                                 (collection_info.COLLECTION_INFO_FILENAME,
                                  collection_info_file_path, e))

    if not info:
        results['success'] = False
        results['errors'].append('There was no collection info in %s' %
                                 collection_info_file_path)
        return results

    builder = Build(build_context=build_context, collection_info=info)

    ensure_output_dir(build_context.output_path)

    build_results = builder.run(display_callback=display_callback)

    log.debug('build_results: %s', build_results)

    # results here include the builder results and... ?
    results['build_results'] = build_results

    log.debug('build action results: %s', results)

    if build_results.status == BuildStatuses.success:
        results['success'] = True
        return results

    results['success'] = False
    return results
示例#5
0
def test_load():
    file_name = "example_collection_info1.yml"
    test_data_path = os.path.join(os.path.dirname(__file__), '%s' % file_name)
    expected = {
        'namespace': 'some_namespace',
        'name': 'some_name',
        'version': '11.11.11',
        'author': 'Carlos Boozer',
        'license': 'GPLv2',
        'format_version': 0.0
    }

    with open(test_data_path, 'r') as data_fd:
        res = collection_info.load(data_fd)
        log.debug('res: %s', res)

        assert isinstance(res, CollectionInfo)
        res_dict = attr.asdict(res)
        assert res_dict == expected

        for key in res_dict:
            assert getattr(res, key) == res_dict[key] == expected[key]
            assert isinstance(getattr(res, key), type(expected[key]))
示例#6
0
def test_migrate_role_galaxy_yml(tmpdir):
    output_path = tmpdir.mkdir(
        'mazer_test_migrate_role_action_test_migrate_role')

    res, migrate_role_context = _migrate_role(output_path=output_path.strpath)

    assert res == 0
    assert os.path.isdir(output_path.strpath)

    galaxy_yml_path = os.path.join(output_path.strpath, 'galaxy.yml')

    assert os.path.isfile(galaxy_yml_path)

    with open(galaxy_yml_path, 'r') as cfd:
        col_info = collection_info.load(cfd)

    log.debug('col_info: %s', col_info)

    assert isinstance(col_info, CollectionInfo)
    assert col_info.namespace == COL_NAMESPACE
    assert col_info.name == COL_NAME
    assert col_info.version == COL_VERSION
    assert isinstance(col_info.authors, list)
    assert isinstance(col_info.dependencies, dict)
示例#7
0
def load_from_archive(repository_archive, namespace=None, installed=True):
    repo_tarfile = repository_archive.tar_file
    archive_path = repository_archive.info.archive_path

    # path_name = os.path.join(content_dir, namespace, name)
    path_name = repository_archive.info.top_dir

    manifest_filename = os.path.join(
        path_name, collection_artifact_manifest.COLLECTION_MANIFEST_FILENAME)
    manifest_data = None

    log.debug('Trying to extract %s from %s', manifest_filename, archive_path)

    try:
        mfd = repo_tarfile.extractfile(manifest_filename)
        if mfd:
            manifest_data = collection_artifact_manifest.load(mfd)
            log.debug('md: %s', manifest_data)
            log.debug('md.collection_info: %s', manifest_data.collection_info)
            log.debug('manifest_data.collection_info.name: %s',
                      manifest_data.collection_info.name)
    except KeyError as e:
        log.warning('No %s found in archive: %s (Error: %s)',
                    manifest_filename, archive_path, e)

    # load galaxy.yml
    galaxy_filename = os.path.join(path_name,
                                   collection_info.COLLECTION_INFO_FILENAME)

    collection_info_data = None

    try:
        gfd = repo_tarfile.extractfile(galaxy_filename)
        if gfd:
            collection_info_data = collection_info.load(gfd)
    except KeyError as e:
        log.warning('No %s found in archive: %s - %s', galaxy_filename,
                    archive_path, e)
        # log.debug('No galaxy.yml collection info found for collection %s.%s: %s', namespace, name, e)

    # TODO/FIXME: what takes precedence?
    #           - the dir name in the archive that a collection lives in ~/.ansible/content/my_ns/my_name
    #           - Or the namespace/name from galaxy.yml?
    # log.debug('collection_info_data: %s', collection_info_data)

    col_info = None
    if manifest_data:
        col_info = manifest_data.collection_info
        log.debug('md.col_info: %s', col_info)
    elif collection_info_data:
        col_info = collection_info_data
    else:
        raise exceptions.GalaxyArchiveError(
            'No galaxy collection info or manifest found in %s', archive_path)

    log.debug('col_info: %s', col_info)

    # FIXME: change collectionInfo to have separate name/namespace so we dont have to 'parse' the name
    # repo_spec = repository_spec.repository_spec_from_string(col_info.name, namespace_override=namespace)
    # spec_data = repository_spec_parse.parse_string(col_info.name)

    # log.debug('spec_data: %s', spec_data)
    # log.debug('repo_spec: %s', repo_spec)

    # Build a repository_spec of the repo now so we can pass it things like requirements.load()
    # that need to know what requires something
    # if we specify a namespace, use it otherwise use the info from galaxy.yml
    repo_spec = RepositorySpec(
        namespace=namespace or col_info.namespace,
        name=col_info.name,
        version=col_info.version,
        spec_string=archive_path,
        # fetch_method=None,
        src=archive_path)

    log.debug('repo spec from %s: %r', archive_path, repo_spec)

    requirements_list = []
    requirements_list = requirements.from_requirement_spec_strings(
        col_info.dependencies, repository_spec=repo_spec)

    repository = Repository(
        repository_spec=repo_spec,
        path=None,
        installed=installed,
        requirements=requirements_list,
        # Assuming this is a collection artifact, FIXME if we support role artifacts
        dependencies=[])

    log.debug('repository: %s', repository)

    return repository
示例#8
0
def load_from_dir(content_dir, namespace, name, installed=True):
    # TODO: or artifact

    path_name = os.path.join(content_dir, namespace, name)
    # TODO: add trad role or collection detection rules here
    #       Or possibly earlier so we could call 'collection' loading
    #       code/class or trad-role-as-collection loading code/class
    #       and avoid intermingly the impls.
    #       Maybe:
    #       if more than one role in roles/ -> collection

    if not os.path.isdir(path_name):
        log.debug(
            'The directory %s does not exist, unable to load a Repository from it',
            path_name)
        return None

    requirements_list = []

    # Now look for any install_info for the repository
    install_info_data = None
    install_info_filename = os.path.join(path_name,
                                         'meta/.galaxy_install_info')
    try:
        with open(install_info_filename, 'r') as ifd:
            install_info_data = install_info.load(ifd)
    except EnvironmentError as e:
        log.warning(
            'Unable to find or load meta/.galaxy_install_info for repository %s.%s: %s',
            namespace, name, e)

    # TODO: figure out what to do if the version from install_info conflicts with version
    #       from galaxy.yml etc.
    install_info_version = getattr(install_info_data, 'version', None)

    # Try to load a MANIFEST.json if we have one

    manifest_filename = os.path.join(
        path_name, collection_artifact_manifest.COLLECTION_MANIFEST_FILENAME)
    manifest_data = None

    try:
        with open(manifest_filename, 'r') as mfd:
            manifest_data = collection_artifact_manifest.load(mfd)
    except EnvironmentError:
        # log.debug('No galaxy.yml collection info found for collection %s.%s: %s', namespace, name, e)
        pass

    # load galaxy.yml
    galaxy_filename = os.path.join(path_name,
                                   collection_info.COLLECTION_INFO_FILENAME)

    collection_info_data = None

    try:
        with open(galaxy_filename, 'r') as gfd:
            collection_info_data = collection_info.load(gfd)
    except EnvironmentError:
        # log.debug('No galaxy.yml collection info found for collection %s.%s: %s', namespace, name, e)
        pass

    # Now try the repository as a role-as-collection
    # FIXME: For a repository with one role that matches the collection name and doesn't
    #        have a galaxy.yml, that's indistinguishable from a role-as-collection
    # FIXME: But in theory, if there is more than one role in roles/, we should skip this
    role_meta_main_filename = os.path.join(path_name, 'roles', name, 'meta',
                                           'main.yml')
    role_meta_main = None
    role_name = '%s.%s' % (namespace, name)

    try:
        with open(role_meta_main_filename, 'r') as rmfd:
            # FIXME: kluge to avoid circular import on py2
            #        repository->role_metadata->dependencies->repository_spec->repository (loop)
            #        repository->requirements->repository_spec->repository (loop)
            from ansible_galaxy import role_metadata
            role_meta_main = role_metadata.load(rmfd, role_name=role_name)
    except EnvironmentError:
        # log.debug('No meta/main.yml was loaded for repository %s.%s: %s', namespace, name, e)
        pass

    # Prefer version from install_info, but for a editable installed, there may be only galaxy version
    installed_version = install_info_version
    if manifest_data:
        installed_version = manifest_data.collection_info.version
    elif collection_info_data:
        installed_version = collection_info_data.version
    # if role_meta_main:
    #    installed_version = installed_version or role_meta_main.version

    # TODO/FIXME: what takes precedence?
    #           - the dir names a collection lives in ~/.ansible/content/my_ns/my_name
    #           - Or the namespace/name from galaxy.yml?
    # log.debug('collection_info_data: %s', collection_info_data)

    # Build a repository_spec of the repo now so we can pass it things like requirements.load()
    # that need to know what requires something
    repository_spec = RepositorySpec(namespace=namespace,
                                     name=name,
                                     version=installed_version)

    # The current galaxy.yml 'dependencies' are actually 'requirements' in ansible/ansible terminology
    # (ie, install-time)
    if collection_info_data:
        collection_requires = requirements.from_dependencies_dict(
            collection_info_data.dependencies, repository_spec=repository_spec)
        requirements_list.extend(collection_requires)

    # TODO: add requirements loaded from galaxy.yml
    # TODO: should the requirements in galaxy.yml be plain strings or dicts?
    # TODO: should there be requirements in galaxy.yml at all? in liue of requirements.yml
    # collection_info_requirements = []

    requirements_filename = os.path.join(path_name, 'requirements.yml')

    try:
        with open(requirements_filename, 'r') as rfd:
            requirements_list.extend(
                requirements.load(rfd, repository_spec=repository_spec))
    except EnvironmentError:
        # log.debug('No requirements.yml was loaded for repository %s.%s: %s', namespace, name, e)
        pass

    # TODO: if there are other places to load dependencies (ie, runtime deps) we will need
    #       to load them and combine them with role_depenency_specs
    role_dependency_specs = []
    if role_meta_main:
        role_dependency_specs = role_meta_main.dependencies

    repository = Repository(repository_spec=repository_spec,
                            path=path_name,
                            installed=installed,
                            requirements=requirements_list,
                            dependencies=role_dependency_specs)

    log.debug('Repository %s loaded from %s', repository.repository_spec.label,
              path_name)

    return repository
示例#9
0
def load_from_dir(content_dir,
                  namespace_path,
                  namespace,
                  name,
                  installed=True):
    path_name = os.path.join(namespace_path, name)

    log.debug('Loading repository %s.%s from path: %s', namespace, name,
              path_name)

    if not os.path.isdir(path_name):
        log.debug(
            'The directory %s does not exist, unable to load a Repository from it',
            path_name)
        return None

    # Now look for any install_info for the repository
    install_info_data = None
    install_info_filename = os.path.join(path_name,
                                         'meta/.galaxy_install_info')

    try:
        with open(install_info_filename, 'r') as ifd:
            install_info_data = install_info.load(ifd)
    except EnvironmentError as e:
        log.warning(
            'Unable to find or load meta/.galaxy_install_info for repository %s.%s: %s',
            namespace, name, e)

    # TODO: figure out what to do if the version from install_info conflicts with version
    #       from galaxy.yml etc.
    install_info_version = getattr(install_info_data, 'version', None)

    # Try to load a MANIFEST.json if we have one

    manifest_filename = os.path.join(
        path_name, collection_artifact_manifest.COLLECTION_MANIFEST_FILENAME)
    manifest_data = None

    try:
        with open(manifest_filename, 'r') as mfd:
            manifest_data = collection_artifact_manifest.load(mfd)
    except EnvironmentError:
        # log.debug('No galaxy.yml collection info found for collection %s.%s: %s', namespace, name, e)
        pass

    # # TODO/FIXME: do we even need to load file_manifest here?
    # file_manifest_filename = os.path.join(path_name, collection_artifact_file_manifest.COLLECTION_FILE_MANIFEST_FILENAME)
    # file_manifest_data = None

    # try:
    #     with open(file_manifest_filename, 'r') as mfd:
    #         file_manifest_data = collection_artifact_file_manifest.load(mfd)
    # except EnvironmentError:
    #     # log.debug('No galaxy.yml collection info found for collection %s.%s: %s', namespace, name, e)
    #     pass

    # load galaxy.yml
    galaxy_filename = os.path.join(path_name,
                                   collection_info.COLLECTION_INFO_FILENAME)

    galaxy_yml_data = None

    try:
        with open(galaxy_filename, 'r') as gfd:
            if gfd:
                galaxy_yml_data = collection_info.load(gfd)
    except EnvironmentError:
        # for the case of collections that are not from or intended for galaxy, they do not
        # need to provide a galaxy.yml or MANIFEST.json, so an error here is exceptable.
        # log.debug('No galaxy.yml collection info found for collection %s.%s: %s', namespace, name, e)
        pass

    # TODO: make existence of a galaxy.yml and a MANIFEST.json mutual exclude and raise an exception for that case

    col_info = None
    # MANIFEST.json is higher prec than galaxy.yml
    if galaxy_yml_data:
        col_info = galaxy_yml_data

    if manifest_data:
        col_info = manifest_data.collection_info

    # Prefer version from install_info, but for a editable installed, there may be only galaxy version
    installed_version = install_info_version
    if col_info:
        installed_version = col_info.version

    # TODO/FIXME: what takes precedence?
    #           - the dir names a collection lives in ~/.ansible/content/my_ns/my_name
    #           - Or the namespace/name from galaxy.yml?
    #           - Or the namespace/name from MANIFEST.json
    #         Ditto for requirements

    # log.debug('collection_info_data: %s', collection_info_data)

    # Build a repository_spec of the repo now so we can pass it things like
    # requirements.from_dependencies_dict that need to know what requires something.
    repository_spec = RepositorySpec(namespace=namespace,
                                     name=name,
                                     version=installed_version)

    # The current galaxy.yml 'dependencies' are actually 'requirements' in ansible/ansible terminology
    # (ie, install-time)
    requirements_list = []
    if col_info:
        requirements_list = requirements.from_dependencies_dict(
            col_info.dependencies, repository_spec=repository_spec)

    repository = Repository(
        repository_spec=repository_spec,
        path=path_name,
        installed=installed,
        requirements=requirements_list,
    )

    log.debug('Loaded repository %s from %s', repository.repository_spec.label,
              path_name)

    return repository