Skip to content

Add support for layered and plugin configurations - #1543

Merged
jglogan merged 1 commit into
apple:mainfrom
noah-thor:layered-toml
May 12, 2026
Merged

Add support for layered and plugin configurations#1543
jglogan merged 1 commit into
apple:mainfrom
noah-thor:layered-toml

Conversation

@noah-thor

Copy link
Copy Markdown
Contributor

This adds support for reading configurations from a three layer hierarchy:

  1. User provided roml
  2. Install root toml
  3. Code defaults

Additionally we add some code to support plugin configurations via the ConfigurationLoader. Each plugin can provide a struct with an accompanying id that gets used to parse the scoped section of the TOML.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Motivation and Context

Allows users at install time to configure package widgets defaults without having to recompile container

Testing

  • Tested locally
  • Added/updated tests
  • Added/updated docs

This adds support for reading configurations from a three layer
hierarchy:
1. User provided roml
2. Install root toml
3. Code defaults

Additionally we add some code to support plugin configurations via the
ConfigurationLoader. Each plugin can provide a struct with an
accompanying id that gets used to parse the scoped section of the TOML.
@github-actions github-actions Bot added the cli label May 11, 2026
@github-actions

Copy link
Copy Markdown

Code Coverage

Tier Line Coverage
Unit 33.92%
Integration 20.16%
Combined 53.51%

@jglogan
jglogan self-requested a review May 12, 2026 20:00

public func run() async throws {
let containerSystemConfig: ContainerSystemConfig = try ConfigurationLoader.load()
let containerSystemConfig: ContainerSystemConfig = try await ConfigurationLoader.load()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't these not get the right environment variables for when the app root and install root are set by the user in system start since system start only sets the environment variables on the APIServer's service?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which env var do you mean? Could you give a concrete example for my understanding?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a user ran system start --app-root <test app root> --install-root <test install root>, the configuration would be loaded correctly in the system start code and any services created by APIServer. For the other CLI calls where we fallback to the default config files (aka we just call ConfigurationLoader.load()), the base config path for the app root configuration file would first check for the environment variable CONTAINER_APP_ROOT which would not be set in this shell instance (but is set in the APIServer's env), then fallback to the default ~/Library/Application\ Support/com.apple.container app root path (see here). Same for the install root.

/// - decodeErrorContext: Prefix used in the `invalidArgument` error thrown on decode failure.
private static func loadAndDecode<T: LoadableConfiguration>(
_ type: T.Type,
configurationFiles: [FilePath],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this just be

configurationFiles: [FilePath] = defaultConfigFiles()

like the other functions?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do that, but the two call sites of this private are using that same defaultConfigFiles logic so the outcome would be unchanged.

do {
try providers.append(await FileProvider<TOMLSnapshot>(filePath: path, allowMissing: true))
} catch {
throw ContainerizationError(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this and L155: if none of the files exist, we return an empty config, but if some exist and some don't we throw?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now the logic is:

  • If no files exist return T()
  • else make a provider for every file
    • providers allow for missing files via allowMissing: true, any missing files will have no change to the ConfigReader view
  • an exception is thrown in the case that creating a FileProvider causes some unexpected exception like malformed text, etc

@jglogan
jglogan merged commit a967399 into apple:main May 12, 2026
4 checks passed
katiewasnothere added a commit that referenced this pull request Jun 2, 2026
Adds new entry in NOTICE.md for the swift-configuration-toml dependency
added by #1543

Signed-off-by: Kathryn Baldauf <k_baldauf@apple.com>
@noah-thor
noah-thor deleted the layered-toml branch July 22, 2026 17:32
jianliang00 pushed a commit to jianliang00/container that referenced this pull request Aug 28, 2026
- This adds support for reading configurations from
  a three layer hierarchy:
  1. User provided TOML
  2. Install root TOML
  3. Code defaults
- We add some code to support plugin configurations
  via the ConfigurationLoader. Each plugin can provide
  a struct with an accompanying id that gets used to
  parse the scoped section of the TOML.
jianliang00 pushed a commit to jianliang00/container that referenced this pull request Aug 28, 2026
Adds new entry in NOTICE.md for the swift-configuration-toml dependency
added by apple#1543

Signed-off-by: Kathryn Baldauf <k_baldauf@apple.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants