Skip to content

Commit

Permalink
Add omittable_distros support for configs
Browse files Browse the repository at this point in the history
  • Loading branch information
MHendricks committed Oct 8, 2024
1 parent 7d9f656 commit c2ae21d
Show file tree
Hide file tree
Showing 14 changed files with 384 additions and 5 deletions.
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1286,6 +1286,32 @@ the `-r`/`--requirement` option.
Users can see the optional distros in the dump output with verbosity level of 1
or higher. `hab dump - -v`

### Omittable Distros

The `omittable_distros` key in [config](#config) definitions are used to specify distros
that are not required to use this hab configuration. This can be used to make it
so not all hosts need to have a dcc installed. For example a producer likely will
never need to open houdini but does need access to external tools. You would need
to install Houdini(or create a empty .hab.json distro) so hab doesn't raise an
`InvalidRequirementError` when it can't find Houdini.

```json5
"distros": [
"houdini20.0==20.0.688",
"SideFXLabs20.0==20.0.506",
"python_tools"
],
"omittable_distros": [
"houdini20.0",
"SideFXLabs20.0"
]
```
This will make it so `houdini20.0` and `SideFXLabs20.0` will be loaded if found,
but if not they will be ignored. `python_tools` will always need to be installed.

Note: `omittable_distros` is a list of distro names. It does not accept specifier
arguments like `==20.0.688`.

### Platform specific code

Hab works on windows, linux and osx(needs tested). To make it easier to handle
Expand Down
11 changes: 11 additions & 0 deletions hab/parsers/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,19 @@ def load(self, filename):
data = super().load(filename)
self._alias_mods = data.get("alias_mods", NotSet)
self.inherits = data.get("inherits", NotSet)
if self.omittable_distros is NotSet:
self.omittable_distros = data.get("omittable_distros", NotSet)
return data

@hab_property(verbosity=3, process_order=50)
def omittable_distros(self):
"""A collection of distro names that are ignored if required by distros."""
return self.frozen_data.get("omittable_distros", NotSet)

@omittable_distros.setter
def omittable_distros(self, value):
self.frozen_data["omittable_distros"] = value

@hab_property(verbosity=1, group=0)
def uri(self):
# Mark uri as a HabProperty so it is included in _properties
Expand Down
4 changes: 3 additions & 1 deletion hab/parsers/flat_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,9 @@ def versions(self):
self._alias_mods = {}
self.frozen_data["versions"] = versions

reqs = self.resolver.resolve_requirements(distros)
reqs = self.resolver.resolve_requirements(
distros, omittable=self.omittable_distros
)
for req in reqs.values():
version = self.resolver.find_distro(req)
versions.append(version)
Expand Down
9 changes: 7 additions & 2 deletions hab/resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,18 +356,23 @@ def resolve(self, uri, forced_requirements=None):
if forced_requirements is not None:
self.forced_requirements = current

def resolve_requirements(self, requirements):
def resolve_requirements(self, requirements, omittable=None):
"""Recursively solve the provided requirements into a final list of requirements.
Args:
requirements (list): The requirements to resolve.
omittable (list, optional): A list of distro names that are not required.
If a suitable distro can not be found, normally an `InvalidRequirementError`
is raised. If that distro name is in this list a warning is logged instead.
Raises:
MaxRedirectError: Redirect limit reached, unable to resolve the requested
requirements.
"""

solver = Solver(requirements, self, forced=self.forced_requirements)
solver = Solver(
requirements, self, forced=self.forced_requirements, omittable=omittable
)
return solver.resolve()

def uri_validate(self, uri):
Expand Down
10 changes: 9 additions & 1 deletion hab/solvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,18 @@ class Solver(object):
forced (dict, optional): Forces this distro requirement replacing any resolved
requirements. Using this may lead to configuring your environment
incorrectly, use with caution.
omittable (list, optional): A list of distro names that are not required.
If a suitable distro can not be found, normally an `InvalidRequirementError`
is raised. If that distro name is in this list a warning is logged instead.
Attributes:
invalid (dict, optional): If a recursive requirement makes a already resolved
version invalid, that version is added to this list as an exclusive exclude.
"""

def __init__(self, requirements, resolver, forced=None):
def __init__(self, requirements, resolver, forced=None, omittable=None):
self.forced = forced if forced else {}
self.omittable = omittable if omittable else []
self.invalid = {}
self.max_redirects = 2
self.requirements = requirements
Expand Down Expand Up @@ -126,6 +130,10 @@ def _resolve(
logger.warning(f"Forced Requirement: {req}")
reported.add(name)

if name in self.omittable and name not in self.resolver.distros:
logger.warning(f"Skipping missing omitted requirement: {req}")
continue

# Update the requirement to match all current requirements
req = self.append_requirement(resolved, req)
if name in self.invalid:
Expand Down
10 changes: 10 additions & 0 deletions tests/site_omit/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
This is a isolated site configuration specifically for testing omittable_distros.
This allows for custom configuration of the default config without affecting other tests.

* The [default](configs/default.json) config defines `omittable_distros` that can be
inherited by other distros. It lists two distros that do not exist for this site.
* [omittable/defined](omittable/defined.json) defines `omittable_distros` replacing it with a modified
list of distros to omit for this URI and its children.
* [omittable/inherited](omittable/inherited.json) does not define the `omittable_distros` and inherits
from its parents which aren't defined so it finally inherits the value defined
in the `default` config.
20 changes: 20 additions & 0 deletions tests/site_omit/configs/default.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "default",
"context": [],
"inherits": false,
"distros": {
"maya2020": [
"the_dcc_plugin_a",
"the_dcc_plugin_b",
"the_dcc_plugin_c"
],
"houdini19.5": [
"the_dcc_plugin_d"
]
},
"omittable_distros": [
"missing_dcc",
"non-existent-distro",
"the_dcc_plugin_b"
]
}
25 changes: 25 additions & 0 deletions tests/site_omit/configs/omittable_defined.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "defined",
"context": ["omittable"],
"description": "This config defines omittable_distros and will ignore the default.",
"inherits": true,
"distros": {
"maya2020": [
"the_dcc_plugin_a",
"the_dcc_plugin_b",
"the_dcc_plugin_c"
],
"houdini19.5": [
"the_dcc_plugin_d"
],
"missing_dcc": [
"the_dcc_plugin_d",
"non-existent-distro"
]
},
"omittable_distros": [
"houdini19.5",
"missing_dcc",
"non-existent-distro"
]
}
16 changes: 16 additions & 0 deletions tests/site_omit/configs/omittable_inherited.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "inherited",
"context": ["omittable"],
"description": "This config doesn't define omittable_distros and will inherit from default.",
"inherits": true,
"distros": {
"maya2020": [
"the_dcc_plugin_a",
"the_dcc_plugin_b"
],
"missing_dcc": [
"the_dcc_plugin_d",
"non-existent-distro"
]
}
}
24 changes: 24 additions & 0 deletions tests/site_omit/configs/omittable_invalid.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "invalid",
"context": ["omittable"],
"description": "This config doesn't mark the distro missing_dcc as omittable_distros and will cause an InvalidRequirementError.",
"inherits": true,
"distros": {
"maya2020": [
"the_dcc_plugin_a",
"the_dcc_plugin_b",
"the_dcc_plugin_c"
],
"houdini19.5": [
"the_dcc_plugin_d"
],
"missing_dcc": [
"the_dcc_plugin_d",
"non-existent-distro"
]
},
"omittable_distros": [
"houdini19.5",
"non-existent-distro"
]
}
16 changes: 16 additions & 0 deletions tests/site_omit/site_omit.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"append": {
"config_paths": [
"{relative_root}/configs"
],
"distro_paths": [
"{relative_root}/../distros/*"
]
},
"set": {
"platforms": [
"windows",
"linux"
]
}
}
Loading

0 comments on commit c2ae21d

Please sign in to comment.