-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Finer selection of virtual providers #15569
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
33 commits
Select commit
Hold shift + click to select a range
a733857
Added a simple test for the tokenization of the new syntax
alalazo 0d6c52d
Spec with virtual dependency bindings parse correctly
alalazo 24a9431
Specs can pick which virtual they want to bind
alalazo cb6a9a5
Vendor ChainMap for Python 2.X
alalazo 014599e
Added tests for more complicated cases of bindings
alalazo 1a821b7
Declare virtual dependencies that needs to be provided together
alalazo 353a89a
Added further tests of consistency with the proposed semantics
alalazo 1bc9c68
Dict comprehension not allowed in Python 2.6
alalazo 72d4dce
Added documentation for explicit bindings of vdeps
alalazo bbaf81b
Removed leftover TODOs and FIXMEs
alalazo 5627539
Improved documentation
alalazo 424418c
chainmap: added a link to the license
alalazo bb3b938
DependencySpec: added "virtuals" as a new edge attribute
alalazo ee65bbc
provider_index: improved docstrings and variable names
alalazo ac44f4f
Modified the parser to allow for multiple bindings
alalazo b0d1e17
DependencySpec: remove default value for "virtuals" argument
alalazo 38ea0fc
Spec._dup_deps now correctly duplicates information on virtuals
alalazo 44d12b1
Keep track of virtual dependencies on DAG edges
alalazo dd11a89
Renamed dictionary from "provided_together" to "used_together"
alalazo 3bb6fbd
Handle conditionals when selecting virtual dependencies
alalazo cd54221
Renamed "virtuals" to "provides" in spec YAML dictionary
alalazo 0e4ee81
Fixed issue with test/ci.py
alalazo b2e044f
Renamed "_explicit_providers" to "_user_requested_providers"
alalazo 5cd7027
Fixed issue with reindex and a failing unit test
alalazo ef93be9
Updated documentation according to review comments
alalazo e718b3b
Spec._providers is now a private method
alalazo aedaa78
flake8: comply to new rules on variable naming
alalazo 9a18d56
Removed spurious FIXME
alalazo 8adea7a
Removed ^mpich from test spec
alalazo 263de40
Properly reconstruct virtuals on edges for old DBs
alalazo da431ce
Preserve monkeypatching of objects if name is virtual
alalazo 22a20f4
Copy specs when parsing user requested providers
alalazo 4622489
__contains__ now respect edge properties
alalazo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1167,6 +1167,56 @@ any MPI implementation will do. If another package depends on | |
| error. Likewise, if you try to plug in some package that doesn't | ||
| provide MPI, Spack will raise an error. | ||
|
|
||
| """""""""""""""""""""""""""""""""""""""" | ||
| Explicit binding of virtual dependencies | ||
| """""""""""""""""""""""""""""""""""""""" | ||
|
|
||
| There are packages that provide more than just one virtual dependency. | ||
| When interacting with them users might want to pick only | ||
| a single virtual dependency from one package and use different providers for | ||
| the others. For example, consider these two packages: | ||
|
|
||
| * ``intel-parallel-studio``, which provides ``mpi``, ``lapack``, and ``blas`` | ||
| * ``openblas``, which provides ``lapack`` and ``blas`` | ||
|
|
||
| We might want to use ``intel-parallel-studio`` for ``mpi`` and ``openblas`` | ||
| for ``lapack`` and ``blas``: | ||
|
|
||
| .. code-block:: console | ||
|
|
||
| $ spack spec netlib-scalapack ^mpi=intel-parallel-studio@cluster+mpi ^openblas | ||
| Input spec | ||
| -------------------------------- | ||
| netlib-scalapack | ||
| ^intel-parallel-studio@cluster+mpi | ||
| ^openblas | ||
|
|
||
| Concretized | ||
| -------------------------------- | ||
| [email protected]%[email protected] build_type=RelWithDebInfo patches=f2baedde688ffe4c20943c334f580eb298e04d6f35c86b90a1f4e8cb7ae344a2 ~pic+shared arch=linux-ubuntu18.04-broadwell | ||
| ^[email protected]%[email protected]~doc+ncurses+openssl+ownlibs~qt arch=linux-ubuntu18.04-broadwell | ||
| ^[email protected]%[email protected]~symlinks+termlib arch=linux-ubuntu18.04-broadwell | ||
| ^[email protected]%[email protected] arch=linux-ubuntu18.04-broadwell | ||
| ^[email protected]%[email protected]+systemcerts arch=linux-ubuntu18.04-broadwell | ||
| ^[email protected]%[email protected]+cpanm+shared+threads arch=linux-ubuntu18.04-broadwell | ||
| ^[email protected]%[email protected] arch=linux-ubuntu18.04-broadwell | ||
| ^[email protected]%[email protected] arch=linux-ubuntu18.04-broadwell | ||
| ^[email protected]%[email protected]+optimize+pic+shared arch=linux-ubuntu18.04-broadwell | ||
| ^intel-parallel-studio@cluster%[email protected]~advisor auto_dispatch=none ~clck+daal~gdb~ilp64~inspector+ipp~itac+mkl+mpi~newdtags+rpath+shared+tbb threads=none ~vtune arch=linux-ubuntu18.04-broadwell | ||
| ^[email protected]%[email protected]~consistent_fpcsr~ilp64+pic+shared threads=none arch=linux-ubuntu18.04-broadwell | ||
|
|
||
| The ``^<virtual>=<spec>`` syntax tells Spack to use ``<spec>`` to satisfy the | ||
| requested virtual (so ``^mpi=intel-parallel-studio`` tells Spack to use | ||
| ``intel-parallel-studio`` as the ``mpi`` provider) and to consider its other virtual | ||
| dependencies after any other explicitly mentioned package. Adding ``^openblas`` | ||
| to the spec thus means that ``openblas`` will then be used for ``lapack``, and | ||
| ``blas`` because it is specified explicitly. | ||
|
|
||
| In this example, that covers all the virtual dependencies, but if there were other | ||
| virtual dependencies, Spack could try to satisfy them with ``intel-parallel-studio``. | ||
| For instance, if another package depended on ``tbb`` or ``daal`` (which ``intel-parallel-studio`` | ||
| also provides), Spack could use ``intel-parallel-studio`` to satisfy them as a last resort. | ||
|
|
||
| ^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| Specifying Specs by Hash | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,154 @@ | ||
| try: | ||
| from collections.abc import MutableMapping | ||
| except ImportError: | ||
| from collections import MutableMapping | ||
|
|
||
|
|
||
| try: | ||
| from thread import get_ident | ||
| except ImportError: | ||
| try: | ||
| from threading import _get_ident as get_ident | ||
| except ImportError: | ||
| from threading import get_ident | ||
|
|
||
|
|
||
| def _recursive_repr(fillvalue='...'): | ||
| 'Decorator to make a repr function return fillvalue for a recursive call' | ||
|
|
||
| def decorating_function(user_function): | ||
| repr_running = set() | ||
|
|
||
| def wrapper(self): | ||
| key = id(self), get_ident() | ||
| if key in repr_running: | ||
| return fillvalue | ||
| repr_running.add(key) | ||
| try: | ||
| result = user_function(self) | ||
| finally: | ||
| repr_running.discard(key) | ||
| return result | ||
|
|
||
| # Can't use functools.wraps() here because of bootstrap issues | ||
| wrapper.__module__ = getattr(user_function, '__module__') | ||
| wrapper.__doc__ = getattr(user_function, '__doc__') | ||
| wrapper.__name__ = getattr(user_function, '__name__') | ||
| wrapper.__annotations__ = getattr(user_function, '__annotations__', {}) | ||
| return wrapper | ||
|
|
||
| return decorating_function | ||
|
|
||
|
|
||
| class ChainMap(MutableMapping): | ||
| """ | ||
| A ChainMap groups multiple dicts (or other mappings) together to create a | ||
| single, updateable view. | ||
|
|
||
| The underlying mappings are stored in a list. That list is public and can | ||
| accessed or updated using the *maps* attribute. There is no other state. | ||
|
|
||
| Lookups search the underlying mappings successively until a key is found. In | ||
| contrast, writes, updates, and deletions only operate on the first mapping. | ||
| """ | ||
|
|
||
| def __init__(self, *maps): | ||
| """ | ||
| Initialize a ChainMap by setting *maps* to the given mappings. | ||
| If no mappings are provided, a single empty dictionary is used. | ||
| """ | ||
| self.maps = list(maps) or [{}] # always at least one map | ||
|
|
||
| def __missing__(self, key): | ||
| raise KeyError(key) | ||
|
|
||
| def __getitem__(self, key): | ||
| for mapping in self.maps: | ||
| try: | ||
| return mapping[key] # can't use 'key in mapping' with defaultdict | ||
| except KeyError: | ||
| pass | ||
| return self.__missing__(key) # support subclasses that define __missing__ | ||
|
|
||
| def get(self, key, default=None): | ||
| return self[key] if key in self else default | ||
|
|
||
| def __len__(self): | ||
| return len(set().union(*self.maps)) # reuses stored hash values if possible | ||
|
|
||
| def __iter__(self): | ||
| return iter(set().union(*self.maps)) | ||
|
|
||
| def __contains__(self, key): | ||
| return any(key in m for m in self.maps) | ||
|
|
||
| def __bool__(self): | ||
| return any(self.maps) | ||
|
|
||
| @_recursive_repr() | ||
| def __repr__(self): | ||
| return '{0.__class__.__name__}({1})'.format( | ||
| self, ', '.join(map(repr, self.maps))) | ||
|
|
||
| @classmethod | ||
| def fromkeys(cls, iterable, *args): | ||
| "Create a ChainMap with a single dict created from the iterable." | ||
| return cls(dict.fromkeys(iterable, *args)) | ||
|
|
||
| def copy(self): | ||
| """ | ||
| New ChainMap or subclass with a new copy of ``maps[0]`` and refs | ||
| to ``maps[1:]`` | ||
| """ | ||
| return self.__class__(self.maps[0].copy(), *self.maps[1:]) | ||
|
|
||
| __copy__ = copy | ||
|
|
||
| def new_child(self, m=None): # like Django's Context.push() | ||
| """ | ||
| New ChainMap with a new map followed by all previous maps. If no | ||
| map is provided, an empty dict is used. | ||
| """ | ||
| if m is None: | ||
| m = {} | ||
| return self.__class__(m, *self.maps) | ||
|
|
||
| @property | ||
| def parents(self): # like Django's Context.pop() | ||
| "New ChainMap from ``maps[1:]``." | ||
| return self.__class__(*self.maps[1:]) | ||
|
|
||
| def __setitem__(self, key, value): | ||
| self.maps[0][key] = value | ||
|
|
||
| def __delitem__(self, key): | ||
| try: | ||
| del self.maps[0][key] | ||
| except KeyError: | ||
| raise KeyError('Key not found in the first mapping: {0!r}'.format(key)) | ||
|
|
||
| def popitem(self): | ||
| """ | ||
| Remove and return an item pair from ``maps[0]``. Raise ``KeyError`` is | ||
| ``maps[0]`` is empty. | ||
| """ | ||
| try: | ||
| return self.maps[0].popitem() | ||
| except KeyError: | ||
| raise KeyError('No keys found in the first mapping.') | ||
|
|
||
| def pop(self, key, *args): | ||
| """ | ||
| Remove ``key`` from ``maps[0]`` and return its value. Raise ``KeyError`` | ||
| if ``key`` not in ``maps[0]``. | ||
| """ | ||
| try: | ||
| return self.maps[0].pop(key, *args) | ||
| except KeyError: | ||
| raise KeyError('Key not found in the first mapping: {0!r}'.format(key)) | ||
|
|
||
| def clear(self): | ||
| """ | ||
| Clear ```maps[0]```, leaving ``maps[1:]`` intact. | ||
| """ | ||
| self.maps[0].clear() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.