bugfix: concrete dependencies are now copied properly.
- Dependencies in concrete specs did not previously have their cache fields (_concrete, _normal, etc.) preserved. - _dup and _dup_deps weren't passing each other enough information to preserve concreteness properly, so only the root was properly preserved. - cached concreteness is now preserved properly for the entire DAG, not just the root. - added method docs.
This commit is contained in:
parent
14cd73ed3c
commit
8c42aed9d5
1 changed files with 45 additions and 26 deletions
|
@ -2542,7 +2542,7 @@ def virtual_dependencies(self):
|
||||||
"""Return list of any virtual deps in this spec."""
|
"""Return list of any virtual deps in this spec."""
|
||||||
return [spec for spec in self.traverse() if spec.virtual]
|
return [spec for spec in self.traverse() if spec.virtual]
|
||||||
|
|
||||||
def _dup(self, other, deps=True, cleardeps=True):
|
def _dup(self, other, deps=True, cleardeps=True, caches=None):
|
||||||
"""Copy the spec other into self. This is an overwriting
|
"""Copy the spec other into self. This is an overwriting
|
||||||
copy. It does not copy any dependents (parents), but by default
|
copy. It does not copy any dependents (parents), but by default
|
||||||
copies dependencies.
|
copies dependencies.
|
||||||
|
@ -2557,6 +2557,10 @@ def _dup(self, other, deps=True, cleardeps=True):
|
||||||
cleardeps (bool): if True clears the dependencies of ``self``,
|
cleardeps (bool): if True clears the dependencies of ``self``,
|
||||||
before possibly copying the dependencies of ``other`` onto
|
before possibly copying the dependencies of ``other`` onto
|
||||||
``self``
|
``self``
|
||||||
|
caches (bool or None): preserve cached fields such as
|
||||||
|
``_normal``, ``_concrete``, and ``_cmp_key_cache``. By
|
||||||
|
default this is ``False`` if DAG structure would be
|
||||||
|
changed by the copy, ``True`` if it's an exact copy.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
True if ``self`` changed because of the copy operation,
|
True if ``self`` changed because of the copy operation,
|
||||||
|
@ -2594,21 +2598,20 @@ def _dup(self, other, deps=True, cleardeps=True):
|
||||||
self.external_module = other.external_module
|
self.external_module = other.external_module
|
||||||
self.namespace = other.namespace
|
self.namespace = other.namespace
|
||||||
|
|
||||||
# If we copy dependencies, preserve DAG structure in the new spec
|
# Cached fields are results of expensive operations.
|
||||||
if deps:
|
|
||||||
deptypes = alldeps # by default copy all deptypes
|
|
||||||
|
|
||||||
# if caller restricted deptypes to be copied, adjust that here.
|
|
||||||
if isinstance(deps, (tuple, list)):
|
|
||||||
deptypes = deps
|
|
||||||
|
|
||||||
self._dup_deps(other, deptypes)
|
|
||||||
|
|
||||||
# These fields are all cached results of expensive operations.
|
|
||||||
# If we preserved the original structure, we can copy them
|
# If we preserved the original structure, we can copy them
|
||||||
# safely. If not, they need to be recomputed.
|
# safely. If not, they need to be recomputed.
|
||||||
# TODO: dependency hashes can be copied more aggressively.
|
if caches is None:
|
||||||
if deps is True or deps == alldeps:
|
caches = (deps is True or deps == alldeps)
|
||||||
|
|
||||||
|
# If we copy dependencies, preserve DAG structure in the new spec
|
||||||
|
if deps:
|
||||||
|
# If caller restricted deptypes to be copied, adjust that here.
|
||||||
|
# By default, just copy all deptypes
|
||||||
|
deptypes = deps if isinstance(deps, (tuple, list)) else alldeps
|
||||||
|
self._dup_deps(other, deptypes, caches)
|
||||||
|
|
||||||
|
if caches:
|
||||||
self._hash = other._hash
|
self._hash = other._hash
|
||||||
self._cmp_key_cache = other._cmp_key_cache
|
self._cmp_key_cache = other._cmp_key_cache
|
||||||
self._normal = other._normal
|
self._normal = other._normal
|
||||||
|
@ -2621,7 +2624,7 @@ def _dup(self, other, deps=True, cleardeps=True):
|
||||||
|
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
def _dup_deps(self, other, deptypes):
|
def _dup_deps(self, other, deptypes, caches):
|
||||||
new_specs = {self.name: self}
|
new_specs = {self.name: self}
|
||||||
for dspec in other.traverse_edges(cover='edges', root=False):
|
for dspec in other.traverse_edges(cover='edges', root=False):
|
||||||
if (dspec.deptypes and
|
if (dspec.deptypes and
|
||||||
|
@ -2629,29 +2632,45 @@ def _dup_deps(self, other, deptypes):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if dspec.parent.name not in new_specs:
|
if dspec.parent.name not in new_specs:
|
||||||
new_specs[dspec.parent.name] = dspec.parent.copy(deps=False)
|
new_specs[dspec.parent.name] = dspec.parent.copy(
|
||||||
|
deps=False, caches=caches)
|
||||||
if dspec.spec.name not in new_specs:
|
if dspec.spec.name not in new_specs:
|
||||||
new_specs[dspec.spec.name] = dspec.spec.copy(deps=False)
|
new_specs[dspec.spec.name] = dspec.spec.copy(
|
||||||
|
deps=False, caches=caches)
|
||||||
|
|
||||||
new_specs[dspec.parent.name]._add_dependency(
|
new_specs[dspec.parent.name]._add_dependency(
|
||||||
new_specs[dspec.spec.name], dspec.deptypes)
|
new_specs[dspec.spec.name], dspec.deptypes)
|
||||||
|
|
||||||
def copy(self, deps=True):
|
def copy(self, deps=True, **kwargs):
|
||||||
"""Return a copy of this spec.
|
"""Make a copy of this spec.
|
||||||
|
|
||||||
By default, returns a deep copy. To control how dependencies are
|
Args:
|
||||||
copied, supply:
|
deps (bool or tuple): Defaults to True. If boolean, controls
|
||||||
|
whether dependencies are copied (copied if True). If a
|
||||||
|
tuple is provided, *only* dependencies of types matching
|
||||||
|
those in the tuple are copied.
|
||||||
|
kwargs: additional arguments for internal use (passed to ``_dup``).
|
||||||
|
|
||||||
deps=True: deep copy
|
Returns:
|
||||||
|
A copy of this spec.
|
||||||
|
|
||||||
deps=False: shallow copy (no dependencies)
|
Examples:
|
||||||
|
Deep copy with dependnecies::
|
||||||
|
|
||||||
deps=('link', 'build'):
|
spec.copy()
|
||||||
only build and link dependencies. Similar for other deptypes.
|
spec.copy(deps=True)
|
||||||
|
|
||||||
|
Shallow copy (no dependencies)::
|
||||||
|
|
||||||
|
spec.copy(deps=False)
|
||||||
|
|
||||||
|
Only build and run dependencies::
|
||||||
|
|
||||||
|
deps=('build', 'run'):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
clone = Spec.__new__(Spec)
|
clone = Spec.__new__(Spec)
|
||||||
clone._dup(self, deps=deps)
|
clone._dup(self, deps=deps, **kwargs)
|
||||||
return clone
|
return clone
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
Loading…
Reference in a new issue