Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions docs/user/explanation/config-system.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,9 @@ These are simple structs (not maps). Later files' non-empty fields override earl
Component configuration supports a layered inheritance model. When azldev resolves the effective configuration for a component, it assembles it from multiple sources in this order (later layers override earlier ones):

1. **Distro version defaults** — the `default-component-config` defined in the distro version (e.g., `[distros.azurelinux.versions.'4.0'.default-component-config]`)
2. **Component group defaults** — the `default-component-config` from any component groups the component belongs to (applied in alphabetical order by group name)
3. **Component-specific config** — the component's own explicit configuration
2. **Project-level defaults** — the `default-component-config` defined at the project root
3. **Component group defaults** — the `default-component-config` from any component groups the component belongs to (applied in alphabetical order by group name)
4. **Component-specific config** — the component's own explicit configuration

This inheritance is applied lazily at resolution time, not at config load time.

Expand Down
10 changes: 6 additions & 4 deletions docs/user/how-to/inspect-package-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ binary-package configuration for your project without running a build.
## Background

Binary package configuration in azldev is assembled from up to four layers
(see [Package Groups](../reference/config/package-groups.md) for details):
(see [Package Groups](../reference/config/package-groups.md) and
[Config System](../explanation/config-system.md) for details):

1. Project `default-package-config`
2. Package group `default-package-config`
3. Component `default-package-config`
1. Project `default-package-config` (lowest priority)
2. Component `publish` channel settings (`publish.rpm-channel`, `publish.debuginfo-channel`) —
themselves resolved from distro defaults → project defaults → component-group defaults → component config
3. Package group `default-package-config`
4. Component `packages.<name>` override (highest priority)

`azldev package list` resolves all of these layers and prints the effective
Expand Down
9 changes: 5 additions & 4 deletions docs/user/reference/cli/azldev_package_list.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions docs/user/reference/config/component-groups.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,9 @@ defines = { azure = "1" }
When a component belongs to one or more groups, the effective configuration is assembled in this order (later layers override earlier ones):

1. Distro version `default-component-config`
2. Component group `default-component-config` (in alphabetical order by group name if multiple groups apply)
3. Component's own explicit configuration
2. Project-level `default-component-config`
3. Component group `default-component-config` (in alphabetical order by group name if multiple groups apply)
4. Component's own explicit configuration

