mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-08 21:06:48 +00:00
Implement bundle content digest and cache
This commit is contained in:
parent
a685253a1a
commit
d98ed8cec1
2
Makefile
2
Makefile
@ -97,7 +97,7 @@ KTEST_TESTABLE := \
|
||||
all: build
|
||||
|
||||
install_osdk:
|
||||
@cargo install cargo-osdk --path osdk --force
|
||||
@cargo install cargo-osdk --path osdk
|
||||
|
||||
build:
|
||||
@make --no-print-directory -C regression
|
||||
|
78
osdk/Cargo.lock
generated
78
osdk/Cargo.lock
generated
@ -86,6 +86,15 @@ version = "2.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "1.9.1"
|
||||
@ -131,10 +140,17 @@ dependencies = [
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"toml",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.1"
|
||||
@ -181,12 +197,41 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "difflib"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "doc-comment"
|
||||
version = "0.3.3"
|
||||
@ -238,6 +283,16 @@ dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.3"
|
||||
@ -460,6 +515,17 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.0"
|
||||
@ -518,6 +584,12 @@ dependencies = [
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
@ -530,6 +602,12 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "wait-timeout"
|
||||
version = "0.2.0"
|
||||
|
@ -18,6 +18,7 @@ log = "0.4.20"
|
||||
regex = "1.10.3"
|
||||
serde = { version = "1.0.195", features = ["derive"] }
|
||||
serde_json = "1.0.111"
|
||||
sha2 = "0.10.8"
|
||||
toml = { version = "0.8.8", features = ["preserve_order"] }
|
||||
which = "6.0.0"
|
||||
|
||||
|
@ -15,15 +15,25 @@ OSDK (short for Operating System Development Kit) is designed to simplify the de
|
||||
|
||||
Currenly, `cargo-osdk` only supports x86_64 ubuntu system.
|
||||
|
||||
`cargo-osdk` requires the following tools to be installed:
|
||||
To run a kernel with QEMU, `cargo-osdk` requires the following tools to be installed:
|
||||
- Rust >= 1.75.0
|
||||
- Gcc compiler
|
||||
- cargo-binutils
|
||||
- gcc
|
||||
- qemu-system-x86_64
|
||||
- grub-mkrescue
|
||||
- ovmf
|
||||
- xorriso
|
||||
|
||||
About how to install Rust, you can refer to the [official site](https://www.rust-lang.org/tools/install).
|
||||
|
||||
Gcc compiler can be installed by
|
||||
After installing Rust, you can install Cargo tools by
|
||||
```bash
|
||||
apt install build-essential
|
||||
cargo install cargo-binutils
|
||||
```
|
||||
|
||||
Other tools can be installed by
|
||||
```bash
|
||||
apt install build-essential grub2-common qemu-system-x86 ovmf xorriso
|
||||
```
|
||||
|
||||
#### Install
|
||||
@ -44,17 +54,6 @@ cargo install --force cargo-osdk
|
||||
|
||||
Here we provide a simple demo to demonstrate how to create and run a simple kernel with `cargo-osdk`.
|
||||
|
||||
Suppose you are on a x86_64 ubuntu machine, to run a kernel with QEMU, the following tools should be installed:
|
||||
- qemu-system-x86_64
|
||||
- grub-mkrescue
|
||||
- ovmf
|
||||
- xorriso
|
||||
|
||||
If these tools are missing, they can be installed by
|
||||
```bash
|
||||
apt install grub2-common qemu-system-x86 ovmf xorriso
|
||||
```
|
||||
|
||||
With `cargo-osdk`, a kernel project can be created by one command
|
||||
```bash
|
||||
cargo osdk new --kernel my-first-os
|
||||
@ -105,15 +104,17 @@ ovmf = "/usr/bin/ovmf" # <7>
|
||||
path = "/usr/bin/qemu-system-x86_64" # <8>
|
||||
machine = "q35" # <9>
|
||||
args = [ # <10>
|
||||
"--enable-kvm",
|
||||
"-enable-kvm",
|
||||
"-m 2G",
|
||||
"--device virtio-keyboard-pci,disable-legacy=on,disable-modern=off"
|
||||
"-device virtio-keyboard-pci,disable-legacy=on,disable-modern=off"
|
||||
]
|
||||
|
||||
[qemu.'cfg(feature="iommu")'] # <11>
|
||||
path = "/usr/local/sbin/qemu-kvm" # <8>
|
||||
machine = "q35" # <9>
|
||||
args = [ # <10>
|
||||
"-enable-kvm",
|
||||
"-m 2G",
|
||||
"-device virtio-keyboard-pci,disable-legacy=on,disable-modern=off,iommu_platform=on,ats=on",
|
||||
"-device intel-iommu,intremap=on,device-iotlb=on"
|
||||
]
|
||||
@ -145,18 +146,7 @@ Optional. Default is `q35`.
|
||||
The allowed values are `q35` and `microvm`.
|
||||
10. Additional arguments passed to QEMU.
|
||||
Optional. The default value is empty.
|
||||
Each argument should be in the form `KEY VALUE` (separated by space), or `KEY` if no value is required. Some keys can appear multiple times (e.g., `--device`, `--netdev`), while other keys can appear at most once. Certain keys, such as `-cpu` and `-machine`, are not allowed to be set here as they may conflict with the internal settings of `cargo-osdk`.
|
||||
Each argument should be in the form `KEY VALUE` (separated by space), or `KEY` if no value is required. Some keys can appear multiple times (e.g., `-device`, `-netdev`), while other keys can appear at most once. Certain keys, such as `-cpu` and `-machine`, are not allowed to be set here as they may conflict with the internal settings of `cargo-osdk`.
|
||||
11. Conditional QEMU settings.
|
||||
Optional. The default value is empty.
|
||||
Conditional QEMU settings allow for a condition to be specified after `qemu`. Currently, `cargo-osdk` only supports the condition `cfg(feature="FEATURE")`, which activates the QEMU settings only if the `FEATURE` is set. The `FEATURE` must be defined in the project's `Cargo.toml`. At most one conditional setting can be activated at a time. If multiple conditional settings can be activated simultaneously, `cargo-osdk` will report an error. In the future, `cargo-osdk` will support all possible conditions that [Rust conditional compilation](https://doc.rust-lang.org/reference/conditional-compilation.html) supports.
|
||||
|
||||
|
||||
### The framekernel architecture
|
||||
|
||||
The architecture divides the OS development into two distinct realms: the safe world and the unsafe world. In the safe world, only safe Rust code is allowed, while the unsafe world can tap into the power of the unsafe keyword. At the heart of the unsafe world lies `aster-frame`, a compact framework with limited functionalities. It encapsulates essential OS operations such as booting, physical memory management, context switching, and more.
|
||||
|
||||
With `aster-frame` as the foundation, higher-level OS functionalities like process management, file systems, network protocols, and even device drivers can be built upon it using only safe Rust. This segregation ensures that critical operations are handled securely in the unsafe realm while allowing for the development of complex and feature-rich OS components.
|
||||
|
||||
In addition to OS functionalities, `aster-frame` also provides development utilities, including kernel mode unit test support. The shared base of crates built on `aster-frame` allows for easy reuse and facilitates the creation of sophisticated operating systems with rich features.
|
||||
|
||||
Overall, this architectural approach promotes safety and modularity, empowering developers to build robust and advanced OS systems using Rust.
|
||||
Conditional QEMU settings allow for a condition to be specified after `qemu`. Currently, `cargo-osdk` only supports the condition `cfg(feature="FEATURE")`, which activates the QEMU settings only if the `FEATURE` is set. The `FEATURE` must be defined in the project's `Cargo.toml`. At most one conditional setting can be activated at a time. If multiple conditional settings can be activated simultaneously, `cargo-osdk` will report an error. In the future, `cargo-osdk` will support all possible conditions that [Rust conditional compilation](https://doc.rust-lang.org/reference/conditional-compilation.html) supports.
|
@ -1,33 +0,0 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AsterBin {
|
||||
pub path: PathBuf,
|
||||
pub typ: AsterBinType,
|
||||
pub version: String,
|
||||
pub sha256sum: String,
|
||||
pub stripped: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum AsterBinType {
|
||||
Elf(AsterElfMeta),
|
||||
BzImage(AsterBzImageMeta),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AsterElfMeta {
|
||||
pub has_linux_header: bool,
|
||||
pub has_pvh_header: bool,
|
||||
pub has_multiboot_header: bool,
|
||||
pub has_multiboot2_header: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AsterBzImageMeta {
|
||||
pub support_legacy32_boot: bool,
|
||||
pub support_efi_boot: bool,
|
||||
pub support_efi_handover: bool,
|
||||
}
|
87
osdk/src/bundle/bin.rs
Normal file
87
osdk/src/bundle/bin.rs
Normal file
@ -0,0 +1,87 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use std::{
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use super::file::BundleFile;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AsterBin {
|
||||
path: PathBuf,
|
||||
typ: AsterBinType,
|
||||
version: String,
|
||||
sha256sum: String,
|
||||
stripped: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum AsterBinType {
|
||||
Elf(AsterElfMeta),
|
||||
BzImage(AsterBzImageMeta),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AsterElfMeta {
|
||||
pub has_linux_header: bool,
|
||||
pub has_pvh_header: bool,
|
||||
pub has_multiboot_header: bool,
|
||||
pub has_multiboot2_header: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AsterBzImageMeta {
|
||||
pub support_legacy32_boot: bool,
|
||||
pub support_efi_boot: bool,
|
||||
pub support_efi_handover: bool,
|
||||
}
|
||||
|
||||
impl BundleFile for AsterBin {
|
||||
fn path(&self) -> &PathBuf {
|
||||
&self.path
|
||||
}
|
||||
|
||||
fn sha256sum(&self) -> &String {
|
||||
&self.sha256sum
|
||||
}
|
||||
}
|
||||
|
||||
impl AsterBin {
|
||||
pub fn new(path: impl AsRef<Path>, typ: AsterBinType, version: String, stripped: bool) -> Self {
|
||||
let created = Self {
|
||||
path: path.as_ref().to_path_buf(),
|
||||
typ,
|
||||
version,
|
||||
sha256sum: String::new(),
|
||||
stripped,
|
||||
};
|
||||
Self {
|
||||
sha256sum: created.calculate_sha256sum(),
|
||||
..created
|
||||
}
|
||||
}
|
||||
|
||||
pub fn version(&self) -> &String {
|
||||
&self.version
|
||||
}
|
||||
|
||||
pub fn stripped(&self) -> bool {
|
||||
self.stripped
|
||||
}
|
||||
|
||||
/// Move the binary to the `base` directory and convert the path to a relative path.
|
||||
pub fn move_to(self, base: impl AsRef<Path>) -> Self {
|
||||
let file_name = self.path.file_name().unwrap();
|
||||
let copied_path = base.as_ref().join(file_name);
|
||||
fs::copy(&self.path, copied_path).unwrap();
|
||||
fs::remove_file(&self.path).unwrap();
|
||||
Self {
|
||||
path: PathBuf::from(file_name),
|
||||
typ: self.typ,
|
||||
version: self.version,
|
||||
sha256sum: self.sha256sum,
|
||||
stripped: self.stripped,
|
||||
}
|
||||
}
|
||||
}
|
66
osdk/src/bundle/file.rs
Normal file
66
osdk/src/bundle/file.rs
Normal file
@ -0,0 +1,66 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use std::{
|
||||
fs, io,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
/// A trait for files in a bundle. The file in a bundle should have it's digest and be validatable.
|
||||
pub trait BundleFile {
|
||||
fn path(&self) -> &PathBuf;
|
||||
|
||||
fn sha256sum(&self) -> &String;
|
||||
|
||||
fn calculate_sha256sum(&self) -> String {
|
||||
let mut file = fs::File::open(self.path()).unwrap();
|
||||
let mut hasher = Sha256::new();
|
||||
let _n = io::copy(&mut file, &mut hasher).unwrap();
|
||||
format!("{:x}", hasher.finalize())
|
||||
}
|
||||
|
||||
fn validate(&self) -> bool {
|
||||
self.sha256sum() == &self.calculate_sha256sum()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Initramfs {
|
||||
path: PathBuf,
|
||||
sha256sum: String,
|
||||
}
|
||||
|
||||
impl BundleFile for Initramfs {
|
||||
fn path(&self) -> &PathBuf {
|
||||
&self.path
|
||||
}
|
||||
|
||||
fn sha256sum(&self) -> &String {
|
||||
&self.sha256sum
|
||||
}
|
||||
}
|
||||
|
||||
impl Initramfs {
|
||||
pub fn new(path: impl AsRef<Path>) -> Self {
|
||||
let created = Self {
|
||||
path: path.as_ref().to_path_buf(),
|
||||
sha256sum: String::new(),
|
||||
};
|
||||
Self {
|
||||
sha256sum: created.calculate_sha256sum(),
|
||||
..created
|
||||
}
|
||||
}
|
||||
|
||||
/// Move the initramfs to the `base` directory and convert the path to a relative path.
|
||||
pub fn copy_to(self, base: impl AsRef<Path>) -> Self {
|
||||
let name = self.path.file_name().unwrap();
|
||||
let dest = base.as_ref().join(name);
|
||||
fs::copy(&self.path, dest).unwrap();
|
||||
Self {
|
||||
path: PathBuf::from(name),
|
||||
..self
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,20 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
pub mod bin;
|
||||
pub mod file;
|
||||
pub mod vm_image;
|
||||
|
||||
use bin::AsterBin;
|
||||
use file::{BundleFile, Initramfs};
|
||||
use vm_image::AsterVmImage;
|
||||
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
process::Command,
|
||||
time::SystemTime,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
bin::AsterBin,
|
||||
cli::CargoArgs,
|
||||
config_manager::{
|
||||
boot::Boot,
|
||||
@ -15,7 +23,6 @@ use crate::{
|
||||
},
|
||||
error::Errno,
|
||||
error_msg,
|
||||
vm_image::AsterVmImage,
|
||||
};
|
||||
|
||||
/// The osdk bundle artifact that stores as `bundle` directory.
|
||||
@ -28,39 +35,111 @@ pub struct Bundle {
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
/// The osdk bundle artifact manifest that stores as `bundle.toml`.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct BundleManifest {
|
||||
pub kcmd_args: Vec<String>,
|
||||
pub initramfs: Option<Initramfs>,
|
||||
pub aster_bin: Option<AsterBin>,
|
||||
pub vm_image: Option<AsterVmImage>,
|
||||
pub boot: Boot,
|
||||
pub qemu: Qemu,
|
||||
pub cargo_args: CargoArgs,
|
||||
pub last_modified: SystemTime,
|
||||
}
|
||||
|
||||
impl Bundle {
|
||||
pub fn new(manifest: BundleManifest, path: impl AsRef<Path>) -> Self {
|
||||
/// This function creates a new `Bundle` without adding any files.
|
||||
pub fn new(
|
||||
path: impl AsRef<Path>,
|
||||
kcmd_args: Vec<String>,
|
||||
boot: Boot,
|
||||
qemu: Qemu,
|
||||
cargo_args: CargoArgs,
|
||||
) -> Self {
|
||||
std::fs::create_dir_all(path.as_ref()).unwrap();
|
||||
let created = Self {
|
||||
manifest,
|
||||
let mut created = Self {
|
||||
manifest: BundleManifest {
|
||||
kcmd_args,
|
||||
initramfs: None,
|
||||
aster_bin: None,
|
||||
vm_image: None,
|
||||
boot,
|
||||
qemu,
|
||||
cargo_args,
|
||||
last_modified: SystemTime::now(),
|
||||
},
|
||||
path: path.as_ref().to_path_buf(),
|
||||
};
|
||||
created.write_manifest_content();
|
||||
created.write_manifest_to_fs();
|
||||
created
|
||||
}
|
||||
|
||||
// FIXME: the load function should be used when implementing build cache, but it is not
|
||||
// implemented yet.
|
||||
#[allow(dead_code)]
|
||||
pub fn load(path: impl AsRef<Path>) -> Self {
|
||||
// Load the bundle from the file system. If the bundle does not exist or have inconsistencies,
|
||||
// it will return `None`.
|
||||
pub fn load(path: impl AsRef<Path>) -> Option<Self> {
|
||||
let manifest_file_path = path.as_ref().join("bundle.toml");
|
||||
let manifest_file_content = std::fs::read_to_string(manifest_file_path).unwrap();
|
||||
let manifest: BundleManifest = toml::from_str(&manifest_file_content).unwrap();
|
||||
// TODO: check integrity of the loaded bundle.
|
||||
Self {
|
||||
let manifest_file_content = std::fs::read_to_string(manifest_file_path).ok()?;
|
||||
let manifest: BundleManifest = toml::from_str(&manifest_file_content).ok()?;
|
||||
|
||||
let original_dir = std::env::current_dir().unwrap();
|
||||
std::env::set_current_dir(&path).unwrap();
|
||||
|
||||
if let Some(aster_bin) = &manifest.aster_bin {
|
||||
if !aster_bin.validate() {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
if let Some(vm_image) = &manifest.vm_image {
|
||||
if !vm_image.validate() {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
if let Some(initramfs) = &manifest.initramfs {
|
||||
if !initramfs.validate() {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
std::env::set_current_dir(original_dir).unwrap();
|
||||
|
||||
Some(Self {
|
||||
manifest,
|
||||
path: path.as_ref().to_path_buf(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn can_run_with_config(&self, config: &RunConfig) -> bool {
|
||||
// Compare the manifest with the run configuration.
|
||||
// TODO: This pairwise comparison will result in some false negatives. We may
|
||||
// fix it by pondering upon each fields with more care.
|
||||
self.manifest.kcmd_args == config.manifest.kcmd_args
|
||||
&& self.manifest.initramfs == config.manifest.initramfs
|
||||
&& self.manifest.boot == config.manifest.boot
|
||||
&& self.manifest.qemu == config.manifest.qemu
|
||||
&& self.manifest.cargo_args == config.cargo_args
|
||||
if self.manifest.kcmd_args != config.manifest.kcmd_args
|
||||
|| self.manifest.boot != config.manifest.boot
|
||||
|| self.manifest.qemu != config.manifest.qemu
|
||||
|| self.manifest.cargo_args != config.cargo_args
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compare the initramfs.
|
||||
match (&self.manifest.initramfs, &config.manifest.initramfs) {
|
||||
(Some(initramfs), Some(initramfs_path)) => {
|
||||
let config_initramfs = Initramfs::new(initramfs_path);
|
||||
if initramfs.sha256sum() != config_initramfs.sha256sum() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
(None, None) => {}
|
||||
_ => {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
pub fn last_modified_time(&self) -> SystemTime {
|
||||
self.manifest.last_modified
|
||||
}
|
||||
|
||||
pub fn run(&self, config: &RunConfig) {
|
||||
@ -84,7 +163,9 @@ impl Bundle {
|
||||
error_msg!("Kernel ELF binary is required for Microvm");
|
||||
std::process::exit(Errno::RunBundle as _);
|
||||
};
|
||||
qemu_cmd.arg("-kernel").arg(self.path.join(&aster_bin.path));
|
||||
qemu_cmd
|
||||
.arg("-kernel")
|
||||
.arg(self.path.join(aster_bin.path()));
|
||||
let Some(ref initramfs) = config.manifest.initramfs else {
|
||||
error_msg!("Initramfs is required for Microvm");
|
||||
std::process::exit(Errno::RunBundle as _);
|
||||
@ -100,7 +181,7 @@ impl Bundle {
|
||||
error_msg!("VM image is required for QEMU booting");
|
||||
std::process::exit(Errno::RunBundle as _);
|
||||
};
|
||||
qemu_cmd.arg("-cdrom").arg(self.path.join(&vm_image.path));
|
||||
qemu_cmd.arg("-cdrom").arg(self.path.join(vm_image.path()));
|
||||
if let Some(ovmf) = &config.manifest.boot.ovmf {
|
||||
qemu_cmd.arg("-drive").arg(format!(
|
||||
"if=pflash,format=raw,unit=0,readonly=on,file={}",
|
||||
@ -136,61 +217,37 @@ impl Bundle {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_vm_image(&mut self, vm_image: &AsterVmImage) {
|
||||
/// Move the vm_image into the bundle.
|
||||
pub fn consume_vm_image(&mut self, vm_image: AsterVmImage) {
|
||||
if self.manifest.vm_image.is_some() {
|
||||
panic!("vm_image already exists");
|
||||
}
|
||||
let file_name = vm_image.path.file_name().unwrap();
|
||||
let copied_path = self.path.join(file_name);
|
||||
std::fs::copy(&vm_image.path, copied_path).unwrap();
|
||||
self.manifest.vm_image = Some(AsterVmImage {
|
||||
path: file_name.into(),
|
||||
typ: vm_image.typ.clone(),
|
||||
aster_version: vm_image.aster_version.clone(),
|
||||
sha256sum: vm_image.sha256sum.clone(),
|
||||
});
|
||||
self.write_manifest_content();
|
||||
self.manifest.vm_image = Some(vm_image.move_to(&self.path));
|
||||
self.write_manifest_to_fs();
|
||||
}
|
||||
|
||||
pub fn add_aster_bin(&mut self, aster_bin: &AsterBin) {
|
||||
/// Move the aster_bin into the bundle.
|
||||
pub fn consume_aster_bin(&mut self, aster_bin: AsterBin) {
|
||||
if self.manifest.aster_bin.is_some() {
|
||||
panic!("aster_bin already exists");
|
||||
}
|
||||
let file_name = aster_bin.path.file_name().unwrap();
|
||||
let copied_path = self.path.join(file_name);
|
||||
std::fs::copy(&aster_bin.path, copied_path).unwrap();
|
||||
self.manifest.aster_bin = Some(AsterBin {
|
||||
path: file_name.into(),
|
||||
typ: aster_bin.typ.clone(),
|
||||
version: aster_bin.version.clone(),
|
||||
sha256sum: aster_bin.sha256sum.clone(),
|
||||
stripped: aster_bin.stripped,
|
||||
});
|
||||
self.write_manifest_content();
|
||||
self.manifest.aster_bin = Some(aster_bin.move_to(&self.path));
|
||||
self.write_manifest_to_fs();
|
||||
}
|
||||
|
||||
fn write_manifest_content(&self) {
|
||||
/// Copy the initramfs into the bundle.
|
||||
pub fn add_initramfs(&mut self, initramfs: Initramfs) {
|
||||
if self.manifest.initramfs.is_some() {
|
||||
panic!("initramfs already exists");
|
||||
}
|
||||
self.manifest.initramfs = Some(initramfs.copy_to(&self.path));
|
||||
self.write_manifest_to_fs();
|
||||
}
|
||||
|
||||
fn write_manifest_to_fs(&mut self) {
|
||||
self.manifest.last_modified = SystemTime::now();
|
||||
let manifest_file_content = toml::to_string(&self.manifest).unwrap();
|
||||
let manifest_file_path = self.path.join("bundle.toml");
|
||||
std::fs::write(manifest_file_path, manifest_file_content).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
/// The osdk bundle artifact manifest that stores as `bundle.toml`.
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct BundleManifest {
|
||||
#[serde(default)]
|
||||
pub kcmd_args: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub initramfs: Option<PathBuf>,
|
||||
#[serde(default)]
|
||||
pub aster_bin: Option<AsterBin>,
|
||||
#[serde(default)]
|
||||
pub vm_image: Option<AsterVmImage>,
|
||||
#[serde(default)]
|
||||
pub boot: Boot,
|
||||
#[serde(default)]
|
||||
pub qemu: Qemu,
|
||||
#[serde(default)]
|
||||
pub cargo_args: CargoArgs,
|
||||
}
|
66
osdk/src/bundle/vm_image.rs
Normal file
66
osdk/src/bundle/vm_image.rs
Normal file
@ -0,0 +1,66 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use std::{
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use super::file::BundleFile;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AsterVmImage {
|
||||
path: PathBuf,
|
||||
typ: AsterVmImageType,
|
||||
aster_version: String,
|
||||
sha256sum: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum AsterVmImageType {
|
||||
GrubIso(AsterGrubIsoImageMeta),
|
||||
// TODO: add more vm image types such as qcow2, etc.
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AsterGrubIsoImageMeta {
|
||||
pub grub_version: String,
|
||||
}
|
||||
|
||||
impl BundleFile for AsterVmImage {
|
||||
fn path(&self) -> &PathBuf {
|
||||
&self.path
|
||||
}
|
||||
|
||||
fn sha256sum(&self) -> &String {
|
||||
&self.sha256sum
|
||||
}
|
||||
}
|
||||
|
||||
impl AsterVmImage {
|
||||
pub fn new(path: impl AsRef<Path>, typ: AsterVmImageType, aster_version: String) -> Self {
|
||||
let created = Self {
|
||||
path: path.as_ref().to_path_buf(),
|
||||
typ,
|
||||
aster_version,
|
||||
sha256sum: String::new(),
|
||||
};
|
||||
Self {
|
||||
sha256sum: created.calculate_sha256sum(),
|
||||
..created
|
||||
}
|
||||
}
|
||||
|
||||
/// Move the binary to the `base` directory and convert the path to a relative path.
|
||||
pub fn move_to(self, base: impl AsRef<Path>) -> Self {
|
||||
let file_name = self.path.file_name().unwrap();
|
||||
let copied_path = base.as_ref().join(file_name);
|
||||
fs::copy(&self.path, copied_path).unwrap();
|
||||
fs::remove_file(&self.path).unwrap();
|
||||
Self {
|
||||
path: PathBuf::from(file_name),
|
||||
typ: self.typ,
|
||||
aster_version: self.aster_version,
|
||||
sha256sum: self.sha256sum,
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -8,14 +8,12 @@ extern crate log;
|
||||
extern crate serde;
|
||||
|
||||
mod base_crate;
|
||||
mod bin;
|
||||
mod bundle;
|
||||
mod cli;
|
||||
mod commands;
|
||||
mod config_manager;
|
||||
mod error;
|
||||
mod utils;
|
||||
mod vm_image;
|
||||
|
||||
fn main() {
|
||||
// init logger
|
||||
|
@ -1,22 +0,0 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AsterVmImage {
|
||||
pub path: PathBuf,
|
||||
pub typ: AsterVmImageType,
|
||||
pub aster_version: String,
|
||||
pub sha256sum: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum AsterVmImageType {
|
||||
GrubIso(AsterGrubIsoImageMeta),
|
||||
// TODO: add more vm image types such as qcow2, etc.
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AsterGrubIsoImageMeta {
|
||||
pub grub_version: String,
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user