Monty.Config.Source (ExTbpMonty.Core v0.1.0)

Copy Markdown View Source

Reads Monty's own Hydra/OmegaConf config files.

The promise this module exists for: a config that Monty ships can be handed to this application unchanged. Nothing here knows what an experiment means; it only knows how Hydra lays one out on disk.

What is implemented is the subset Monty actually uses (checked against its conf/ tree): a defaults: list, _self_, # @package headers, and group@package overrides. There is no override syntax, no optional: marker and no CLI group override in the tree, so none of those are invented here.

Summary

Functions

The config tree to compose from.

The Hydra config directory inside a Monty checkout.

The package a group's config lands in when the file does not say.

Names of the experiments Monty ships, relative to the experiment group and without the .yaml suffix.

The Monty inputs this application ships: the Hydra configs it composes and the snapshots it checks them against.

Loads one config file of a group.

Loads a config file by path, wherever it lives.

Parses config text as if it were the file at path.

The file a group option lives in.

The Monty checkout: a maintainer's input, never a running system's.

The snapshots to check composed configs against, shipped with them.

The snapshot directory inside a Monty checkout.

The teleop checkout to read from.

Types

config()

@type config() :: %{
  package: [String.t()] | nil,
  defaults: [default()],
  body: map() | nil,
  file: Path.t()
}

default()

@type default() ::
  :self | {:group, String.t(), String.t() | :missing, String.t() | nil}

Functions

conf_dir()

@spec conf_dir() :: Path.t()

The config tree to compose from.

The shipped copy by default; conf_dir/1 names the same tree inside a checkout, which is what a person comparing against an upstream pull wants.

conf_dir(root)

@spec conf_dir(Path.t()) :: Path.t()

The Hydra config directory inside a Monty checkout.

default_package(group)

@spec default_package(String.t()) :: [String.t()]

The package a group's config lands in when the file does not say.

Hydra's default package for - group: option is the group path with dots, so monty/connectivity lands at monty.connectivity unless a # @package header overrides it. Monty's files almost always override it; this is the fallback that makes the rule complete.

experiments(conf_dir \\ conf_dir())

@spec experiments(Path.t()) :: [String.t()]

Names of the experiments Monty ships, relative to the experiment group and without the .yaml suffix.

Nested directories (test/, tutorial/) are included with their prefix, so test/run is a name an experiment can be launched by.

inputs_root()

@spec inputs_root() :: Path.t()

The Monty inputs this application ships: the Hydra configs it composes and the snapshots it checks them against.

Copied from a checkout by mix monty.inputs and checked in, so that building the image, running the suite and running CI need no Monty checkout. :code.priv_dir/1 rather than a relative priv/, because a release runs from bin/ while its files live under lib/.

load(conf_dir, group, option)

@spec load(Path.t(), String.t(), String.t()) :: {:ok, config()} | {:error, term()}

Loads one config file of a group.

load_file(path)

@spec load_file(Path.t()) :: {:ok, config()} | {:error, term()}

Loads a config file by path, wherever it lives.

load_text(text, path \\ "<generated>")

@spec load_text(String.t(), Path.t()) :: {:ok, config()} | {:error, term()}

Parses config text as if it were the file at path.

This is what makes a generated config the same kind of thing as one Monty ships: it is composed from its text, not from a struct that would have to keep its own idea of what the text means.

path_for(conf_dir, group, option)

@spec path_for(Path.t(), String.t(), String.t()) :: Path.t()

The file a group option lives in.

root()

@spec root() :: Path.t()

The Monty checkout: a maintainer's input, never a running system's.

MONTY_SOURCE wins; otherwise ../monty-orig next to the project, which is where the reference checkout lives in this workspace. What reads it: the mix tasks that regenerate from upstream (mix monty.inputs, mix monty.module_map, mix monty.port_census) and the tests of those tasks. Reading a neighbouring checkout is a development thing — copying its files in, comparing against it — and the image does not carry one, so nothing a release runs may fall back to this path: a tool that needs documentation or roadmap data reads the project's published site, and one that needs configs reads those priv/monty already ships.

snapshots_dir()

@spec snapshots_dir() :: Path.t()

The snapshots to check composed configs against, shipped with them.

snapshots_dir(root)

@spec snapshots_dir(Path.t()) :: Path.t()

The snapshot directory inside a Monty checkout.

teleop_root()

@spec teleop_root() :: Path.t()

The teleop checkout to read from.

TELEOP_SOURCE wins; otherwise ../tbp.teleop next to the project, which is where the reference checkout lives in this workspace.