Beispiel #1
0
def _use_pom_resolution(context: DependencyContext, dependency: Dependency, classified_name: str, base_name: str) \
        -> Optional[DependencyPathSet]:
    """
    A function that resolves Java dependencies using POM files (the old way).

    :param context: the current dependency context in play.
    :param dependency: the dependency we are to resolve.
    :param classified_name: the classified base name for the main asset.
    :param base_name: the base name for file assets.
    :return: the appropriate dependency path set or ``None``.
    """
    jar_file = context.to_local_path(dependency, f'{classified_name}.jar')

    if not jar_file:
        return None

    # Ok, we're good to go.
    # First, let's see if there's a POM file that can tell us about dependencies.
    pom_file = context.to_local_path(dependency, f'{base_name}.pom')

    if pom_file and not dependency.ignore_transients:
        read_pom_for_dependencies(pom_file, context, dependency)

    # Now, let's create and load up our result:
    result = DependencyPathSet(dependency, jar_file)

    _try_to_add_secondary_path(context, dependency, 'sources', f'{base_name}-sources.jar', result)
    _try_to_add_secondary_path(context, dependency, 'javadoc', f'{base_name}-javadoc.jar', result)

    return result
Beispiel #2
0
    def test_resolve_no_dependencies(self):
        language = Language({}, 'lang')
        context = DependencyContext([], language, Configuration({}, [], None))

        language.resolver = MagicMock()

        assert context.resolve() == []
Beispiel #3
0
    def test_handle_project_resolution(self, tmpdir):
        directory = Path(str(tmpdir))
        name = 'name.txt'
        path = directory / name
        mock_project = MagicMock()
        mock_project.get_config.return_value = None
        mock_cache = MagicMock()
        mock_cache.names = ['a name']
        mock_cache.get_project.return_value = mock_project
        language = Language({}, 'lang')

        language.project_as_dist_path = MagicMock(return_value=None)

        context = DependencyContext([], language,
                                    Configuration({}, [], mock_cache))

        assert context._handle_project_resolution('', name) is None

        language.project_as_dist_path = MagicMock(return_value=directory)

        assert context._handle_project_resolution('', name) is None

        path.write_text("")

        assert context._handle_project_resolution('', name) == path
Beispiel #4
0
    def test_read_pom_for_dependencies_no_dependencies(self):
        """Make sure we generate no dependencies when none exist."""
        pom_path = get_test_path('java/junit-2.pom.xml')
        context = DependencyContext([], Language({}, 'lang'),
                                    Configuration({}, [], None))

        read_pom_for_dependencies(pom_path, context, self._parent_dependency())

        assert context.is_empty()
Beispiel #5
0
    def test_resolve_no_resolver(self):
        context = DependencyContext([], Language({}, 'lang'),
                                    Configuration({}, [], None))

        with pytest.raises(ValueError) as info:
            context.resolve()

        assert info.value.args[
            0] == 'The language, lang, does not provide a means of resolving dependencies.'
Beispiel #6
0
    def test_handle_project_resolution_missing_function(self):
        context = DependencyContext([], Language({}, 'lang'),
                                    Configuration({}, [], None))

        with pytest.raises(ValueError) as info:
            context._handle_project_resolution('', 'name.txt')

        assert info.value.args[0] == 'The language, lang, does not provide a means of resolving project-based ' \
                                     'dependencies.'
Beispiel #7
0
    def test_to_local_file_no_path(self):
        mock_fetch = MagicMock(return_value=None)
        dep = _make_dep()
        context = DependencyContext([], Language({}, 'lang'),
                                    Configuration({}, [], None))

        context._fetch_file = mock_fetch

        assert context.to_local_path(dep, 'file.txt') is None

        mock_fetch.assert_called_once_with(dep, 'file.txt')
Beispiel #8
0
    def test_to_local_file_empty_signatures(self):
        path = 'file.txt'
        mock_fetch = MagicMock(return_value=path)
        dep = _make_dep()
        context = DependencyContext([], Language({}, 'lang'),
                                    Configuration({}, [], None))

        context._fetch_file = mock_fetch

        assert context.to_local_path(dep, 'file.txt', {}) is path

        mock_fetch.assert_called_once_with(dep, 'file.txt')
