mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-29 16:13:27 +00:00
Implement bundle content digest and cache
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
a685253a1a
commit
d98ed8cec1
@ -10,7 +10,10 @@ use std::{
|
||||
use linux_bzimage_builder::{legacy32_rust_target_json, make_bzimage, BzImageType};
|
||||
|
||||
use crate::{
|
||||
bin::{AsterBin, AsterBinType, AsterBzImageMeta, AsterElfMeta},
|
||||
bundle::{
|
||||
bin::{AsterBin, AsterBinType, AsterBzImageMeta, AsterElfMeta},
|
||||
file::BundleFile,
|
||||
},
|
||||
config_manager::boot::BootProtocol,
|
||||
utils::get_current_crate_info,
|
||||
};
|
||||
@ -52,30 +55,35 @@ pub fn make_install_bzimage(
|
||||
let install_path = install_dir.as_ref().join(target_name);
|
||||
info!("Building bzImage");
|
||||
println!("install_path: {:?}", install_path);
|
||||
make_bzimage(&install_path, image_type, &aster_elf.path, &setup_bin);
|
||||
make_bzimage(&install_path, image_type, aster_elf.path(), &setup_bin);
|
||||
|
||||
AsterBin {
|
||||
path: install_path,
|
||||
typ: AsterBinType::BzImage(AsterBzImageMeta {
|
||||
AsterBin::new(
|
||||
&install_path,
|
||||
AsterBinType::BzImage(AsterBzImageMeta {
|
||||
support_legacy32_boot: matches!(protocol, BootProtocol::LinuxLegacy32),
|
||||
support_efi_boot: false,
|
||||
support_efi_handover: matches!(protocol, BootProtocol::LinuxEfiHandover64),
|
||||
}),
|
||||
version: aster_elf.version.clone(),
|
||||
sha256sum: "TODO".to_string(),
|
||||
stripped: aster_elf.stripped,
|
||||
}
|
||||
aster_elf.version().clone(),
|
||||
aster_elf.stripped(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn strip_elf_for_qemu(install_dir: impl AsRef<Path>, elf: &AsterBin) -> AsterBin {
|
||||
let stripped_elf_path = {
|
||||
let elf_name = elf.path.file_name().unwrap().to_str().unwrap().to_string();
|
||||
let elf_name = elf
|
||||
.path()
|
||||
.file_name()
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string();
|
||||
install_dir.as_ref().join(elf_name + ".stripped.elf")
|
||||
};
|
||||
|
||||
// We use rust-strip to reduce the kernel image size.
|
||||
let status = Command::new("rust-strip")
|
||||
.arg(&elf.path)
|
||||
.arg(elf.path())
|
||||
.arg("-o")
|
||||
.arg(stripped_elf_path.as_os_str())
|
||||
.status();
|
||||
@ -112,18 +120,17 @@ pub fn strip_elf_for_qemu(install_dir: impl AsRef<Path>, elf: &AsterBin) -> Aste
|
||||
file.write_all(&bytes).unwrap();
|
||||
file.flush().unwrap();
|
||||
|
||||
AsterBin {
|
||||
path: stripped_elf_path,
|
||||
typ: AsterBinType::Elf(AsterElfMeta {
|
||||
AsterBin::new(
|
||||
&stripped_elf_path,
|
||||
AsterBinType::Elf(AsterElfMeta {
|
||||
has_linux_header: false,
|
||||
has_pvh_header: false,
|
||||
has_multiboot_header: true,
|
||||
has_multiboot2_header: true,
|
||||
}),
|
||||
version: elf.version.clone(),
|
||||
sha256sum: "TODO".to_string(),
|
||||
stripped: true,
|
||||
}
|
||||
elf.version().clone(),
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
enum SetupInstallArch {
|
||||
|
@ -7,10 +7,13 @@ use std::{
|
||||
|
||||
use super::bin::make_install_bzimage;
|
||||
use crate::{
|
||||
bin::AsterBin,
|
||||
bundle::{
|
||||
bin::AsterBin,
|
||||
file::BundleFile,
|
||||
vm_image::{AsterGrubIsoImageMeta, AsterVmImage, AsterVmImageType},
|
||||
},
|
||||
config_manager::{boot::BootProtocol, BuildConfig},
|
||||
utils::get_current_crate_info,
|
||||
vm_image::{AsterGrubIsoImageMeta, AsterVmImage, AsterVmImageType},
|
||||
};
|
||||
|
||||
pub fn create_bootdev_image(
|
||||
@ -46,7 +49,7 @@ pub fn create_bootdev_image(
|
||||
BootProtocol::Multiboot | BootProtocol::Multiboot2 => {
|
||||
// Copy the kernel image to the boot directory.
|
||||
let target_path = iso_root.join("boot").join(&target_name);
|
||||
fs::copy(&aster_bin.path, target_path).unwrap();
|
||||
fs::copy(aster_bin.path(), target_path).unwrap();
|
||||
}
|
||||
};
|
||||
|
||||
@ -77,14 +80,13 @@ pub fn create_bootdev_image(
|
||||
panic!("Failed to run {:#?}.", grub_mkrescue_cmd);
|
||||
}
|
||||
|
||||
AsterVmImage {
|
||||
path: iso_path.clone(),
|
||||
typ: AsterVmImageType::GrubIso(AsterGrubIsoImageMeta {
|
||||
AsterVmImage::new(
|
||||
iso_path,
|
||||
AsterVmImageType::GrubIso(AsterGrubIsoImageMeta {
|
||||
grub_version: get_grub_mkrescue_version(grub_mkrescue_bin),
|
||||
}),
|
||||
aster_version: aster_bin.version.clone(),
|
||||
sha256sum: "TODO".to_string(),
|
||||
}
|
||||
aster_bin.version().clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn generate_grub_cfg(
|
||||
|
@ -14,8 +14,11 @@ use bin::strip_elf_for_qemu;
|
||||
use super::utils::{cargo, COMMON_CARGO_ARGS, DEFAULT_TARGET_RELPATH};
|
||||
use crate::{
|
||||
base_crate::new_base_crate,
|
||||
bin::{AsterBin, AsterBinType, AsterElfMeta},
|
||||
bundle::{Bundle, BundleManifest},
|
||||
bundle::{
|
||||
bin::{AsterBin, AsterBinType, AsterElfMeta},
|
||||
file::Initramfs,
|
||||
Bundle,
|
||||
},
|
||||
cli::CargoArgs,
|
||||
config_manager::{qemu::QemuMachine, BuildConfig},
|
||||
error::Errno,
|
||||
@ -70,30 +73,31 @@ pub fn do_build(
|
||||
cargo_target_directory: impl AsRef<Path>,
|
||||
config: &BuildConfig,
|
||||
) -> Bundle {
|
||||
if bundle_path.as_ref().exists() {
|
||||
std::fs::remove_dir_all(&bundle_path).unwrap();
|
||||
}
|
||||
let mut bundle = Bundle::new(
|
||||
&bundle_path,
|
||||
config.manifest.kcmd_args.clone(),
|
||||
config.manifest.boot.clone(),
|
||||
config.manifest.qemu.clone(),
|
||||
config.cargo_args.clone(),
|
||||
);
|
||||
|
||||
if let Some(ref initramfs) = config.manifest.initramfs {
|
||||
if !initramfs.exists() {
|
||||
error_msg!("initramfs file not found: {}", initramfs.display());
|
||||
process::exit(Errno::BuildCrate as _);
|
||||
}
|
||||
bundle.add_initramfs(Initramfs::new(initramfs));
|
||||
};
|
||||
let mut bundle = Bundle::new(
|
||||
BundleManifest {
|
||||
kcmd_args: config.manifest.kcmd_args.clone(),
|
||||
initramfs: config.manifest.initramfs.clone(),
|
||||
aster_bin: None,
|
||||
vm_image: None,
|
||||
boot: config.manifest.boot.clone(),
|
||||
qemu: config.manifest.qemu.clone(),
|
||||
cargo_args: config.cargo_args.clone(),
|
||||
},
|
||||
&bundle_path,
|
||||
);
|
||||
|
||||
info!("Building kernel ELF");
|
||||
let aster_elf = build_kernel_elf(&config.cargo_args, &cargo_target_directory);
|
||||
|
||||
if matches!(config.manifest.qemu.machine, QemuMachine::Microvm) {
|
||||
let stripped_elf = strip_elf_for_qemu(&osdk_target_directory, &aster_elf);
|
||||
bundle.add_aster_bin(&stripped_elf);
|
||||
bundle.consume_aster_bin(stripped_elf);
|
||||
}
|
||||
|
||||
// TODO: A boot device is required if we use GRUB. Actually you can boot
|
||||
@ -107,7 +111,7 @@ pub fn do_build(
|
||||
config.manifest.initramfs.as_ref(),
|
||||
config,
|
||||
);
|
||||
bundle.add_vm_image(&bootdev_image);
|
||||
bundle.consume_vm_image(bootdev_image);
|
||||
}
|
||||
|
||||
bundle
|
||||
@ -141,16 +145,15 @@ fn build_kernel_elf(args: &CargoArgs, cargo_target_directory: impl AsRef<Path>)
|
||||
}
|
||||
.join(get_current_crate_info().name);
|
||||
|
||||
AsterBin {
|
||||
path: aster_bin_path,
|
||||
typ: AsterBinType::Elf(AsterElfMeta {
|
||||
AsterBin::new(
|
||||
aster_bin_path,
|
||||
AsterBinType::Elf(AsterElfMeta {
|
||||
has_linux_header: false,
|
||||
has_pvh_header: false,
|
||||
has_multiboot_header: true,
|
||||
has_multiboot2_header: true,
|
||||
}),
|
||||
version: get_current_crate_info().version,
|
||||
sha256sum: "TODO".to_string(),
|
||||
stripped: false,
|
||||
}
|
||||
get_current_crate_info().version,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
@ -14,9 +14,10 @@ fn kernel_main() -> ! {
|
||||
}
|
||||
|
||||
#[cfg(ktest)]
|
||||
mod test {
|
||||
mod tests {
|
||||
#[ktest]
|
||||
fn trivial_test() {
|
||||
assert_eq!(1 + 1, 2);
|
||||
fn it_works() {
|
||||
let memory_regions = aster_frame::boot::memory_regions();
|
||||
assert!(!memory_regions.is_empty());
|
||||
}
|
||||
}
|
||||
|
@ -30,10 +30,8 @@ pub fn execute_new_command(args: &NewArgs) {
|
||||
|
||||
/// OSDK assumes that the toolchain used by the kernel should be same same as the toolchain
|
||||
/// specified in the asterinas workspace.
|
||||
macro_rules! aster_rust_toolchain {
|
||||
() => {
|
||||
include_str!("../../../../rust-toolchain.toml")
|
||||
};
|
||||
fn aster_rust_toolchain() -> &'static str {
|
||||
include_str!("../../../../rust-toolchain.toml")
|
||||
}
|
||||
|
||||
fn add_manifest_dependencies(cargo_metadata: &serde_json::Value, crate_name: &str) {
|
||||
@ -126,7 +124,7 @@ fn add_rust_toolchain(cargo_metadata: &serde_json::Value) {
|
||||
return;
|
||||
}
|
||||
|
||||
let contents = aster_rust_toolchain!();
|
||||
let contents = aster_rust_toolchain();
|
||||
fs::write(rust_toolchain_path, contents).unwrap();
|
||||
}
|
||||
|
||||
@ -177,7 +175,7 @@ fn get_package_metadata<'a>(
|
||||
|
||||
fn check_rust_toolchain(toolchain: &toml::Table) {
|
||||
let expected = {
|
||||
let contents = aster_rust_toolchain!();
|
||||
let contents = aster_rust_toolchain();
|
||||
toml::Table::from_str(contents).unwrap()
|
||||
};
|
||||
|
||||
|
@ -1,9 +1,15 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
time::{Duration, SystemTime},
|
||||
};
|
||||
|
||||
use super::{build::create_base_and_build, utils::DEFAULT_TARGET_RELPATH};
|
||||
use crate::{
|
||||
bundle::Bundle,
|
||||
config_manager::{BuildConfig, RunConfig},
|
||||
utils::{get_current_crate_info, get_target_directory},
|
||||
utils::{get_cargo_metadata, get_current_crate_info, get_target_directory},
|
||||
};
|
||||
|
||||
pub fn execute_run_command(config: &RunConfig) {
|
||||
@ -11,13 +17,34 @@ pub fn execute_run_command(config: &RunConfig) {
|
||||
let osdk_target_directory = ws_target_directory.join(DEFAULT_TARGET_RELPATH);
|
||||
let target_name = get_current_crate_info().name;
|
||||
let default_bundle_directory = osdk_target_directory.join(target_name);
|
||||
let existing_bundle = Bundle::load(&default_bundle_directory);
|
||||
|
||||
// If the source is not since modified and the last build is recent, we can reuse the existing bundle.
|
||||
if let Some(existing_bundle) = existing_bundle {
|
||||
if existing_bundle.can_run_with_config(config) {
|
||||
if let Ok(built_since) =
|
||||
SystemTime::now().duration_since(existing_bundle.last_modified_time())
|
||||
{
|
||||
if built_since < Duration::from_secs(600) {
|
||||
let workspace_root = {
|
||||
let meta = get_cargo_metadata(None::<&str>, None::<&[&str]>).unwrap();
|
||||
PathBuf::from(meta.get("workspace_root").unwrap().as_str().unwrap())
|
||||
};
|
||||
if get_last_modified_time(workspace_root) < existing_bundle.last_modified_time()
|
||||
{
|
||||
existing_bundle.run(config);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let required_build_config = BuildConfig {
|
||||
manifest: config.manifest.clone(),
|
||||
cargo_args: config.cargo_args.clone(),
|
||||
};
|
||||
|
||||
// TODO: Check if the bundle is already built and compatible with the run configuration.
|
||||
let bundle = create_base_and_build(
|
||||
default_bundle_directory,
|
||||
&osdk_target_directory,
|
||||
@ -27,3 +54,21 @@ pub fn execute_run_command(config: &RunConfig) {
|
||||
|
||||
bundle.run(config);
|
||||
}
|
||||
|
||||
fn get_last_modified_time(path: impl AsRef<Path>) -> SystemTime {
|
||||
let mut last_modified = SystemTime::UNIX_EPOCH;
|
||||
for entry in std::fs::read_dir(path).unwrap() {
|
||||
let entry = entry.unwrap();
|
||||
if entry.file_name() == "target" {
|
||||
continue;
|
||||
}
|
||||
|
||||
let metadata = entry.metadata().unwrap();
|
||||
if metadata.is_dir() {
|
||||
last_modified = std::cmp::max(last_modified, get_last_modified_time(&entry.path()));
|
||||
} else {
|
||||
last_modified = std::cmp::max(last_modified, metadata.modified().unwrap());
|
||||
}
|
||||
}
|
||||
last_modified
|
||||
}
|
||||
|
Reference in New Issue
Block a user