concretizer: refactor conditional rules to be less repetitious (#20507)
We have to repeat all the spec attributes in a number of places in
`concretize.lp`, and Spack has a fair number of spec attributes. If we
instead add some rules up front that establish equivalencies like this:
```
    node(Package) :- attr("node", Package).
    attr("node", Package) :- node(Package).
    version(Package, Version) :- attr("version", Package, Version).
    attr("version", Package, Version) :- version(Package, Version).
```
We can rewrite most of the repetitive conditions with `attr` and repeat
only for each arity (there are only 3 arities for spec attributes so far)
as opposed to each spec attribute. This makes the logic easier to read
and the rules easier to follow.
Co-authored-by: Massimiliano Culpo <massimiliano.culpo@gmail.com>
			
			
This commit is contained in:
		 Todd Gamblin
					Todd Gamblin
				
			
				
					committed by
					
						 Tamara Dahlgren
						Tamara Dahlgren
					
				
			
			
				
	
			
			
			 Tamara Dahlgren
						Tamara Dahlgren
					
				
			
						parent
						
							acd523c7f3
						
					
				
				
					commit
					1a1babe185
				
			| @@ -709,7 +709,7 @@ def package_dependencies_rules(self, pkg, tests): | |||||||
| 
 | 
 | ||||||
|                 # each independent condition has an id |                 # each independent condition has an id | ||||||
|                 self.gen.fact(fn.dependency_condition( |                 self.gen.fact(fn.dependency_condition( | ||||||
|                     dep.pkg.name, dep.spec.name, global_condition_id |                     global_condition_id, dep.pkg.name, dep.spec.name | ||||||
|                 )) |                 )) | ||||||
| 
 | 
 | ||||||
|                 for t in sorted(dep.type): |                 for t in sorted(dep.type): | ||||||
|   | |||||||
| @@ -54,10 +54,49 @@ depends_on(Package, Dependency, Type) | |||||||
|     virtual(Virtual), |     virtual(Virtual), | ||||||
|     not external(Package). |     not external(Package). | ||||||
|  |  | ||||||
|  | % Equivalencies of the form: | ||||||
|  | % | ||||||
|  | %   name(Arg1, Arg2, ...) :- attr("name", Arg1, Arg2, ...). | ||||||
|  | %   attr("name", Arg1, Arg2, ...) :- name(Arg1, Arg2, ...). | ||||||
|  | % | ||||||
|  | % These allow us to easily define conditional dependency and conflict rules | ||||||
|  | % without enumerating all spec attributes every time. | ||||||
|  | node(Package)                          :- attr("node", Package). | ||||||
|  | version(Package, Version)              :- attr("version", Package, Version). | ||||||
|  | version_satisfies(Package, Constraint) :- attr("version_satisfies", Package, Constraint). | ||||||
|  | node_platform(Package, Platform)       :- attr("node_platform", Package, Platform). | ||||||
|  | node_os(Package, OS)                   :- attr("node_os", Package, OS). | ||||||
|  | node_target(Package, Target)           :- attr("node_target", Package, Target). | ||||||
|  | node_target_satisfies(Package, Target) :- attr("node_target_satisfies", Package, Target). | ||||||
|  | variant_value(Package, Variant, Value) :- attr("variant_value", Package, Variant, Value). | ||||||
|  | variant_set(Package, Variant, Value)   :- attr("variant_set", Package, Variant, Value). | ||||||
|  | node_flag(Package, FlagType, Flag)     :- attr("node_flag", Package, FlagType, Flag). | ||||||
|  | node_compiler(Package, Compiler)       :- attr("node_compiler", Package, Compiler). | ||||||
|  | node_compiler_version(Package, Compiler, Version) | ||||||
|  |   :- attr("node_compiler_version", Package, Compiler, Version). | ||||||
|  | node_compiler_version_satisfies(Package, Compiler, Version) | ||||||
|  |   :- attr("node_compiler_version_satisfies", Package, Compiler, Version). | ||||||
|  |  | ||||||
|  | attr("node", Package)                          :- node(Package). | ||||||
|  | attr("version", Package, Version)              :- version(Package, Version). | ||||||
|  | attr("version_satisfies", Package, Constraint) :- version_satisfies(Package, Constraint). | ||||||
|  | attr("node_platform", Package, Platform)       :- node_platform(Package, Platform). | ||||||
|  | attr("node_os", Package, OS)                   :- node_os(Package, OS). | ||||||
|  | attr("node_target", Package, Target)           :- node_target(Package, Target). | ||||||
|  | attr("node_target_satisfies", Package, Target) :- node_target_satisfies(Package, Target). | ||||||
|  | attr("variant_value", Package, Variant, Value) :- variant_value(Package, Variant, Value). | ||||||
|  | attr("variant_set", Package, Variant, Value)   :- variant_set(Package, Variant, Value). | ||||||
|  | attr("node_flag", Package, FlagType, Flag)     :- node_flag(Package, FlagType, Flag). | ||||||
|  | attr("node_compiler", Package, Compiler)       :- node_compiler(Package, Compiler). | ||||||
|  | attr("node_compiler_version", Package, Compiler, Version) | ||||||
|  |   :- node_compiler_version(Package, Compiler, Version). | ||||||
|  | attr("node_compiler_version_satisfies", Package, Compiler, Version) | ||||||
|  |   :- node_compiler_version_satisfies(Package, Compiler, Version). | ||||||
|  |  | ||||||
| % if any individual condition below is true, trigger the dependency. | % if any individual condition below is true, trigger the dependency. | ||||||
| dependency_conditions(P, D, T) :- | dependency_conditions(Package, Dependency, Type) :- | ||||||
|   dependency_conditions_hold(P, D, I), |   dependency_conditions_hold(ID, Package, Dependency), | ||||||
|   dependency_type(I, T). |   dependency_type(ID, Type). | ||||||
|  |  | ||||||
| #defined dependency_type/2. | #defined dependency_type/2. | ||||||
|  |  | ||||||
| @@ -68,51 +107,23 @@ dependency_conditions(P, D, T) :- | |||||||
| % depends_on('patchelf@0.9', when='@1.0:1.1 ^python@:2') | % depends_on('patchelf@0.9', when='@1.0:1.1 ^python@:2') | ||||||
| % | % | ||||||
| % that include dependencies | % that include dependencies | ||||||
| dependency_conditions_hold(Parent, Dependency, ID) :- | dependency_conditions_hold(ID, Parent, Dependency) :- | ||||||
|   node(Package) |   attr(Name, Arg1)             : required_dependency_condition(ID, Name, Arg1); | ||||||
|     : required_dependency_condition(ID, "node", Package); |   attr(Name, Arg1, Arg2)       : required_dependency_condition(ID, Name, Arg1, Arg2); | ||||||
|   version(Package, Version) |   attr(Name, Arg1, Arg2, Arg3) : required_dependency_condition(ID, Name, Arg1, Arg2, Arg3); | ||||||
|     : required_dependency_condition(ID, "version", Package, Version); |   dependency_condition(ID, Parent, Dependency); | ||||||
|   version_satisfies(Package, Constraint) |  | ||||||
|     : required_dependency_condition(ID, "version_satisfies", Package, Constraint); |  | ||||||
|   node_platform(Package, Platform) |  | ||||||
|     : required_dependency_condition(ID, "node_platform", Package, Platform); |  | ||||||
|   node_os(Package, OS) |  | ||||||
|     : required_dependency_condition(ID, "node_os", Package, OS); |  | ||||||
|   node_target(Package, Target) |  | ||||||
|     : required_dependency_condition(ID, "node_target", Package, Target); |  | ||||||
|   variant_value(Package, Variant, Value) |  | ||||||
|     : required_dependency_condition(ID, "variant_value", Package, Variant, Value); |  | ||||||
|   node_compiler(Package, Compiler) |  | ||||||
|     : required_dependency_condition(ID, "node_compiler", Package, Compiler); |  | ||||||
|   node_compiler_version(Package, Compiler, Version) |  | ||||||
|     : required_dependency_condition(ID, "node_compiler_version", Package, Compiler, Version); |  | ||||||
|   node_compiler_version_satisfies(Package, Compiler, Version) |  | ||||||
|     : required_dependency_condition(ID, "node_compiler_version_satisfies", Package, Compiler, Version); |  | ||||||
|   node_flag(Package, FlagType, Flag) |  | ||||||
|     : required_dependency_condition(ID, "node_flag", Package, FlagType, Flag); |  | ||||||
|   dependency_condition(Parent, Dependency, ID); |  | ||||||
|   node(Parent). |   node(Parent). | ||||||
|  |  | ||||||
| #defined dependency_condition/3. | #defined dependency_condition/3. | ||||||
| #defined required_dependency_condition/3. | #defined required_dependency_condition/3. | ||||||
| #defined required_dependency_condition/4. | #defined required_dependency_condition/4. | ||||||
| #defined required_dependency_condition/5. | #defined required_dependency_condition/5. | ||||||
| #defined required_dependency_condition/5. |  | ||||||
|  |  | ||||||
| % general rules for conflicts | % general rules for conflicts | ||||||
| :- node(Package) : conflict_condition(ID, "node", Package); | :- not external(Package)        : conflict_condition(ID, "node", Package); | ||||||
|    not external(Package) : conflict_condition(ID, "node", Package); |    attr(Name, Arg1)             : conflict_condition(ID, Name, Arg1); | ||||||
|    version(Package, Version) : conflict_condition(ID, "version", Package, Version); |    attr(Name, Arg1, Arg2)       : conflict_condition(ID, Name, Arg1, Arg2); | ||||||
|    version_satisfies(Package, Constraint) : conflict_condition(ID, "version_satisfies", Package, Constraint); |    attr(Name, Arg1, Arg2, Arg3) : conflict_condition(ID, Name, Arg1, Arg2, Arg3); | ||||||
|    node_platform(Package, Platform) : conflict_condition(ID, "node_platform", Package, Platform); |  | ||||||
|    node_os(Package, OS) : conflict_condition(ID, "node_os", Package, OS); |  | ||||||
|    node_target(Package, Target) : conflict_condition(ID, "node_target", Package, Target); |  | ||||||
|    variant_value(Package, Variant, Value) : conflict_condition(ID, "variant_value", Package, Variant, Value); |  | ||||||
|    node_compiler(Package, Compiler) : conflict_condition(ID, "node_compiler", Package, Compiler); |  | ||||||
|    node_compiler_version(Package, Compiler, Version) : conflict_condition(ID, "node_compiler_version", Package, Compiler, Version); |  | ||||||
|    node_compiler_version_satisfies(Package, Compiler, Version) : conflict_condition(ID, "node_compiler_version_satisfies", Package, Compiler, Version); |  | ||||||
|    node_flag(Package, FlagType, Flag) : conflict_condition(ID, "node_flag", Package, FlagType, Flag); |  | ||||||
|    conflict(ID, Package). |    conflict(ID, Package). | ||||||
|  |  | ||||||
| #defined conflict/2. | #defined conflict/2. | ||||||
| @@ -122,63 +133,23 @@ dependency_conditions_hold(Parent, Dependency, ID) :- | |||||||
|  |  | ||||||
| % Implications from matching a dependency condition | % Implications from matching a dependency condition | ||||||
| node(Dependency) :- | node(Dependency) :- | ||||||
|   dependency_conditions_hold(Package, Dependency, ID), |   dependency_conditions_hold(ID, Package, Dependency), | ||||||
|   depends_on(Package, Dependency). |   depends_on(Package, Dependency). | ||||||
|  |  | ||||||
| version(Dependency, Version) :- | attr(Name, Arg1, Arg2) :- | ||||||
|   dependency_conditions_hold(Package, Dependency, ID), |   dependency_conditions_hold(ID, Package, Dependency), | ||||||
|   depends_on(Package, Dependency), |   depends_on(Package, Dependency), | ||||||
|   imposed_dependency_condition(ID, "version", Dependency, Version). |   imposed_dependency_condition(ID, Name, Arg1, Arg2). | ||||||
|  |  | ||||||
| version_satisfies(Dependency, Constraint) :- | attr(Name, Arg1, Arg2, Arg3) :- | ||||||
|   dependency_conditions_hold(Package, Dependency, ID), |   dependency_conditions_hold(ID, Package, Dependency), | ||||||
|   depends_on(Package, Dependency), |   depends_on(Package, Dependency), | ||||||
|   imposed_dependency_condition(ID, "version_satisfies", Dependency, Constraint). |   imposed_dependency_condition(ID, Name, Arg1, Arg2, Arg3). | ||||||
|  |  | ||||||
| node_platform(Dependency, Platform) :- |  | ||||||
|   dependency_conditions_hold(Package, Dependency, ID), |  | ||||||
|   depends_on(Package, Dependency), |  | ||||||
|   imposed_dependency_condition(ID, "node_platform", Dependency, Platform). |  | ||||||
|  |  | ||||||
| node_os(Dependency, OS) :- |  | ||||||
|   dependency_conditions_hold(Package, Dependency, ID), |  | ||||||
|   depends_on(Package, Dependency), |  | ||||||
|   imposed_dependency_condition(ID, "node_os", Dependency, OS). |  | ||||||
|  |  | ||||||
| node_target(Dependency, Target) :- |  | ||||||
|   dependency_conditions_hold(Package, Dependency, ID), |  | ||||||
|   depends_on(Package, Dependency), |  | ||||||
|   imposed_dependency_condition(ID, "node_target", Dependency, Target). |  | ||||||
|  |  | ||||||
| variant_set(Dependency, Variant, Value) :- |  | ||||||
|   dependency_conditions_hold(Package, Dependency, ID), |  | ||||||
|   depends_on(Package, Dependency), |  | ||||||
|   imposed_dependency_condition(ID, "variant_set", Dependency, Variant, Value). |  | ||||||
|  |  | ||||||
| node_compiler(Dependency, Compiler) :- |  | ||||||
|   dependency_conditions_hold(Package, Dependency, ID), |  | ||||||
|   depends_on(Package, Dependency), |  | ||||||
|   imposed_dependency_condition(ID, "node_compiler", Dependency, Compiler). |  | ||||||
|  |  | ||||||
| node_compiler_version(Dependency, Compiler, Version) :- |  | ||||||
|   dependency_conditions_hold(Package, Dependency, ID), |  | ||||||
|   depends_on(Package, Dependency), |  | ||||||
|   imposed_dependency_condition(ID, "node_compiler_version", Dependency, Compiler, Version). |  | ||||||
|  |  | ||||||
| node_compiler_version_satisfies(Dependency, Compiler, Version) :- |  | ||||||
|   dependency_conditions_hold(Package, Dependency, ID), |  | ||||||
|   depends_on(Package, Dependency), |  | ||||||
|   imposed_dependency_condition(ID, "node_compiler_version_satisfies", Dependency, Compiler, Version). |  | ||||||
|  |  | ||||||
| node_flag(Dependency, FlagType, Flag) :- |  | ||||||
|   dependency_conditions_hold(Package, Dependency, ID), |  | ||||||
|   depends_on(Package, Dependency), |  | ||||||
|   imposed_dependency_condition(ID, "node_flag", Dependency, FlagType, Flag). |  | ||||||
|  |  | ||||||
| #defined imposed_dependency_condition/4. | #defined imposed_dependency_condition/4. | ||||||
| #defined imposed_dependency_condition/5. | #defined imposed_dependency_condition/5. | ||||||
|  |  | ||||||
| % if a virtual was required by some root spec, one provider is in the DAG | % if a virtual was required by some package, one provider is in the DAG | ||||||
| 1 { node(Package) : provides_virtual(Package, Virtual) } 1 | 1 { node(Package) : provides_virtual(Package, Virtual) } 1 | ||||||
|  :- virtual_node(Virtual). |  :- virtual_node(Virtual). | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user