Beispiel #9
0
    def test_add_dependency(self):
        dep = _make_dep()
        context = DependencyContext([], Language({}, 'lang'),
                                    Configuration({}, [], None))
        context._resolve = MagicMock()

        assert dep.transient is False
        assert len(context._dependencies) == 0

        context.add_dependency(dep)

        assert dep.transient is True
Beispiel #10
0
    def test_resolve_duplicates(self):
        dep = _make_dep()
        path = Path('/path/to/file.txt')
        language = Language({}, 'lang')
        path_set = DependencyPathSet(dep, path)
        context = DependencyContext([dep, dep], language,
                                    Configuration({}, [], None))

        language.resolver = MagicMock(return_value=path_set)

        assert context.resolve() == [path_set]

        language.resolver.assert_called_once_with(context, dep)
Beispiel #11
0
    def test_handle_local_resolution(self, tmpdir):
        directory = Path(str(tmpdir))
        good_name = 'file.txt'
        bad_name = 'no-such-file.txt'

        existing_file = directory / good_name
        existing_file.write_text("")

        context = DependencyContext([], Language({}, 'lang'),
                                    Configuration({}, [directory], None))

        assert context._handle_local_resolution(bad_name) is None
        assert context._handle_local_resolution(good_name) == existing_file
Beispiel #12
0
    def test_fetch_file(self):
        remote_dep = _make_dep(location='remote')
        local_dep = _make_dep(location='local')
        project_dep = _make_dep(location='project')
        p1 = Path('path1')
        p2 = Path('path2')
        p3 = Path('path3')
        context = DependencyContext([], Language({}, 'lang'),
                                    Configuration({}, [], None))

        context._handle_remote_resolution = MagicMock(return_value=p1)
        context._handle_local_resolution = MagicMock(return_value=p2)
        context._handle_project_resolution = MagicMock(return_value=p3)

        r1 = context._fetch_file(remote_dep, 'remote.name')
        r2 = context._fetch_file(local_dep, 'local.name')
        r3 = context._fetch_file(project_dep, 'project.name')

        context._handle_remote_resolution.assert_called_once_with(
            'remote.name')
        context._handle_local_resolution.assert_called_once_with('local.name')
        context._handle_project_resolution.assert_called_once_with(
            'dep', 'project.name')

        assert r1 is p1
        assert r2 is p2
        assert r3 is p3
Beispiel #13
0
    def test_resolve_to_nothing(self):
        dep = _make_dep(name='resolve-to-nothing')
        language = Language({}, 'lang')
        context = DependencyContext([dep], language, Configuration({}, [],
                                                                   None))

        language.resolver = MagicMock(return_value=None)

        with pytest.raises(ValueError) as info:
            context.resolve()

        assert info.value.args[0] == 'Dependency path:\nresolve-to-nothing:resolve-to-nothing:1.2.3\nThe dependency, ' \
                                     'resolve-to-nothing:resolve-to-nothing:1.2.3, could not be resolved.'

        language.resolver.assert_called_once_with(context, dep)
Beispiel #14
0
    def test_to_local_file_good_passed_signatures(self, tmpdir):
        directory = Path(str(tmpdir))
        path = directory / 'file.txt'
        mock_fetch = MagicMock(return_value=path)
        dep = _make_dep()
        context = DependencyContext([], Language({}, 'lang'),
                                    Configuration({}, [], None))
        context._fetch_file = mock_fetch

        path.write_text("file content.\n")

        signatures = sign_path(path)

        assert context.to_local_path(dep, 'file.txt', signatures) is path
        assert mock_fetch.mock_calls == [call(dep, 'file.txt')]
