Skip to content
Draft
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
70 changes: 70 additions & 0 deletions src/commands/runtime/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1198,6 +1198,14 @@ cp /opt/src/.tuf-staging-tmp/delegations/runtime-{runtime_uuid}.json \
)
})?;

// Device-tree overlays declared by this runtime's extensions (ENG-2134).
// Empty section - and no build-time work - unless at least one is declared.
let device_tree_overlay_section = {
let overlays =
crate::utils::device_tree_overlay::collect_for_runtime(&merged_runtime, parsed)?;
crate::utils::device_tree_overlay::render_build_section(&overlays)?
};

// Extract extension names from the `extensions` array
let mut required_extensions = HashSet::new();
let _extension_type_overrides: HashMap<String, Vec<String>> = HashMap::new();
Expand Down Expand Up @@ -2411,6 +2419,8 @@ if [ -n "${{AVOCADO_STONE_INCLUDE_PATHS:-}}" ]; then
fi
STONE_INCLUDE_FLAGS="$STONE_INCLUDE_FLAGS -i $STONE_INPUT_DIR"

STONE_OVERLAY_FLAG=""
{device_tree_overlay_section}
echo -e "\033[94m[INFO]\033[0m Running stone bundle."
echo -e " Manifest: $STONE_MANIFEST"
echo -e " Output: $STONE_AOS_OUTPUT"
Expand All @@ -2427,6 +2437,7 @@ stone bundle \
$STONE_INITRD_FLAG \
-m "$STONE_MANIFEST" \
$STONE_INCLUDE_FLAGS \
$STONE_OVERLAY_FLAG \
--partition-size "var=$FINAL_SIZE" \
-o "$STONE_AOS_OUTPUT" \
--build-dir "$STONE_BUILD_DIR"
Expand Down Expand Up @@ -2528,6 +2539,7 @@ sign_amf "$AVOCADO_MANIFEST_PATH"
manifest_section = manifest_section,
update_authority_section = update_authority_section,
docker_section = docker_section,
device_tree_overlay_section = device_tree_overlay_section,
);

Ok(script)
Expand Down Expand Up @@ -3041,6 +3053,9 @@ runtimes:
assert!(script.contains("VAR_DIR=$AVOCADO_PREFIX/runtimes/$RUNTIME_NAME/var-staging"));
assert!(script.contains("stone bundle"));
assert!(script.contains("mkfs.btrfs"));
// No overlays declared: the device-tree overlay section is inert.
assert!(!script.contains("device-tree overlays (ENG-2134)"));
assert!(script.contains("STONE_OVERLAY_FLAG=\"\""));
}

#[test]
Expand Down Expand Up @@ -3088,6 +3103,61 @@ extensions:
assert!(!script.contains("$VAR_DIR/lib/avocado/extensions/"));
}

#[test]
fn test_create_build_script_with_device_tree_overlays() {
let temp_dir = TempDir::new().unwrap();
let config_content = r#"
sdk:
image: "test-image"

connect:
org: test

runtimes:
test-runtime:
target: "x86_64"
extensions:
- test-ext

extensions:
test-ext:
version: "1.0.0"
types:
- sysext
device_tree_overlays:
- name: my-spi
src: overlays/my-spi.dtso
"#;
let config_path = create_test_config_file(&temp_dir, config_content);
let parsed: serde_yaml::Value = serde_yaml::from_str(config_content).unwrap();
let cmd = RuntimeBuildCommand::new(
"test-runtime".to_string(),
config_path,
false,
Some("x86_64".to_string()),
None,
None,
);

let config = Config::load(&cmd.config_path).unwrap();
let resolved_extensions = vec!["test-ext-1.0.0".to_string()];
let script = cmd
.create_build_script(&config, &parsed, "x86_64", &resolved_extensions)
.unwrap();

// The overlay section is emitted, builds the declared overlay via the
// SDK wrapper, and wires the delivery hook + stone --overlay before the
// bundle call.
assert!(script.contains("device-tree overlays (ENG-2134)"));
assert!(script.contains(
"avocado-dtc-overlay --name \"my-spi\" --src \"/opt/src/overlays/my-spi.dtso\""
));
assert!(script.contains("device-tree-overlay-deliver"));
assert!(script.contains("STONE_OVERLAY_FLAG=\"--overlay $DTO_FRAGMENT\""));
// And the bundle call consumes the flag.
assert!(script.contains("$STONE_OVERLAY_FLAG \\"));
}