See [Configuration Inheritance](../../explanation/config-system.md#configuration-inheritance) for the full details.

Expand Down
41 changes: 22 additions & 19 deletions docs/user/reference/config/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ A component definition tells azldev where to find the spec file, how to customiz
| Build config | `build` | [BuildConfig](#build-configuration) | No | Build-time options (macros, conditionals, check config) |
| Render config | `render` | [RenderConfig](#render-configuration) | No | Options controlling spec rendering behavior |
| Source files | `source-files` | array of [SourceFileReference](#source-file-references) | No | Additional source files to download for this component |
| Default package config | `default-package-config` | [PackageConfig](package-groups.md#package-config) | No | Default configuration applied to all binary packages produced by this component; overrides project defaults and package-group defaults |
| Package overrides | `packages` | map of string → [PackageConfig](package-groups.md#package-config) | No | Exact per-package configuration overrides; highest priority in the resolution order |

### Bare Components
Expand Down Expand Up @@ -232,16 +231,7 @@ hints = { expensive = true }

## Package Configuration

Components can customize the configuration for the binary packages they produce. There are two fields for this, applied at different levels of specificity.

### Default Package Config

The `default-package-config` field provides a component-level default that applies to **all** binary packages produced by this component. It overrides any matching [package groups](package-groups.md) but is itself overridden by the `packages` map.

```toml
[components.curl.default-package-config.publish]
channel = "rpm-base"
```
Components can customize the configuration for the binary packages they produce using the `packages` map.

### Per-Package Overrides

Expand All @@ -250,7 +240,7 @@ The `[components.<name>.packages.<pkgname>]` map lets you override config for a
```toml
# Override just one subpackage
[components.curl.packages.curl-devel.publish]
channel = "rpm-devel"
rpm-channel = "rpm-devel"
```

### Resolution Order
Expand All @@ -259,27 +249,40 @@ For each binary package produced by a component, the effective config is assembl

1. Project `default-package-config`
2. Package group containing this package name (if any)
3. Component `default-package-config`
4. Component `packages.<exact-name>` (highest priority)
3. Component `packages.<exact-name>` (highest priority)

The component's `[publish]` section provides default channels for all packages that don't have explicit overrides. See [Publish Settings](#publish-settings) for details.

See [Package Groups](package-groups.md) for the full field reference and a complete example.

### Publish Settings

The `[components.<name>.publish]` section sets default publish channels for all packages produced by this component. These channels are inherited by every binary package unless overridden by a package-group or per-package setting.

| Field | TOML Key | Type | Required | Description |
|-------|----------|------|----------|-------------|
| RPM Channel | `rpm-channel` | string | No | Default publish channel for binary (non-debuginfo) packages |
| SRPM Channel | `srpm-channel` | string | No | Publish channel for the SRPM |
| Debuginfo Channel | `debuginfo-channel` | string | No | Publish channel for debuginfo and debugsource packages |

### Example

```toml
[components.curl]

# Route all curl packages to "base" by default ...
[components.curl.default-package-config.publish]
channel = "rpm-base"
# Set component-level default channels via publish
[components.curl.publish]
rpm-channel = "rpm-base"
srpm-channel = "rpm-base-srpm"
debuginfo-channel = "rpm-base-debuginfo"

# ... but put curl-devel in the "devel" channel
[components.curl.packages.libcurl-devel.publish]
channel = "rpm-devel"
rpm-channel = "rpm-devel"

# Signal to downstream tooling that this package should not be published
[components.curl.packages.libcurl-minimal.publish]
channel = "none"
rpm-channel = "none"
```

## Source File References
Expand Down
14 changes: 7 additions & 7 deletions docs/user/reference/config/package-groups.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,16 @@ The `[package-groups.<name>.default-package-config]` section defines the configu

| Field | TOML Key | Type | Required | Description |
|-------|----------|------|----------|-------------|
| Channel | `channel` | string | No | Publish channel for this package. Use `"none"` to signal to downstream tooling that this package should not be published. |
| RPM Channel | `rpm-channel` | string | No | Publish channel for binary packages. Use `"none"` to signal to downstream tooling that this package should not be published. |
| Debuginfo Channel | `debuginfo-channel` | string | No | Publish channel for debuginfo and debugsource packages. |

## Resolution Order

When determining the effective config for a binary package, azldev applies config layers in this order — later layers override earlier ones:

1. **Project `default-package-config`** — lowest priority; applies to all packages in the project
2. **Package group** — the group (if any) whose `packages` list contains the package name
3. **Component `default-package-config`** — applies to all packages produced by that component
4. **Component `packages.<name>`** — highest priority; exact per-package override
3. **Component `packages.<name>`** — highest priority; exact per-package override

> **Note:** Each package name may appear in at most one group. Listing the same name in two groups produces a validation error.

Expand All @@ -61,14 +61,14 @@ When determining the effective config for a binary package, azldev applies confi
```toml
# Set a project-wide default channel
[default-package-config.publish]
channel = "rpm-base"
rpm-channel = "rpm-base"

[package-groups.devel-packages]
description = "Development subpackages"
packages = ["libcurl-devel", "curl-static", "wget2-devel"]

[package-groups.devel-packages.default-package-config.publish]
channel = "rpm-build-only"
rpm-channel = "rpm-build-only"

[package-groups.debug-packages]
description = "Debug info and source"
Expand All @@ -82,11 +82,11 @@ packages = [
]

[package-groups.debug-packages.default-package-config.publish]
channel = "rpm-debug"
debuginfo-channel = "rpm-debug"
```

## Related Resources

- [Project Configuration](project.md) — top-level `default-package-config` and `package-groups` fields
- [Components](components.md) — per-component `default-package-config` and `packages` overrides
- [Components](components.md) — per-component `packages` overrides and `publish` settings
- [Configuration System](../../explanation/config-system.md) — inheritance and merge behavior
31 changes: 26 additions & 5 deletions docs/user/reference/config/project.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ The following fields are nested under the `[project]` TOML section:
| Rendered specs directory | `rendered-specs-dir` | string | No | Output directory for `component render` (relative to this config file) |
| Default distro | `default-distro` | [DistroReference](distros.md#distro-references) | No | The default distro and version to use when building components |

> **Note:** `[default-package-config]` and `[package-groups]` are **top-level** TOML sections — they are not nested under `[project]`. They are documented in the sections below.
> **Note:** `[default-component-config]`, `[default-package-config]`, and `[package-groups]` are **top-level** TOML sections — they are not nested under `[project]`. They are documented in the sections below.

## Directory Paths

Expand All @@ -39,15 +39,30 @@ default-distro = { name = "azurelinux", version = "4.0" }

Components inherit their spec source and build environment from the default distro's configuration unless they override it explicitly. See [Configuration Inheritance](../../explanation/config-system.md#configuration-inheritance) for details.

## Default Component Config

The `[default-component-config]` section is a **top-level** TOML section (not nested under `[project]`). It defines the lowest-priority configuration layer applied to every component in the project before any component-group or component-level config is considered.

The most common use is to set project-wide default publish channels for all components:

```toml
[default-component-config.publish]
rpm-channel = "rpms-base"
srpm-channel = "rpms-base-srpm"
debuginfo-channel = "rpms-base-debuginfo"
```

Individual components or [component groups](component-groups.md) can override these defaults. See [Components — Publish Settings](components.md#publish-settings) for the full field reference and [Package Groups](package-groups.md#resolution-order) for the complete resolution order.

## Default Package Config

The `[default-package-config]` section is a **top-level** TOML section (not nested under `[project]`). It defines the lowest-priority configuration layer applied to every binary package produced by any component in the project. It is overridden by [package groups](package-groups.md), [component-level defaults](components.md#package-configuration), and explicit per-package overrides.
The `[default-package-config]` section is a **top-level** TOML section (not nested under `[project]`). It defines the lowest-priority configuration layer applied to every binary package produced by any component in the project. It is overridden by [package groups](package-groups.md) `default-package-config` settings and explicit per-package overrides.

The most common use is to set a project-wide default publish channel:

```toml
[default-package-config.publish]
channel = "rpm-base"
rpm-channel = "rpm-base"
```

See [Package Groups](package-groups.md#resolution-order) for the full resolution order.
Expand All @@ -70,21 +85,27 @@ work-dir = "build/work"
output-dir = "out"
default-distro = { name = "azurelinux", version = "4.0" }

[default-component-config.publish]
rpm-channel = "rpms-base"
srpm-channel = "rpms-base-srpm"
debuginfo-channel = "rpms-base-debuginfo"

[default-package-config.publish]
channel = "base"
rpm-channel = "base"

[package-groups.devel-packages]
description = "Development subpackages"
packages = ["curl-devel", "curl-static", "wget2-devel"]

[package-groups.devel-packages.default-package-config.publish]
channel = "devel"
rpm-channel = "devel"
```

## Related Resources

- [Config File Structure](config-file.md) — top-level config file layout
- [Distros](distros.md) — distro definitions referenced by `default-distro`
- [Component Groups](component-groups.md) — group-level component config overrides
- [Package Groups](package-groups.md) — full reference for `package-groups` and package config resolution
- [Components](components.md) — per-component package config overrides
- [Configuration System](../../explanation/config-system.md) — how project config merges with other files
56 changes: 38 additions & 18 deletions internal/app/azldev/cmds/component/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ type ComponentBuildResults struct {
// Absolute paths to any source RPMs built by the operation.
SRPMPaths []string `json:"srpmPaths" table:"SRPM Paths"`

// SRPMChannel is the resolved publish channel for the SRPM.
// Empty when no channel is configured.
SRPMChannel string `json:"srpmPublishChannel,omitempty" table:"SRPM Publish Channel"`

// Absolute paths to any RPMs built by the operation.
RPMPaths []string `json:"rpmPaths" table:"RPM Paths"`

Expand Down Expand Up @@ -329,6 +333,9 @@ func buildComponentUsingBuilder(
results.ComponentName = component.GetName()
results.SRPMPaths = []string{outputSourcePackagePath}

// The component is already resolved — its Publish field reflects all inherited defaults.
results.SRPMChannel = component.GetConfig().Publish.SRPMChannel

// Short circuit if we were asked only to build the SRPM.
if sourcePackageOnly {
return results, nil
Expand All @@ -345,38 +352,51 @@ func buildComponentUsingBuilder(
return results, fmt.Errorf("failed to build RPM for %#q:\n%w", component.GetName(), err)
}

// Enrich each RPM with its binary package name and resolved publish channel.
// Enrich each RPM with its binary package name and resolved publish channel,
// move RPMs into channel subdirectories, and populate the parallel result slices.
if err = resolveAndPlaceRPMs(env, component, &results, rpmsDir); err != nil {
return results, err
}

// Publish built RPMs to local repo with publish enabled.
if localRepoWithPublishPath != "" && len(results.RPMPaths) > 0 {
publishErr := publishToLocalRepo(env, results.RPMPaths, localRepoWithPublishPath)
if publishErr != nil {
return results, fmt.Errorf("failed to publish RPMs for %#q:\n%w", component.GetName(), publishErr)
}
}

return results, nil
}

// resolveAndPlaceRPMs enriches build results with per-RPM publish channels, moves RPMs into
// channel subdirectories, and populates the parallel RPMPaths/RPMChannels slices.
func resolveAndPlaceRPMs(
env *azldev.Env, component components.Component,
results *ComponentBuildResults, rpmsDir string,
) error {
var err error

results.RPMs, err = resolveRPMResults(env.FS(), results.RPMPaths, env.Config(), component.GetConfig())
if err != nil {
return results, fmt.Errorf("failed to resolve publish channels for %#q:\n%w", component.GetName(), err)
return fmt.Errorf("failed to resolve publish channels for %#q:\n%w", component.GetName(), err)
}

// Move RPMs with a channel into out/rpms/<channel>/, leaving unconfigured ones in out/rpms/.
if err = PlaceRPMsByChannel(env, results.RPMs, rpmsDir); err != nil {
return results, fmt.Errorf("failed to place RPMs by channel for %#q:\n%w", component.GetName(), err)
return fmt.Errorf("failed to place RPMs by channel for %#q:\n%w", component.GetName(), err)
}

// Sync RPMPaths to the final (possibly moved) locations.
results.RPMPaths = make([]string, len(results.RPMs))
for rpmIdx, rpm := range results.RPMs {
results.RPMPaths[rpmIdx] = rpm.Path
}

// Populate the parallel Channels slice for table display.
results.RPMChannels = make([]string, len(results.RPMs))
for rpmIdx, rpm := range results.RPMs {
results.RPMChannels[rpmIdx] = rpm.Channel
}

// Publish built RPMs to local repo with publish enabled.
if localRepoWithPublishPath != "" && len(results.RPMPaths) > 0 {
publishErr := publishToLocalRepo(env, results.RPMPaths, localRepoWithPublishPath)
if publishErr != nil {
return results, fmt.Errorf("failed to publish RPMs for %q:\n%w", component.GetName(), publishErr)
}
}

return results, nil
return nil
}

// PlaceRPMsByChannel moves each RPM with a configured channel from its initial location in
Expand Down Expand Up @@ -480,12 +500,12 @@ func resolveRPMResults(
}

if proj != nil {
pkgConfig, err := projectconfig.ResolvePackageConfig(pkgName, compConfig, proj)
channel, err := projectconfig.ResolvePackagePublishChannel(pkgName, compConfig, proj)
if err != nil {
return nil, fmt.Errorf("failed to resolve package config for %#q:\n%w", pkgName, err)
return nil, fmt.Errorf("failed to resolve publish channel for %#q:\n%w", pkgName, err)
}

rpmResult.Channel = pkgConfig.Publish.Channel
rpmResult.Channel = channel
}

rpmResults = append(rpmResults, rpmResult)
Expand Down
Loading
Loading