mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-26 02:43:24 +00:00
Add OSDK command line interface
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
f2f991b239
commit
3b3d088767
27
osdk/src/commands/check.rs
Normal file
27
osdk/src/commands/check.rs
Normal file
@ -0,0 +1,27 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use std::process;
|
||||
|
||||
use crate::commands::utils::create_target_json;
|
||||
use crate::error::Errno;
|
||||
use crate::error_msg;
|
||||
use crate::utils::get_cargo_metadata;
|
||||
|
||||
use super::utils::{cargo, COMMON_CARGO_ARGS};
|
||||
|
||||
pub fn execute_check_command() {
|
||||
let target_json_path = {
|
||||
let metadata = get_cargo_metadata(None::<&str>, None::<&[&str]>);
|
||||
let target_directory = metadata.get("target_directory").unwrap().as_str().unwrap();
|
||||
create_target_json(target_directory)
|
||||
};
|
||||
|
||||
let mut command = cargo();
|
||||
command.arg("check").arg("--target").arg(target_json_path);
|
||||
command.args(COMMON_CARGO_ARGS);
|
||||
let status = command.status().unwrap();
|
||||
if !status.success() {
|
||||
error_msg!("Check failed");
|
||||
process::exit(Errno::ExecuteCommand as _);
|
||||
}
|
||||
}
|
38
osdk/src/commands/clippy.rs
Normal file
38
osdk/src/commands/clippy.rs
Normal file
@ -0,0 +1,38 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use std::process;
|
||||
|
||||
use crate::error_msg;
|
||||
use crate::utils::get_cargo_metadata;
|
||||
use crate::{commands::utils::create_target_json, error::Errno};
|
||||
|
||||
use super::utils::{cargo, COMMON_CARGO_ARGS};
|
||||
|
||||
pub fn execute_clippy_command() {
|
||||
let target_json_path = {
|
||||
let metadata = get_cargo_metadata(None::<&str>, None::<&[&str]>);
|
||||
let target_directory = metadata.get("target_directory").unwrap().as_str().unwrap();
|
||||
create_target_json(target_directory)
|
||||
};
|
||||
|
||||
let mut command = cargo();
|
||||
command.arg("clippy").arg("-h");
|
||||
info!("[Running] cargo clippy -h");
|
||||
let output = command.output().unwrap();
|
||||
if !output.status.success() {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
eprintln!("{}", &stderr);
|
||||
error_msg!("Cargo clippy failed");
|
||||
process::exit(Errno::ExecuteCommand as _);
|
||||
}
|
||||
|
||||
let mut command = cargo();
|
||||
command.arg("clippy").arg("--target").arg(target_json_path);
|
||||
command.args(COMMON_CARGO_ARGS);
|
||||
command.args(["--", "-D", "warnings"]);
|
||||
let status = command.status().unwrap();
|
||||
if !status.success() {
|
||||
error_msg!("Cargo clippy failed");
|
||||
process::exit(Errno::ExecuteCommand as _);
|
||||
}
|
||||
}
|
12
osdk/src/commands/mod.rs
Normal file
12
osdk/src/commands/mod.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//! This module contains subcommands of cargo-osdk.
|
||||
|
||||
mod check;
|
||||
mod clippy;
|
||||
mod new;
|
||||
mod utils;
|
||||
|
||||
pub use self::check::execute_check_command;
|
||||
pub use self::clippy::execute_clippy_command;
|
||||
pub use self::new::execute_new_command;
|
164
osdk/src/commands/new.rs
Normal file
164
osdk/src/commands/new.rs
Normal file
@ -0,0 +1,164 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use std::{fs, process};
|
||||
|
||||
use crate::cli::NewArgs;
|
||||
use crate::error::Errno;
|
||||
use crate::error_msg;
|
||||
use crate::utils::{cargo_new_lib, get_cargo_metadata, ASTER_FRAME_DEP};
|
||||
|
||||
pub fn execute_new_command(args: &NewArgs) {
|
||||
cargo_new_lib(&args.crate_name);
|
||||
let cargo_metadata = get_cargo_metadata(Some(&args.crate_name), None::<&[&str]>);
|
||||
add_manifest_dependencies(&cargo_metadata, &args.crate_name);
|
||||
create_osdk_manifest(&cargo_metadata);
|
||||
if args.kernel {
|
||||
write_kernel_template(&cargo_metadata, &args.crate_name);
|
||||
} else {
|
||||
write_library_template(&cargo_metadata, &args.crate_name);
|
||||
}
|
||||
add_rust_toolchain(&cargo_metadata);
|
||||
}
|
||||
|
||||
fn add_manifest_dependencies(cargo_metadata: &serde_json::Value, crate_name: &str) {
|
||||
let mainfest_path = get_manifest_path(cargo_metadata, crate_name);
|
||||
|
||||
let mut manifest: toml::Table = {
|
||||
let content = fs::read_to_string(mainfest_path).unwrap();
|
||||
toml::from_str(&content).unwrap()
|
||||
};
|
||||
|
||||
let dependencies = manifest.get_mut("dependencies").unwrap();
|
||||
|
||||
let aster_frame_dep = toml::Table::from_str(ASTER_FRAME_DEP).unwrap();
|
||||
dependencies.as_table_mut().unwrap().extend(aster_frame_dep);
|
||||
|
||||
let content = toml::to_string(&manifest).unwrap();
|
||||
fs::write(mainfest_path, content).unwrap();
|
||||
}
|
||||
|
||||
fn create_osdk_manifest(cargo_metadata: &serde_json::Value) {
|
||||
let osdk_manifest_path = {
|
||||
let workspace_root = get_workspace_root(cargo_metadata);
|
||||
PathBuf::from(workspace_root).join("OSDK.toml")
|
||||
};
|
||||
|
||||
if osdk_manifest_path.is_file() {
|
||||
// If the OSDK.toml of workspace exists, just return.
|
||||
return;
|
||||
}
|
||||
|
||||
// Create `OSDK.toml` for the workspace
|
||||
fs::write(osdk_manifest_path, "").unwrap();
|
||||
}
|
||||
|
||||
/// Write the default content of `src/kernel.rs`, with contents in provided template.
|
||||
fn write_kernel_template(cargo_metadata: &serde_json::Value, crate_name: &str) {
|
||||
let src_path = get_src_path(cargo_metadata, crate_name);
|
||||
let contents = include_str!("template/kernel.template");
|
||||
fs::write(src_path, contents).unwrap();
|
||||
}
|
||||
|
||||
/// Write the default content of `src/lib.rs`, with contents in provided template.
|
||||
fn write_library_template(cargo_metadata: &serde_json::Value, crate_name: &str) {
|
||||
let src_path = get_src_path(cargo_metadata, crate_name);
|
||||
let contents = include_str!("template/lib.template");
|
||||
fs::write(src_path, contents).unwrap();
|
||||
}
|
||||
|
||||
/// Add the rust-toolchain.toml file in workspace root
|
||||
fn add_rust_toolchain(cargo_metadata: &serde_json::Value) {
|
||||
let workspace_root = get_workspace_root(cargo_metadata);
|
||||
|
||||
let rust_toolchain_path = PathBuf::from(workspace_root).join("rust-toolchain.toml");
|
||||
if let Ok(true) = rust_toolchain_path.try_exists() {
|
||||
let toolchain = {
|
||||
let content = fs::read_to_string(&rust_toolchain_path).unwrap();
|
||||
toml::Table::from_str(&content).unwrap()
|
||||
};
|
||||
|
||||
check_rust_toolchain(&toolchain);
|
||||
return;
|
||||
}
|
||||
|
||||
let contents = include_str!("template/rust-toolchain.toml.template");
|
||||
fs::write(rust_toolchain_path, contents).unwrap();
|
||||
}
|
||||
|
||||
fn get_manifest_path<'a>(cargo_metadata: &'a serde_json::Value, crate_name: &str) -> &'a str {
|
||||
let metadata = get_package_metadata(cargo_metadata, crate_name);
|
||||
metadata.get("manifest_path").unwrap().as_str().unwrap()
|
||||
}
|
||||
|
||||
fn get_src_path<'a>(cargo_metadata: &'a serde_json::Value, crate_name: &str) -> &'a str {
|
||||
let metadata = get_package_metadata(cargo_metadata, crate_name);
|
||||
let targets = metadata.get("targets").unwrap().as_array().unwrap();
|
||||
|
||||
for target in targets {
|
||||
let name = target.get("name").unwrap().as_str().unwrap();
|
||||
if name != crate_name {
|
||||
continue;
|
||||
}
|
||||
|
||||
let src_path = target.get("src_path").unwrap();
|
||||
return src_path.as_str().unwrap();
|
||||
}
|
||||
|
||||
panic!("the crate name does not match with any target");
|
||||
}
|
||||
|
||||
fn get_workspace_root(cargo_metadata: &serde_json::Value) -> &str {
|
||||
let workspace_root = cargo_metadata.get("workspace_root").unwrap();
|
||||
workspace_root.as_str().unwrap()
|
||||
}
|
||||
|
||||
fn get_package_metadata<'a>(
|
||||
cargo_metadata: &'a serde_json::Value,
|
||||
crate_name: &str,
|
||||
) -> &'a serde_json::Value {
|
||||
let packages = cargo_metadata.get("packages").unwrap();
|
||||
|
||||
let package_metadatas = packages.as_array().unwrap();
|
||||
|
||||
for package_metadata in package_metadatas {
|
||||
let name = package_metadata.get("name").unwrap().as_str().unwrap();
|
||||
if crate_name == name {
|
||||
return package_metadata;
|
||||
}
|
||||
}
|
||||
|
||||
panic!("cannot find metadata of the crate")
|
||||
}
|
||||
|
||||
fn check_rust_toolchain(toolchain: &toml::Table) {
|
||||
let expected = {
|
||||
let contents = include_str!("template/rust-toolchain.toml.template");
|
||||
toml::Table::from_str(contents).unwrap()
|
||||
};
|
||||
|
||||
let expected = expected.get("toolchain").unwrap().as_table().unwrap();
|
||||
let toolchain = toolchain.get("toolchain").unwrap().as_table().unwrap();
|
||||
|
||||
let channel = toolchain.get("channel").unwrap().as_str().unwrap();
|
||||
let expected_channel = expected.get("channel").unwrap().as_str().unwrap();
|
||||
|
||||
if channel != expected_channel {
|
||||
error_msg!("The current version of rust-toolchain.toml is not compatible with the osdk");
|
||||
process::exit(Errno::AddRustToolchain as _);
|
||||
}
|
||||
|
||||
let components = toolchain.get("components").unwrap().as_array().unwrap();
|
||||
let expected_components = toolchain.get("components").unwrap().as_array().unwrap();
|
||||
|
||||
for expected_component in expected_components {
|
||||
if !components.contains(expected_component) {
|
||||
error_msg!(
|
||||
"rust-toolchain.toml does not contains {}",
|
||||
expected_component.as_str().unwrap()
|
||||
);
|
||||
process::exit(Errno::AddRustToolchain as _);
|
||||
}
|
||||
}
|
||||
}
|
9
osdk/src/commands/template/kernel.template
Normal file
9
osdk/src/commands/template/kernel.template
Normal file
@ -0,0 +1,9 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use aster_frame::prelude::*;
|
||||
|
||||
#[aster_main]
|
||||
fn kernel_main() {
|
||||
println!("Hello world from guest kernel!");
|
||||
}
|
10
osdk/src/commands/template/lib.template
Normal file
10
osdk/src/commands/template/lib.template
Normal file
@ -0,0 +1,10 @@
|
||||
#![no_std]
|
||||
|
||||
#[cfg(ktest)]
|
||||
mod tests {
|
||||
#[ktest]
|
||||
fn it_works() {
|
||||
let memory_regions = aster_frame::boot::memory_regions();
|
||||
assert!(!memory_regions.is_empty());
|
||||
}
|
||||
}
|
3
osdk/src/commands/template/rust-toolchain.toml.template
Normal file
3
osdk/src/commands/template/rust-toolchain.toml.template
Normal file
@ -0,0 +1,3 @@
|
||||
[toolchain]
|
||||
channel = "nightly-2023-12-01"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
|
16
osdk/src/commands/template/x86_64-custom.json.template
Normal file
16
osdk/src/commands/template/x86_64-custom.json.template
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"llvm-target": "x86_64-unknown-none",
|
||||
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
|
||||
"code-model": "kernel",
|
||||
"cpu": "x86-64",
|
||||
"arch": "x86_64",
|
||||
"target-endian": "little",
|
||||
"target-pointer-width": "64",
|
||||
"target-c-int-width": "32",
|
||||
"os": "none",
|
||||
"executables": true,
|
||||
"linker-flavor": "ld.lld",
|
||||
"linker": "rust-lld",
|
||||
"disable-redzone": true,
|
||||
"features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float"
|
||||
}
|
29
osdk/src/commands/utils.rs
Normal file
29
osdk/src/commands/utils.rs
Normal file
@ -0,0 +1,29 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
pub const COMMON_CARGO_ARGS: &[&str] = &[
|
||||
"-Zbuild-std=core,alloc,compiler_builtins",
|
||||
"-Zbuild-std-features=compiler-builtins-mem",
|
||||
];
|
||||
|
||||
pub fn cargo() -> Command {
|
||||
Command::new("cargo")
|
||||
}
|
||||
|
||||
pub fn create_target_json(target_directory: impl AsRef<Path>) -> PathBuf {
|
||||
let target_osdk_dir = PathBuf::from(target_directory.as_ref()).join("osdk");
|
||||
fs::create_dir_all(&target_osdk_dir).unwrap();
|
||||
|
||||
let target_json_path = target_osdk_dir.join("x86_64-custom.json");
|
||||
if target_json_path.is_file() {
|
||||
return target_json_path;
|
||||
}
|
||||
|
||||
let contents = include_str!("template/x86_64-custom.json.template");
|
||||
fs::write(&target_json_path, contents).unwrap();
|
||||
|
||||
target_json_path
|
||||
}
|
Reference in New Issue
Block a user