Package: hab
HabA launcher that lets you configure software distributions and how they are consumed with
dependency resolution. It provides a habitat for you to work in.Features:URIbased configuration resolution with inheritance. Makes it easy to define
generic settings, but override for child URIs.Simpleconfigurationwith json files.Site configuration, code distributions are separate from URI configurations. All of
these use a common json schema.Flexible site configuration with a minimum of environment variables.No long running python processes. The hab cli uses a shell specific script instead
of a setuptools exe. This prevents some strange behavior in the shell if the python
process is killed without exiting the new shell that python launched.Can modify the existing shell similar to how virtualenv's activate script works.Simple distribution of versions. Should not require updating of checked in files
to release a unique distro version.Easy developer testing. A developer can additional site configurations for their host.
A git checkout can be found and the version of a distro can be dynamically generated
using setuptools_scm, or explicitly set by adding a.hab_version.txtthat is not
committed to the repo.QuickstartUsing habThe general workflow for using hab is to usehab envto configure your shell, then
launch one or more aliases to work in. When done with that environment you exit it
with the shells exit command. Then you can enable another hab config with a
different URI.You should be choosing the correct URI for your current task. This makes it so if
required the underlying configuration for each task you are working on can be
configured you don't need to know that something was changed.Bash (Linux and Windows)$habenvproject_a/Seq001/S0010# Enable this environment[project_a/Seq001/S0010]$maya# Launch a hab defined alias[project_a/Seq001/S0010]$houdini# Launch a hab defined alias[project_a/Seq001/S0010]$exit# Exit out of the current hab environment$# Back at the original shell without hab config$habenvproject_a/Seq001/S0020# Switch to another task with its own config ...Command Prompt (Windows)C:\>hab env project_a/Seq001/S0010      # Enable this environment[project_a/Seq001/S0010] C:\>maya       # Launch a hab defined alias
[project_a/Seq001/S0010] C:\>houdini    # Launch a hab defined alias
[project_a/Seq001/S0010] C:\>exit       # Exit out of the current hab environment
C:\>                                    # Back at the original shell without hab configC:\>hab env project_a/Seq001/S0020      # Switch to another task with its own config ...PowerShell  (Windows)PSC:\>habenvproject_a/Seq001/S0010# Enable this environment[project_a/Seq001/S0010]C:\>maya# Launch a hab defined alias[project_a/Seq001/S0010]C:\>houdini# Launch a hab defined alias[project_a/Seq001/S0010]C:\>exit# Exit out of the current hab environmentPSC:\># Back at the original shell without hab configPSC:\>habenvproject_a/Seq001/S0020# Switch to another task with its own config ...In the above examples the user is enabling the hab environment for the
URI:project_a/Seq001/S0010, then launching the Maya and Houdini aliases.
Finally they are exiting the current URI so they can enable another URI. The user
doesn't need to worry about which version of the Maya or Houdini applications they
should launch, that is configured for them by the URI they pass tohab env.Looking up aliasesIn the previous section the use knew that they could run maya and houdini. You can
lookup the aliases for a given URI with thehab dumpcommand. An alias is a hab
controlled way to launch a application.$habdumpproject_a/Seq001/S0010
DumpofFlatConfig('project_a')------------------------------------------------------
aliases:mayamayapypiphoudinihoudini18.5
------------------------------------------------------This shows that a user has access tomaya,mayapy,pip,houdini, andhoudini18.5aliases. For this config thehoudiniandhoudini18.5aliases
end up launching the same application, SeeMultiple app versionsUser PrefsTo support reusable alias shortcuts, hab has the ability to remember a URI and
reuse it for the next run. Anywhere you pass a URI to the cli, you can pass a
dash-instead. Hab will use the saved URI.$habenv-This feature has to be enabled by the site configuration. Depending on the site config
you may need to enable it by adding--prefsafterhab.hab--prefsdump-The site configuration may also configure a timeout that will require you to re-specify
the URI after a while.If you try to use-with an expired URI, Hab will notify you and prompt you to re-specify a URI.To update the URI manually, pass--save-prefsafter hab. You can
not use-when using this option.hab--save-prefsdumpproject_a/Seq001/S0010User prefs are stored in the%LOCALAPPDATA%folder on Windows and in the user's
home directory on other platforms.InstallingHab is installed using pip. It requires python 3.6 or above. It's recommended
that you add the path to your python's bin or Scripts folder to thePATHenvironment variable so you can simply run thehabcommand.pip3 install habIf you want to make use ofjson5formatting
when creating the various json files that drives hab, you should use the optional
json5 dependency. This lets you add comments and allows for trailing commas.pip3 install hab[json5]Once hab is installed you need to point it to one or moresite configurationsusing the HAB_PATHS environment variable. Each shell/platform assigns environment
variables differently. These set the env variable for the current shell only.Bash (Linux)exportHAB_PATHS="/path/to/site_b.json:/path/to/site_a.json"Bash (Windows, cygwin)You can use windows style paths by adding double quotes around the path(s). If
specifying a unc path with backslashes, you need to escape the leading slashes,
but can leave the remaining backslashes(when double quoted). Use;for the pathsep.exportHAB_PATHS="c:\path\to\site_b.json;/c/path/to/site_a.json;\\\\server\share\path\to\site_a.json"Command Prompt (Windows)set"HAB_PATHS=c:\path\to\site_b.json;/c/path/to/site_a.json"PowerShell (Windows)$env:HAB_PATHS="c:\path\to\site_b.json;c:\path\to\site_a.json"Hab Developer QuickstartHab has some code quality automated checks and extensive unit testing setup. When
contributing, you should make sure your changes match the flake8 rules and follow
the configuredblackformatting.pre-commit hooksIt's recommended that you install the configuredpre-commithooks.
These test for and fix black and flake8 issues as well as other file checks.Use pip to install pre-commit if it's not already installed.pip3 install pre-commitInstall the hab configuration of pre-commit hooks to enable them when using git.
Run this from the root of your git checkout.pre-commit installFrom this point forward when you commit changes using git, it will pre-validate
and fix most code quality issues. Those changes are not staged so you can inspect
the changes it makes.toxWe use tox to do all unit tests using pytest and also run black and flake8 code
quality checks. You should use tox before you push your code changes to ensure
that your tests will pass when running on github.Install tox if its not already installed:pip3 install toxTo run all tests. Make sure to run tox from the root of your git checkout:toxExamples of running specific tests:tox -e py37-jsonRun just the py37-json testtox -e py39-json5Run just the py39-json5 testtox -e begin,py37-json,endShow code coverage report for just this testtox -e flake8Run the flake8 teststox -e begin,py37-json,end -- -vvEnables verbose mode for pytest. Any text after--is passed as cli arguments passed to pytestOverviewURIidentifier1/identifier2/...You specify a configuration using a simple URI of identifiers separated by a/.
Currently hab only supports absolute URI's.Examples:projectDummy/Sc001/S0001.00projectDummy/Sc001/S0001.00/AnimationprojectDummy/ThugdefaultIf the provided URI has no configurations provided, the default configuration is used.
This also supports inheritance with some special rules, seeconfig inheritancefor more details.The provided URI is always stored in theHAB_URIenvironment variable.CLIHab is designed as an api with cli support. The majority of the actual work is
done by the api so it can be used with the provided cli, or can be customized by import.
A gui version of the cli is planned in the future as a second pip package.hab env: The env command launches a new shell configured by hab. You can exit
the shell to return to the original configuration. This is how most users will interact
with hab in the command line.hab activate: Updates the current shell with the hab configuration. This is
similar to activating a virtualenv, but currently there is no way to deactivate. This is
mostly how scripts can make use of hab.hab dump: Formats the resolved configuration and prints it. Used for debugging
configurations and listing the commands available.hab launch: A shortcut forhab env --launch [alias], but automatically exits the
configured shell when the launched application exits. Returning you to your existing
shell without modification. Useful for quickly testing changes to a configuration
requiring a running an application.hab set-uri: A command that allows the user to set a default URI. This default will be
used with the dash"-"flag, which allows the user to quickly recall the saved URI.
A argument can be passed to directly set the default. Alternatively, it can be run with no
argument which will provide a prompt for the user to enter a URI. This method will display
any currently saved URI for reference.Examples:$habenvprojectDummy
$habenvprojectDummy/ThugThe cli prompt is updated while inside a hab config is active. It is[URI] [cwd]Where URI is the URI requested and cwd is the current working directory.Restoring resolved configurationUnder normal operation hab resolves the configuration it loads each time it is run.
This makes it easy to get updates to the configuration by re-launching hab. However,
if you want to load the same hab configuration at a later date or on another computer
it's possible a new distro version has been released or some config settings have
been modified. For example if you submit a render job to the farm, you want every
frame to render using the same hab configuration not what ever it happens to
resolve for that launch.To handle this the hab cli stores the current configuration in theHAB_FREEZEenvironment variable. You can even use a frozen config on other platforms as long
as you properly configureplatform_path_mapsin your site config.The cli can be used to export these freezes. This example uses the cli to save a
freeze to disk as json using dump using--format json.habdumpprojectDummy--formatfreeze>/tmp/frozen_config.jsonAnd to restore that frozen config from the json file. This works for commands
other thandump.habdump--unfreeze/tmp/frozen_config.jsonSimilarly you can save/load the encoded freeze string using--format freeze.
This is what is stored in theHAB_FREEZEenvironment variable.exportfrozen_config=$(habdumpapp/nuke13-ffreeze)habdump--unfreeze$frozen_configA freeze string is prefixed withvX:to denote the version of freeze it was
encoded with. Seehab.utils.encode_freezeandhab.utils.decode_freezeto
encode/decode each version of freeze strings.You can configure what version of freeze string is saved inHAB_FREEZEby
setting thefreeze_versionkey in your site json configuration. This should be
an int value or None. If not specified(ie None), then the default version is used.{"set":{"freeze_version":1}}APITODOConfigurationHab is configured by json files found with glob strings passed to the cli or defined
by an environment variable.Duplicate definitionsThe general rule for when hab encounters duplicated definitions is that the first
encountered object is used and any duplicates are ignored. Here are some examples
that follow that rule and links to details:Aliases:Multiple app versionsEntry Points:Hab Entry PointsSite:Siteconfig_pathsanddistro_pathshavemore complex rules.SiteHab uses theHAB_PATHenvironment variable to point to one or more site
configuration files. If the--siteoption is passed to the cli, it is used instead of
the environment variable.Each of the file paths specified are read and merged into a single site configuration
dictionary hab uses. When using multiple site json files here are some general
rules to keep in mind.The left most site configuration takes precedence for a given item.For prepend/append operations on lists, the left site file's paths will placed
on the outside of the the right site file's paths.Forplatform_path_maps, only the first key is kept and any duplicates
are discarded.The entry_pointhab.site.add_pathsis processed separately afterHAB_PATHor--sitepaths are processed, so:Each path added is treated as left most when merging into the final configuration.The entry_pointhab.site.add_pathswill be ignored for dynamically added paths.This can be used to include site files from inside of pip packages. For
example a host installed pip package may be installed in the system python,
or as a pip editable installation.Duplicate paths added dynamically are discarded keeping the first
encountered(right most).SeeDefining Environmentsfor how to structure the json
to prepend, append, set, unset values.Developers can use this to load local site configurations loading their wip code
instead of the official releases. SeeTestResolvePaths::test_pathsto see an example ofoverridingthemainsite settings.You can inspect the site settings by using thehab dump -t sorhab dump --type sitecli command. SeeTestMultipleSites::test_left_right and TestMultipleSites::test_right_leftfor an example of how these rules are applied. Here is a dump of the final result
of using all3 site json files.$cdtests/site
$hab--sitesite_left.json--sitesite_middle.json--sitesite_right.jsondump--typesite-v
DumpofSite
-------------------------------------------------------------------
HAB_PATHS:C:\blur\dev\hab_\tests\site\site_left.jsonC:\blur\dev\hab_\tests\site\site_middle.jsonC:\blur\dev\hab_\tests\site\site_right.json
config_paths:
distro_paths:
ignored_distros:release,pre
platforms:windows,osx,linux
set_value:left
test_paths:left_prependmiddle_prependright_prependright_appendmiddle_appendleft_append
platform_path_maps:host:linux:host-linux_leftwindows:host-windows_leftmid:linux:mid-linux_middlewindows:mid-windows_middlenet:linux:net-linux_rightwindows:net-windows_rightshared:linux:shared-linux_leftwindows:shared-windows_left
-------------------------------------------------------------------Note the order of left/middle/right in the test_paths variable. Also, forplatform_path_maps,hostis defined in all 3 site files, but only the first
site file with it defined is used. The other path maps are picked up from the
site file they are defined in.Platform Path MapsThe site settingplatform_path_mapsis a dictionary, the key is a unique name
for each mapping, and value is a dictionary of leading directory paths for each platform.PurePath.relative_tois used to match, so full directory names need to be used. The unique name allows
for multiple site json files to override the setting as well as converting
resolved file paths to str.format style paths ({server-main}/folder/file.txt).
If multiple site json files specify the same key, the right-most site json file
specifying that key is used. It is safe to use forward slashes for windows paths.{"append":{"platform_path_maps":{"server-main":{"linux":"/mnt/main","windows":"//example//main"},"server-dev":{"linux":"/mnt/dev","windows":"//example//dev"}}},"set":{"platforms":["linux","windows"]}}With these settings, if a path on a linux host, starts with/mnt/mainwhen
generating the corresponding windows file path it will translate it to\\example\main. Note the use ofplatformsto disable osx platform support.Hab Entry PointsThe site file can be used to replace some hab functionality with custom plugins.
These are defined in site files with the "entry_points" dictionary.Examplesite json entry_point config.{
    "prepend": {
        "entry_points": {
            // Group
            "hab.cli": {
               // Name: Object Reference
               "gui": "hab_test_entry_points:gui"
            }
        }
    }
}See theEntry points specification data modelfor details on each item.GroupDescription**kwargsReturnMultiplehab.cliUsed by the hab cli to add extra commands. This is expected to be aclick.commandorclick.groupdecorated function.Allhab.cfg.reduce.envUsed to make any modifications to a config after the global env is resolved but before aliases are resolved.cfgAllhab.cfg.reduce.finalizeUsed to make any modifications to a config after aliases are resolved and just before the the config finishes reducing.cfgAllhab.habcache_clsThe class Site uses for its habcache features. This can be used to add features to the habcache system.siteFirsthab.launch_clsUsed as the defaultclsbyhab.parsers.Config.launch()to launch aliases from inside of python. This should be a subclass of subprocess.Popen. Acomplex aliasmay override this per alias. Defaults tohab.launcher.Launcher.ExampleFirsthab.site.add_pathsDynamically prepends extrasite configuration filesto the current configuration. This entry_point is ignored for any configs added using this entry_point.siteAlistofpathlib.Pathfor existing site .json files.Allhab.site.finalizeUsed to modify site configuration files just before the site is fully initialized.siteAllhab.uri.validateUsed to validate and modify a URI. If the URI is invalid, this should raise an exception. If the URI should be modified, then return the modified URI as a string.resolver,uriUpdated URI as string or None.AllThe name of each entry point is used to de-duplicate results from multiple site json files.
This follows the general rule defined induplicate definitions.Entry_point names should start withhab.and use.between each following word
following the group specification onhttps://packaging.python.org/en/latest/specifications/entry-points/#data-model.Overriding Entry PointsWhen using multiple site config files you may end up needing to disable a entry point
in specific conditions. For example you want to enablehab-gui's cli integrationby default,
but need to disable it for linux farm nodes that have no gui enabled. If you set
a entry point's value tonullhab will ignore it and not attempt to load it.For example if you have yourHAB_PATHset toc:\hab\host.json;\\server\share\studio.json.Thehost.jsonsite file is stored on each workstation and adds distros that
are not able to be run from over the network.Thestudio.jsonsite file that is shared on the network for ease of deployment.
It is used by all hab users on all platforms to define most of the studio defaults
including adding the hab-gui cli as well as the URI configs.// studio.json
{
   "append": {
      "entry_points": {
         "cli": {
            "gui": "hab_gui.cli:gui"
         }
      }
   }
}For workstations that don't support a gui you modify the workstationshost.jsonsite file, adding a override of the value from"hab_gui.cli:gui"tonull.// host.json
{
   "append": {
      "entry_points": {
         "hab.cli": {
            "gui": null
         }
      }
   }
}Alternatively, you could create a second host site file namedc:\hab\host_no_gui.jsonput the gui disabling config in that file and on the host's you want to disable
the gui prepend toHAB_PATHS=c:\hab\host_no_gui.json;c:\hab\host.json;\\server\share\studio.json.HabcacheBy default hab has to find and process all available configs and distros every
time it's launched. This has to glob the file paths inconfig_pathsanddistro_paths, and parse each file it finds. As you add more distro versions
and configs this can slow down the launching of hab. This is especially true
when storing them on the network and when using windows.To address this you can add per-site habcache files. This is a cross-platform
collection of all of the found files for a specific site file'sconfig_pathsanddistro_pathsglob strings.To enable caching runhab cache /path/to/site_file.json. This will create a
habcache file next to thesite_file.json.It will be named matchingsite["site_cache_file_template"][0], which defaults
to{stem}.habcachewhere stem is the site filename without extension. For the
example command it would create the file/path/to/site_file.habcache. To ensure
cross platform support, make sure yourHAB_PATHSconfiguration contains all of
the requiredplatform_path_mapssite mappings.While thesite_file.habcacheexists andHAB_PATHSincludessite_file.jsonhab will use the cached value unless the--no-cacheflag is used. After adding,
updating or removing a config or distro, you will need to run thehab cachecommand to update the cache with your changes. If using a distribution ci you
should add this command call there.The habcache is cross platform as long as the hab site configuration loaded when
callinghab cachehas all of the requiredplatform_path_mapsdefined. The
cache will replace the start of file paths matching one of the current platform's
mapping values with the mappings key.Python versionHab uses shell script files instead of an entry_point executable. This allows it
to modify the existing shell(seehab activate). This has a small drawback of needing
to know what version of python to call. It relies on the assumption that you are using
hab with the default python 3 install. For example that you can callpython3 -m haborpy -3 -m habon windows. Here is a breakdown of how the python call is built by
the scripts:If theHAB_PYTHONenv var is set, its value is always used.If a virtualenv is active, thepythoncommand is used.Otherwise on linuxpython3is used, and on windowspy -3is used.Common settingscolorize: Ifhab dumpshould colorize its output for ease of reading.config_paths: Configures where URI configs are discovered. See below.distro_paths: Configures where distros discovered. See below.ignored_distros: Don't use distros that have this version number. This makes
it possible for a ci to deploy some non-versioned copies of distros next to the
distros so non-hab workflows can access known file paths. For example this could
be used to put a latest folder next to each of the releases of a distro and not
have to remove the .hab.json file in that folder.platform_path_maps: Configures mappings used to convert
paths from one operating system to another. This is used by the freeze system to
ensure that if unfrozen on another platform it will still work.platforms: A list of platforms that are supported by these hab configurations.
When using freeze, all of these platforms will be stored. Defaults to linux, osx, windows.prereleases: If pre-release distros should be allowed. Works the same aspip install --pre ....prefs_default: Controls ifuser prefscan be used and if they
are enabled by default. Ie if you can pass-for a URI. If this is set todisabled(the default), user prefs can not be used. If set to--prefs, then
user prefs are enabled by default. Conversely, if set to--no-prefsthen user
prefs are disabled by default. Users can pass either of these cli flags to hab
to override the default(as long as its not disabled.)hab --prefs dump ....prefs_uri_timeout: If a URIuser preferencewas set longer
than this duration, force the user to re-save the URI returned for-when using
the--save-prefsflag. To enable a timeout set this to a dictionary of kwargs
to initialize adatetime.timedeltaobject.site_cache_file_template: The str.format template defining the name ofhabcachefiles.config_pathsanddistro_pathstake a list of glob paths. For a given glob
string in these variables you can not have duplicate values. For configs a
duplicate is two configs with the same URI. A duplicate distro is two distros
with the same name and version. If this happens aDuplicateJsonErroris raised.
This prevents developers from copying a config and forgetting to update its context.You can however have duplicates across individual glob paths. The glob paths are processed
left to right and the first config/distro is used, any subsequent duplicates are ignored
and a warning is logged to aid in debugging. This feature allows a developer to add any
git checkouts they are working on that will be used, but still have access to all of the
global shared configs/distros they are not working on.
Seespecifying distro versionfor details on specifying a
distro version in a git repo.DistroA distro defines a application, distribution or plugin that has multiple versions. It
is mostly used to define aliases and environment variables. It can also define
additional requirements.A recommended released distro folder structure:[name]\[version]\.hab.json.
The[name]folder is referenced by one of the disto_path globs. This makes it easy
to store multiple versions of the distro. Each glob specified bydistro_pathswill
automatically have/*/.hab.jsonadded to it, so the.hab.jsonfile should
be in the root of a version folder. The root of the version folder is likely the root of
a git repo.Example .hab.json:{"name":"maya2020","version":"2020.1","environment":{"append":{"MAYA_MODULE_PATH":"{relative_root}"}},"aliases":{"windows":[["maya","C:\\Program Files\\Autodesk\\Maya2020\\bin\\maya.exe"],["mayapy","C:\\Program Files\\Autodesk\\Maya2020\\bin\\mayapy.exe"]]}}In most cases  you will not define version in.hab.json. If not defined, the
parent folder is used as the version. This makes it easy for automated deployments
without needing to modify a file checked into version control.Multiple app versionsYou will note that we are using the version of maya in name. This allows you to
provide access to multiple versions of the Maya application. Only one version of
a given distro name is going to be used so if you need access to multiple versions
of maya you must use this method. If an duplicate alias is defined, it is ignored.
The order distros are specified controls which duplicate alias is used, so make
sure the distro you want to use for a generic alias is specified before the others.
Seeapp/houdini/aandapp/houdini/bfor an example of how this
is controlled. Both of these configs end up adding the aliaseshoudini,houdini18.5andhoudini19.5, but thehoudinialias is configured differently.Specifying distro versionThere are a few ways to define a distro version, they are provided to make deployment
and development testing easy. Here is the 4 ways to define the version of a distro, the
first one found is used.The version property in.hab.json. This has some drawbacks,.hab.jsonis
likely checked into version control so modifying this requires committing changes to
the repo, or working copy changes you have to maintain.A.hab_version.txtfile next to.hab.json. The drawback to this, is that
it requires some maintenance to update, but allows you work around the issues from # 1
by not tracking this file in the repo..hab.json's parent directory name. For distribution, this is the preferred
option. You will end up needing a version folder for each deployed version of a disto
to allow you to pick the version for a given config, so this lets you specify the
version simply by copying it to the target location.setuptools_scm.get_versiongets a version from version control. This is for
developer working copies, they can simply checkout the repo and even if its not a pip
package this will resolve a valid and automatically updated version number provided the
repo follows the setuptools_scm requirements for defining version numbers.ConfigA config defines the environment to be applied. The context is picked by the provided URI.
They are mostly used todefine distros, pin those distros
to specific versions, addalias_mods, and can be used toset environment variables.A given config needs two pieces of information defined, its name and context. The
context is a list of its parents names. When joined together they will build a URI.Example project_a_thug_animation.json:{
    "name": "Animation",
    "context": ["project_a", "Thug"],
    "alias_mods": {
         // Modify this env variable only when using the maya alias
        "maya": {
            "environment": {
                "os_specific": true,
                "windows": {"append": {"MAYA_MODULE_PATH": "//server/share/project_a"}}
            }
        }
    },
    "environment": {
        "set": {
            // Explicitly set this environment variable to a value
            "STUDIO_PROJECT": "project_a"
        }
    },
    // Inherit any configurations NotSet in this file from the parent context
    "inherits": true,
    // Require any version of the Maya2020 distro
    "distros": [
        "maya2020"
    ]
}This config would have the URIproject_a/Thug/Animation.Configs supportmin_verbositywith inheritance.Config InheritanceWhen resolving a URI it will find the closest exact match, so ifproject_a/Thugis
passed but Thug does not have a config, its parent project_a is used. If there is no
config for project_a, the default config will be used.The config system has an inheritance system that follows a tree structure. If a property
ishab.NotSeton the chosen config and the config has inherit enabled the closest
parent with that property set will be used. If the root of the tree has inherit
enabled, and the property still ishab.NotSet, then thedefaulttree will be
checked.When the default tree is checked when resolving inheritance, some special rules for
matching contexts are applied. It will attempt to find the most specific context defined
in the default tree, but it will find the largest partial match for the start of each
URI identifier. In thedefault test config, you will seeSc1andSc11. The URI ofnot_a_project/Sc101would end up usingdefault/Sc1. The URInot_a_project/Sc110would usedefault/Sc11. The URInot_a_project/Sc200would
usedefault.Str FormattingThe configuration environment variables and aliases can be formatted usingstr.format. Hab extends the pythonFormat Specification Mini-Languagewith these extra features:{ANYTHING!e}:!eis a special conversion flag for Environment variables. This will
be replaced with the correct shell environment variable. For bash it becomes$ANYTHING,
in power shell$env:ANYTHING, and in command prompt%ANYTHING%.ANYTHINGis the name
of the environment variable.Hab specific variablesHab defines some specific variables. These are used when parsing an individual json file:{relative_root}: The directory name of the .json config file. Think of this as the relative path.when using the command line, but this is a clear indication that it needs to be
replaced with the dirname and not left alone.{;}: This is replaced with the path separator for the shell. Ie:for bash, and;on windows(including bash).Custom variablesYou can define custom variables in a json file by defining a "variables" dictionary.
You can use these keys in other parts of that file. AnReservedVariableNameErrorwill be raised if you try to replace hab specific variables likerelative_rootand;.{
   "name": "maya2024",
   "variables": {
     "maya_root_linux": "/usr/autodesk/maya2024/bin",
     "maya_root_windows": "C:/Program Files/Autodesk/Maya2024/bin"
   },
   "aliases": {
     "linux": [
         ["maya", {"cmd": "{maya_root_linux}/maya"}]
      ],
     "windows": [
         ["maya", {"cmd": "{maya_root_windows}\\maya.exe"}]
      ]
   }
}Themaya2024testing example shows a
way to centralize the path to the Maya bin directory. This way automated tools
can easily change the install directory of maya if it needs to be installed
into a custom location on specific workstations, or remote computers.Note: Using hard coded paths likemaya_root_windowsshould be avoided unless
you really can't userelative_root.relative_rootis more portable across
workstation setups as it doesn't require any modifications when the path changes.Min_VerbosityConfigandaliasescan be hidden depending on the
verbosity setting the user is using. The schema for this is:"min_verbosity":{"global":1,"hab":2,"hab-gui":0}Theglobalkey is used as a default value if a more specific key is requested
and not defined. Other keys can be used for more fine grained control of that
workflow. By default the targethabis used. The cli useshab.Filtering is not enabled by default, code needs to opt into it by using a with context.import hab

# Specify the target when creating the Resolver instance(defaults to "hab").
resolver = hab.Resolver(target="something")
cfg = resolver.resolve('verbosity/inherit')

# By default, nothing will be hidden
print("a:", cfg.aliases.keys())

# Enable filtering by using the verbosity_filter with context.
with hab.utils.verbosity_filter(resolver, 0):
    print("b:", cfg.aliases.keys())
with hab.utils.verbosity_filter(resolver, 1):
    print("c:", cfg.aliases.keys())Outputs:a: dict_keys(['vb_default', 'vb0', 'vb1', 'vb2', 'vb3'])
b: dict_keys(['vb_default', 'vb0'])
c: dict_keys(['vb_default', 'vb0', 'vb1'])If you use the target "hab-gui" instead of "something"a: dict_keys(['vb_default', 'vb0', 'vb1', 'vb2', 'vb3'])
b: dict_keys(['vb_default', 'vb3'])
c: dict_keys(['vb_default', 'vb2', 'vb3'])Defining AliasesAliases are used to run a program in a specific way. The hab cli creates shell
commands for each alias. Aliases are defined on distros, and per-platform.{"name":"aliased","aliases":{"windows":[["as_dict",{"cmd":["python","{relative_root}/list_vars.py"],"environment":{"prepend":{"ALIASED_GLOBAL_A":"Local A Prepend","ALIASED_LOCAL":"{relative_root}/test"}}}],["as_list",["python","{relative_root}/list_vars.py"]],["as_str","python"]]},"environment":{"set":{"ALIASED_GLOBAL_A":"Global A"}}}This example distro shows the various ways you can define aliases. Each alias is
defined as a two part list where the first item is the name of the created alias
command. The second argument is the actual command to run and configuration
definition.Ultimately all alias definitions are turned into dictionaries likeas_dict, but
you can also define aliases as lists of strings or a single string. It's
recommended that you use a list of strings for any commands that require multiple
arguments, for more details see args documentation insubprocess.Popen.Complex Aliasesas_listandas_strshow simple aliases. Ie aliases that just need to run a
command from inside the current hab environment. They inherit the environment
from the active hab config.as_dictshows a complex alias, that also inherits the environment from the
active hab config, but in this case prepends an additional value onALIASED_GLOBAL_A. While this distro is in use, the environment variableALIASED_GLOBAL_Awill be set toGlobal A. However while you are using the
aliasas_dict, the variable will be set toLocal A Prepend;Global A.Complex Aliases supports several keys:cmdis the command to run. When list or str defined aliases are resolved,
their value is stored under this key.environment: A set of env var configuration options. For details on this
format, seeDefining Environments. This is not
os_specific due to aliases already being defined per-platform.hab.launch_cls: If defined this entry_point is used instead of the Site defined
or default class specifically for launching this alias.
Seehoudinifor an example.Note: Plugins may add support for their own keys.Hab-guiadds icon and label for example.Use Case:You want to add a custom AssetResolver to USD for Maya, Houdini,
and standalone usdview. To get this to work, you need to compile your plugin
against each of these applications unique compiling requirements. This means that
you also need to set the env varPXR_PLUGINPATH_NAMEto a unique path for each
application. Maya's .mod files and houdini's plugin json files make it relatively
easy for the distro to update the global env varsMAYA_MODULE_PATHandHOUDINI_PACKAGE_DIRto application specific configs setting the env var correctly.
However, that doesn't work for the standalone usdview application which doesn't
have a robust plugin loading system that can resolve application specific dll/so
files at startup. If you were to set thePXR_PLUGINPATH_NAMEenv var globally,
it would break houdini and maya as they would try to load the standalone path.
This is where complex aliases are useful. The usd distro can define an complex
alias to launch usdview that only adds the path to your standalone plugin toPXR_PLUGINPATH_NAMEonly when that alias is launched.Alias ModsAlias mods provide a way for adistroorconfigto modify another distro's aliases. This is useful for plugins that need to modify
more than one host application independently.{"name":"aliased_mod","alias_mods":{"as_list":{"environment":{"os_specific":true,"windows":{"set":{"ALIASED_MOD_LOCAL_B":"Local Mod B"}}}}},}This example is forcing an the env varALIASED_MOD_LOCAL_BtoLocal Mod Bif
the resolved config has the aliasas_list. Assuming the above aliased and this
aliased_mod distro are loaded, then the resultingas_listcommand would now set
theALIASED_MOD_LOCAL_Benv var toLocal Mod Bbefore calling its cmd.
Currently only the environment key is supported, and is os_specific.Use Case:The complex alias use case has a drawback, it ties your usd version
to a specific usd plugin release. You likely will have multiple releases of your
plugin for the same usd version, as well as having multiple plugins you want to
version independently. To do this you can define a distro for each USD plugin,
and modify thePXR_PLUGINPATH_NAMEenv var for usdview using alias_mods.Hiding aliasesYou may find that you have to define more aliases than a regular user will
regularly need, making the dump of aliases long and hard to parse. When using
complex aliases, you can specify min_verbosity settings that will prevent showing
some of those aliases unless you enable a higher verbosity.For example all ofsite_main.json's aliases are:maya mayapy maya20 mayapy20 pip houdini houdini18.5 houdinicore houdinicore18.5 husk husk18.5While these are all useful, especially if you want to include access toMultiple versionsof maya or houdini, but in most cases
your users should only callmayaorhoudini, and don't need to call the script
aliases like mayapy, husk etc.Usingmin_verbosity, you can make it so you have to increase the
verbosity of dump's to see these advanced aliases. See.By default just show the non-versioned aliases$ hab dump default
Dump of FlatConfig('default')
-------------------------------------------
aliases:  maya houdini houdinicore
-------------------------------------------Adding a verbosity level now shows the version aliases as well$ hab dump default -v
Dump of FlatConfig('default')
--------------------------------------------------------------------------
name:  default
uri:  default
aliases:  maya maya20 houdini houdini18.5 houdinicore houdinicore18.5 husk
          husk18.5Adding another verbosity level now shows advanced aliases like mayapy and husk.$ hab dump default -vv
Dump of FlatConfig('default')
-------------------------------------------------------------------------
name:  default
uri:  default
aliases:  maya mayapy maya20 mayapy20 pip houdini houdini18.5 houdinicore
          houdinicore18.5 husk husk18.5Defining EnvironmentsTheenvironmentkey in distro and config definitions is used to configure modifications
to the resolved environment. This is stored inHabBase.environment_config."environment":{"unset":["UNSET_VARIABLE"],"set":{"MAYA_MODULE_PATH":"{relative_root}"},"append":{"MAYA_MODULE_PATH":"{relative_root}/append",},"prepend":{"MAYA_MODULE_PATH":"prepend_value"}}There are 4 valid top level keys they are processed in this order if used:unset: The names of environment variables to remove.set: Replace or set the environment variable to this value.prepend: Treat this variable as a list and insert the value at the start of the list.append: Treat this variable as a list and add the value at the end of the list.Theunsetkey stores a list of environment variable names, the rest store a dictionary
of environment variable keys and the values to store.TheHabBase.environmentproperty shows the final resolved
environment variables that will be applied. When using a resolvedFlatConfigobject,
environment also contains the merger of all environment_config definitions for alldistros. When building append and prepend environment variables it processes
each dependency in a depth-first manner.These environment variables will be directly set if there is a value, and unset if the
value is blank. Hab doesn't inherit the session/system/user environment variable
values with the exception of thePATHvariable as this would break the system.
Like Rez, the first set, prepend or append operation on a variable will replace the
existing variable value.This quote from the Rez documentation explains why:"Why does this happen? Consider PYTHONPATH - if an initial overwrite did not happen,
then any modules visible on PYTHONPATH before the rez environment was configured would
still be there. This would mean you may not have a properly configured environment. If
your system PyQt were on PYTHONPATH for example, and you used rez-env to set a
different PyQt version, an attempt to import it within the configured environment would
still, incorrectly, import the system version."If required, you can create OS specific environment variable definitions. To do this,
you nest the above structure into a dictionary with the correctwindowsorlinuxkey. You have to add a extra keyos_specificset totrueto indicate that you are
using os specific configurations."environment":{"os_specific":true,"windows":{"append":{"GOLAEM_WINDOWS_PATH":"C:\\Golaem\\Golaem-7.3.11\\Maya2020"}},"linux":{"append":{"GOLAEM_LINUX_PATH":"/Golaem/Golaem-7.3.11/Maya2020"}}}Defining DistrosThedistoskey in distro and config definitions are used to define the distro version
requirements. When a config is processed the distro requirements are evaluated recursively
to include the requirements of the latest DistroVersion matching the specifier.
This uses the pythonpackaging moduleto resolve version specifiers so you can use the same configuration syntax you
would use in a pip requirements file."distros": [
        "maya2020",
        "maya2022",
        "houdini18.5",
        "hsite",
        "animBot<=1.4",
        "studiolibrary==2.5.7.post1",
        // Use markers to only include 3ds max if hab is currently running on
        // windows. It can't be run on linux.
        "3dsmax2019;platform_system=='Windows'"
    ]The resolved versions matching the requested distros are shown in theversionsproperty.It also supportsmarkers. Hab
should support all of theofficially supported markers,
but the most common marker likely to be used with hab isplatform_system.Platform specific codeHab works on windows, linux and osx(needs tested). To make it easier to handle
platform specific code, it has all been moved intohab.utils.Platforminstead
of directly relying onsys.platform,os.path, etc. This also has the
benefit of making it so the testing suite can test that hab works on for all
platforms without needing to test your code individually on each platform.
Ultimately we still need to test hab on each platform individually, but this
should help reduce surprises when the CI/CD runs the tests on a platform you
don't have easy access to when developing.Hab can be forced to simulate being run on a different platform by replacing
the Platform object.hab.utils.Platform=hab.utils.WinPlatformhab.utils.Platform=utils.BasePlatform.get_platform('osx')# Restore the current platformhab.utils.Platform=BasePlatform.get_platform()When working with tests, its recommended that you use the monkeypatch fixture.monkeypatch.setattr(utils,"Platform",utils.LinuxPlatform)monkeypatch.setattr(utils,"Platform",utils.WinPlatform)DebuggingDebugging generated scriptsHab doesn't use a console_script entry point to create an exe for its cli. It uses a shell
specificlaunch script. This script runs hab as a python process to create
temporary shell scripts to configure the shell(launching a new one if required).
This prevents the need to keep the python process running and prevents shell
corruption if that python process is killed. The shell scripts are written to the
temp location for the shell/os. On windows this should be written to%tmp%and$TMPDIRon linux.Hab does its best to remove these temp script files on exit so inspecting them can be
difficult. The best way to view them is to run ahab envorhab launchcommand
this will leave the hab process running while you find and view the config and launch
scripts in the temp directory. Once you are finished exit the hab process and they
will be removed. Alternatively if you use the--dump-scriptsflag on hab commands
that write scripts, to make it print the contents of every file to the shell
instead of writing them to disk.Logging configurationHab uses python's logging module to output a ton of debugging information. For the
most part you can control the output using thehab -v ...verbosity option.
However if you need more fine grained control you can create a.hab_logging_prefs.jsonfile next to your useruser prefsfile. The cli also supports passing
the path to a configuration file usinghab --logging-config [path/to/file.json]that is used instead of the default file if pased.CaveatsUsinghab activatein the command prompt is disabled. Batch doesn't have a function
feature like the other shells, so each alias is its own .bat file in a directory
prepended to the PATH environment variable. Hab needs to clean up its temp scripts
and due to how activate works, there isn't currently a method to do this. We don't
use doskey so we can support complex aliases.Powershell disables running .ps1 scripts disabled by default. If you get a error likehab.ps1 cannot be loaded because running scripts is disabled on this system., you will
need to launch the Powershell with this commandpowershell -ExecutionPolicy Unrestricted.
You can administratively default the execution policy to unrestricted for windows.To usehab activatein bash or Powershell you need to use.orsource. Powershell
has the.operator so I would use that for both Powershell and bash.. hab activate default.Jinja2 and MarkupSafe minimum requirements should be respected. This allows hab
to work with Houdini 19.5 that ships with very dated versions of these packages.
In practice this just means that we have to cast pathlib objects to strings before
passing them to Jinja2.Glosaryactivate:Update the current process(shell) for a given configuration. Name taken
from virtualenv.env:In the cli this launches a new process for a given configuration. Name taken
from rez.config:Defines the environment variables and distros that should be used when a
specific URI is requested.distro:Defines environment variables and aliases that a specific application or
plugin requires, and other distros that it depends on.site:Apply specific settings to hab. Where to find distros and configs, etc.URI:A/separated list of identifiers used to choose a specific config.Future PlansSupport per-alias environment variable manipulation. This will allow us to prepend to
PATH if required per-dcc. Ie only addC:\Program Files\Chaos Group\V-Ray\3ds Max 2019\binto PATH, if and only if using launching 3ds Max any time its included in the distros.Add support for~and using environment variables in config and distro path resolution.Add pkg_resource plugin interfaces that will allow customization. For example, how
configurations are defined. Allowing the use of site specific database integrations etc.