Beispiel #15
0
def _get_remote_version_info(context: DependencyContext, dependency: Dependency) -> \
        Optional[Tuple[Version, List[Version]]]:
    """
    A function that determines the available and latest version numbers for the given
    remote dependency.  This is achieved by retrieving the ``maven-metadata.xml`` file
    for the dependency from Maven.

    :param context: the current context to use in pulling down remote files.
    :param dependency: the dependency to get the version information for.
    :return: Either ``None``, if version information could not be determined or a tuple
    containing the latest version in the 1st position and the list of available versions
    in the 2nd.
    """
    metadata_path = context.to_local_path(dependency, 'maven-metadata.xml')

    if metadata_path:
        data = ElementTree.parse(metadata_path).getroot()
        versioning = data.find('versioning')
        latest = versioning.find('latest')
        versions = versioning.find('versions')
        versions = [
            Version(version.text) for version in versions.iter('version')
        ]

        return Version(latest.text), versions

    return None
Beispiel #16
0
def resolve(context: DependencyContext, dependency: Dependency) -> Optional[DependencyPathSet]:
    """
    A function to resolve dependencies in Java-land.

    :param context: the current dependency context in play.
    :param dependency: the dependency we are to resolve.
    :return: the appropriate dependency path set or ``None``.
    """
    remote_resolver, classified_name, base_name = build_names(dependency)

    context.set_remote_resolver(remote_resolver)

    module_path = context.to_local_path(dependency, f'{base_name}.module')

    return _use_module_resolution(context, dependency, module_path) if module_path else \
        _use_pom_resolution(context, dependency, classified_name, base_name)
Beispiel #17
0
    def test_to_local_file_bad_passed_signatures(self, tmpdir):
        directory = Path(str(tmpdir))
        path = directory / 'file.txt'
        mock_fetch = MagicMock(return_value=path)
        dep = _make_dep()
        context = DependencyContext([], Language({}, 'lang'),
                                    Configuration({}, [], None))
        context._fetch_file = mock_fetch

        path.write_text("file content.\n")

        with pytest.raises(ValueError) as info:
            context.to_local_path(dep, 'file.txt', {'sha512': 'bad-signature'})

        assert info.value.args[
            0] == 'Dependency path:\n\nCould not verify the signature of the file file.txt.'
        assert mock_fetch.mock_calls == [call(dep, 'file.txt')]
Beispiel #18
0
    def test_construction(self):
        deps = []
        language = Language({}, 'lang')
        context = DependencyContext(deps, language, Configuration({}, [],
                                                                  None))

        assert context._dependencies == deps
        assert context._dependencies is not deps
        assert context._language is language
Beispiel #19
0
    def test_resolve_version_mismatch(self):
        dep1 = _make_dep(version='1.2.3')
        dep2 = _make_dep(version='4.5.6')
        path = Path('/path/to/file.txt')
        language = Language({}, 'lang')
        path_set = DependencyPathSet(dep1, path)
        context = DependencyContext([dep1, dep2], language,
                                    Configuration({}, [], None))

        language.resolver = MagicMock(return_value=path_set)

        with pytest.raises(ValueError) as info:
            context.resolve()

        assert info.value.args[0] == 'The same library, name:name, is required at two different versions, 1.2.3 vs. ' \
                                     '4.5.6.'

        language.resolver.assert_called_once_with(context, dep1)
Beispiel #20
0
def read_pom_for_dependencies(pom_path: Path, context: DependencyContext, parent_dependency: Dependency):
    """
    A function that reads a POM file for transient dependencies and includes them into
    the specified context.

    :param pom_path: the path to the POM file to read.
    :param context: the dependency context to add dependencies to.
    :param parent_dependency: the dependency to which the POM file belongs.
    :return: the list of dependencies found in the POM file, if any.
    """
    pom_file = POMFile(pom_path, context)

    for dependency in pom_file.dependencies():
        group, name, version = pom_file.get_dependency_info(dependency)
        version = pom_file.resolve_version(group, name, version)

        # If the version could not be resolved, it's not a dependency we care about.
        if version:
            context.add_dependency(parent_dependency.derive_from(group, name, version))
