mirror of
https://github.com/YunoHost-Apps/ffsync_ynh.git
synced 2024-09-03 18:26:38 +02:00
122 lines
4.8 KiB
Python
122 lines
4.8 KiB
Python
|
class AbstractProvider(object):
|
||
|
"""Delegate class to provide requirement interface for the resolver.
|
||
|
"""
|
||
|
|
||
|
def identify(self, dependency):
|
||
|
"""Given a dependency, return an identifier for it.
|
||
|
|
||
|
This is used in many places to identify the dependency, e.g. whether
|
||
|
two requirements should have their specifier parts merged, whether
|
||
|
two specifications would conflict with each other (because they the
|
||
|
same name but different versions).
|
||
|
"""
|
||
|
raise NotImplementedError
|
||
|
|
||
|
def get_preference(self, resolution, candidates, information):
|
||
|
"""Produce a sort key for given specification based on preference.
|
||
|
|
||
|
The preference is defined as "I think this requirement should be
|
||
|
resolved first". The lower the return value is, the more preferred
|
||
|
this group of arguments is.
|
||
|
|
||
|
:param resolution: Currently pinned candidate, or `None`.
|
||
|
:param candidates: A list of possible candidates.
|
||
|
:param information: A list of requirement information.
|
||
|
|
||
|
Each information instance is a named tuple with two entries:
|
||
|
|
||
|
* `requirement` specifies a requirement contributing to the current
|
||
|
candidate list
|
||
|
* `parent` specifies the candidate that provids (dependend on) the
|
||
|
requirement, or `None` to indicate a root requirement.
|
||
|
|
||
|
The preference could depend on a various of issues, including (not
|
||
|
necessarily in this order):
|
||
|
|
||
|
* Is this package pinned in the current resolution result?
|
||
|
* How relaxed is the requirement? Stricter ones should probably be
|
||
|
worked on first? (I don't know, actually.)
|
||
|
* How many possibilities are there to satisfy this requirement? Those
|
||
|
with few left should likely be worked on first, I guess?
|
||
|
* Are there any known conflicts for this requirement? We should
|
||
|
probably work on those with the most known conflicts.
|
||
|
|
||
|
A sortable value should be returned (this will be used as the `key`
|
||
|
parameter of the built-in sorting function). The smaller the value is,
|
||
|
the more preferred this specification is (i.e. the sorting function
|
||
|
is called with `reverse=False`).
|
||
|
"""
|
||
|
raise NotImplementedError
|
||
|
|
||
|
def find_matches(self, requirement):
|
||
|
"""Find all possible candidates that satisfy a requirement.
|
||
|
|
||
|
This should try to get candidates based on the requirement's type.
|
||
|
For VCS, local, and archive requirements, the one-and-only match is
|
||
|
returned, and for a "named" requirement, the index(es) should be
|
||
|
consulted to find concrete candidates for this requirement.
|
||
|
|
||
|
The returned candidates should be sorted by reversed preference, e.g.
|
||
|
the most preferred should be LAST. This is done so list-popping can be
|
||
|
as efficient as possible.
|
||
|
"""
|
||
|
raise NotImplementedError
|
||
|
|
||
|
def is_satisfied_by(self, requirement, candidate):
|
||
|
"""Whether the given requirement can be satisfied by a candidate.
|
||
|
|
||
|
A boolean should be returned to indicate whether `candidate` is a
|
||
|
viable solution to the requirement.
|
||
|
"""
|
||
|
raise NotImplementedError
|
||
|
|
||
|
def get_dependencies(self, candidate):
|
||
|
"""Get dependencies of a candidate.
|
||
|
|
||
|
This should return a collection of requirements that `candidate`
|
||
|
specifies as its dependencies.
|
||
|
"""
|
||
|
raise NotImplementedError
|
||
|
|
||
|
|
||
|
class AbstractResolver(object):
|
||
|
"""The thing that performs the actual resolution work.
|
||
|
"""
|
||
|
|
||
|
base_exception = Exception
|
||
|
|
||
|
def __init__(self, provider, reporter):
|
||
|
self.provider = provider
|
||
|
self.reporter = reporter
|
||
|
|
||
|
def resolve(self, requirements, **kwargs):
|
||
|
"""Take a collection of constraints, spit out the resolution result.
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
requirements : Collection
|
||
|
A collection of constraints
|
||
|
kwargs : optional
|
||
|
Additional keyword arguments that subclasses may accept.
|
||
|
|
||
|
Raises
|
||
|
------
|
||
|
self.base_exception
|
||
|
Any raised exception is guaranteed to be a subclass of
|
||
|
self.base_exception. The string representation of an exception
|
||
|
should be human readable and provide context for why it occurred.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
retval : object
|
||
|
A representation of the final resolution state. It can be any object
|
||
|
with a `mapping` attribute that is a Mapping. Other attributes can
|
||
|
be used to provide resolver-specific information.
|
||
|
|
||
|
The `mapping` attribute MUST be key-value pair is an identifier of a
|
||
|
requirement (as returned by the provider's `identify` method) mapped
|
||
|
to the resolved candidate (chosen from the return value of the
|
||
|
provider's `find_matches` method).
|
||
|
"""
|
||
|
raise NotImplementedError
|