#[test]
fn test_create_build_script_with_extension_types() {
let temp_dir = TempDir::new().unwrap();
Expand Down
50 changes: 47 additions & 3 deletions src/commands/sdk/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,17 @@ impl SdkInstallCommand {
// the parallel sysroot installs so all four can run concurrently.
let active_compile_sections =
find_active_compile_sections(&composed.merged_value, active_extensions);
let need_target_dev = config.has_compile_sections() && !active_compile_sections.is_empty();
// ENG-2134: an extension declaring device-tree overlays needs the delivery
// hook in the target-sysroot, so provision the target-sysroot even when
// there is no compile section (a no-#include overlay needs no kernel-devsrc).
let provision_dto =
!crate::utils::device_tree_overlay::active_extensions_declaring_overlays(
&composed.merged_value,
active_extensions,
)
.is_empty();
let need_target_dev =
(config.has_compile_sections() && !active_compile_sections.is_empty()) || provision_dto;

// Prepare target-dev install command if needed (CPU-only prep, no container calls)
let target_dev_command = if need_target_dev {
Expand Down Expand Up @@ -389,20 +399,36 @@ impl SdkInstallCommand {
target_sysroot_config_version,
);

// ENG-2134: the per-BSP delivery hook lands in the target-sysroot so the
// runtime build can invoke it. A BSP that ships no hook package fails the
// install here, earlier and clearer than the build-time backstop.
let dto_hook_pkg = if provision_dto {
build_package_spec_with_lock(
lock_file,
target,
&SysrootType::TargetSysroot,
crate::utils::device_tree_overlay::DELIVERY_HOOK_PACKAGE,
"*",
)
} else {
String::new()
};

let command = format!(
r#"
unset RPM_CONFIGDIR
RPM_ETCCONFIGDIR="$DNF_SDK_TARGET_PREFIX" \
$DNF_SDK_HOST $DNF_NO_SCRIPTS $DNF_SDK_TARGET_REPO_CONF \
--disablerepo=${{AVOCADO_TARGET}}-target-ext \
{} {} {} --installroot ${{AVOCADO_PREFIX}}/sdk/target-sysroot \
install {} {}
install {} {} {}
"#,
dnf_args_str,
exclude_str,
yes,
target_sysroot_pkg,
all_compile_packages.join(" ")
all_compile_packages.join(" "),
dto_hook_pkg
);

Some((
Expand Down Expand Up @@ -439,6 +465,7 @@ $DNF_SDK_HOST $DNF_NO_SCRIPTS $DNF_SDK_TARGET_REPO_CONF \
config,
&bootstrap.sdk_dependencies,
&bootstrap.extension_sdk_dependencies,
provision_dto,
&mut sdk_pkg_lock,
&bootstrap.all_sdk_package_names,
&bootstrap.sdk_sysroot,
Expand Down Expand Up @@ -1673,6 +1700,7 @@ fi
config: &Config,
sdk_dependencies: &Option<HashMap<String, serde_yaml::Value>>,
extension_sdk_dependencies: &HashMap<String, HashMap<String, serde_yaml::Value>>,
provision_dto: bool,
lock_file: &mut LockFile,
bootstrap_package_names: &[String],
sdk_sysroot: &SysrootType,
Expand Down Expand Up @@ -1712,6 +1740,22 @@ fi
sdk_package_names.extend(self.extract_package_names(ext_deps));
}

// ENG-2134: provision the SDK overlay build wrapper when any active
// extension declares device-tree overlays. Its RDEPENDS pulls
// nativesdk-dtc, and stone is a baseline SDK package, so neither is
// provisioned separately.
if provision_dto {
sdk_packages.push(build_package_spec_with_lock(
lock_file,
target,
sdk_sysroot,
crate::utils::device_tree_overlay::SDK_OVERLAY_PACKAGE,
"*",
));
sdk_package_names
.push(crate::utils::device_tree_overlay::SDK_OVERLAY_PACKAGE.to_string());
}

// Track all SDK package names for version query (bootstrap pkgs + new deps)
let mut all_sdk_package_names: Vec<String> = bootstrap_package_names.to_vec();

Expand Down
Loading
Loading