Beispiel #21
0
    def test_handle_remote_resolution(self):
        name = 'file.txt'
        parent_url = 'http://server/path/to'
        url = parent_url + '/' + name
        parent_path = Path('path/to')
        file = parent_path / name
        return_value = Path('/resolved/path/to/' + name)
        context = DependencyContext([], Language({}, 'lang'),
                                    Configuration({}, [], None))

        resolver = RemoteResolver(parent_url, parent_path)
        resolver._resolve_remotely = MagicMock(return_value=return_value)

        context.set_remote_resolver(resolver)

        rv = context._handle_remote_resolution(name)

        resolver._resolve_remotely.assert_called_once_with(url, file)

        assert rv is return_value
Beispiel #22
0
    def test_to_local_file_good_file_signatures(self, tmpdir):
        directory = Path(str(tmpdir))
        path = directory / 'file.txt'
        file_names = ['file.txt']
        file_names.extend([f'file.txt.{sn}' for sn in supported_signatures])
        mock_fetch = MagicMock(
            side_effect=[directory / name for name in file_names])
        dep = _make_dep()
        context = DependencyContext([], Language({}, 'lang'),
                                    Configuration({}, [], None))
        context._fetch_file = mock_fetch
        file_names = ['file.txt']
        file_names.extend([f'file.txt.{sn}' for sn in supported_signatures])

        path.write_text("file content.\n")

        sign_path_to_files(path)

        assert context.to_local_path(dep, 'file.txt') == path
        assert mock_fetch.mock_calls == [
            call(dep, 'file.txt'),
            call(dep, f'file.txt.{supported_signatures[0]}')
        ]
Beispiel #23
0
def _use_module_resolution(context: DependencyContext, dependency: Dependency, module_path: Path) \
        -> Optional[DependencyPathSet]:
    """
    A function that resolves Java dependencies using module files (the new way).

    :param context: the current dependency context in play.
    :param dependency: the dependency we are to resolve.
    :param module_path: the local path to our module file.
    :return: the appropriate dependency path set or ``None``.
    """
    module_data = ModuleData.from_path(module_path)
    variant = module_data.get_variant(API_ELEMENTS)

    # If there's not an API variant, then we really can't do anything.
    if not variant:
        return None

    jar_variant_file = variant.files[0]
    jar_file = context.to_local_path(dependency, jar_variant_file.name, jar_variant_file.signatures)

    # If we couldn't get the jar file, report same.
    if not jar_file:
        return None

    # Ok, let's process any dependencies that may be involved.
    if not dependency.ignore_transients:
        for transient_dependency in variant.dependencies:
            context.add_dependency(transient_dependency.as_dependency(dependency))

    # Now, let's create and load up our result:
    result = DependencyPathSet(dependency, jar_file)

    _try_for_variant(context, dependency, module_data, SOURCE_ELEMENTS, result)
    _try_for_variant(context, dependency, module_data, JAVADOC_ELEMENTS, result)

    return result
Beispiel #24
0
def _try_to_add_secondary_path(context: DependencyContext, dependency: Dependency, key: str, name: str,
                               path_set: DependencyPathSet, signatures: Optional[Dict[str, str]] = None):
    """
    A function that attempts to load a secondary path (sources or javadoc) and, if
    successful, adds them to the given path set.

    :param context: the current dependency context in play.
    :param dependency: the dependency we are to resolve.
    :param key: the key by which the secondary path will be known.
    :param name: the name of the secondary path.
    :param path_set: the path set to add a successfully isolated path to.
    :param signatures: the set of signatures to verify against (if any).
    """
    path = context.to_local_path(dependency, name, signatures)

    if path:
        path_set.add_secondary_path(key, path)
Beispiel #25
0
    def test_remote_info(self):
        path = Path('.')
        context = DependencyContext([], Language({}, 'lang'),
                                    Configuration({}, [], None))
        resolver = RemoteResolver('the url', path)

        assert context._remote_resolver is None

        context.set_remote_resolver(resolver)

        assert context._remote_resolver is resolver

        resolver = RemoteResolver('http://server/path/', path)

        context.set_remote_resolver(resolver)

        assert context._remote_resolver is resolver