浏览代码

feat(dadk): 新的console & dadk-insiders测试目标 (#70)

- 把用户程序编译的功能改到了`dadk user`命令目录下
- 添加了用于开发测试的二进制文件`dadk-insiders`: 使用命令`cargo install --bin dadk-insiders --path ./dadk`即可安装. 开发测试不会跟已有的dadk冲突

Signed-off-by: longjin <longjin@DragonOS.org>
LoGin 5 月之前
父节点
当前提交
eaa67f3cf8

+ 8 - 2
dadk-config/src/common/target_arch.rs

@@ -1,16 +1,17 @@
 use serde::{Deserialize, Deserializer, Serialize};
 
 /// 目标处理器架构
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord)]
 pub enum TargetArch {
     #[default]
     X86_64,
     RiscV64,
+    AArch64,
 }
 
 impl TargetArch {
     /// 期望的目标处理器架构(如果修改了枚举,那一定要修改这里)
-    pub const EXPECTED: [&'static str; 2] = ["x86_64", "riscv64"];
+    pub const EXPECTED: [&'static str; 3] = ["x86_64", "riscv64", "aarch64"];
 }
 
 impl TryFrom<&str> for TargetArch {
@@ -20,6 +21,7 @@ impl TryFrom<&str> for TargetArch {
         match value.trim().to_ascii_lowercase().as_str() {
             "x86_64" => Ok(TargetArch::X86_64),
             "riscv64" => Ok(TargetArch::RiscV64),
+            "aarch64" => Ok(TargetArch::AArch64),
             _ => Err(format!("Unknown target arch: {}", value)),
         }
     }
@@ -30,6 +32,7 @@ impl From<TargetArch> for &str {
         match val {
             TargetArch::X86_64 => "x86_64",
             TargetArch::RiscV64 => "riscv64",
+            TargetArch::AArch64 => "aarch64",
         }
     }
 }
@@ -87,6 +90,9 @@ mod tests {
 
         let riscv64 = TargetArch::try_from("riscv64").unwrap();
         assert_eq!(riscv64, TargetArch::RiscV64);
+
+        let aarch64 = TargetArch::try_from("aarch64").unwrap();
+        assert_eq!(aarch64, TargetArch::AArch64);
     }
 
     #[test]

+ 34 - 8
dadk-config/src/manifest.rs

@@ -59,20 +59,33 @@ pub struct Metadata {
     /// Target processor architecture
     pub arch: TargetArch,
     /// Rootfs configuration file path
-    #[serde(default = "default_rootfs_config_path")]
+    #[serde(default = "default_rootfs_config_path", rename = "rootfs-config")]
     pub rootfs_config: PathBuf,
 
     /// Hypervisor configuration file path
-    #[serde(default = "default_hypervisor_config_path")]
+    #[serde(
+        default = "default_hypervisor_config_path",
+        rename = "hypervisor-config"
+    )]
     pub hypervisor_config: PathBuf,
 
     /// Boot configuration file path
-    #[serde(default = "default_boot_config_path")]
+    #[serde(default = "default_boot_config_path", rename = "boot-config")]
     pub boot_config: PathBuf,
 
     /// Sysroot directory path
-    #[serde(default = "default_sysroot_dir")]
+    #[serde(default = "default_sysroot_dir", rename = "sysroot-dir")]
     pub sysroot_dir: PathBuf,
+
+    /// Root Cache directory path
+    #[serde(default = "default_cache_root_dir", rename = "cache-root-dir")]
+    pub cache_root_dir: PathBuf,
+
+    /// User configuration directory path
+    /// 这个字段只是临时用于兼容旧版本,v0.2版本重构完成后会删除
+    #[deprecated(note = "This field is deprecated and will be removed in DADK 0.2")]
+    #[serde(default = "default_user_config_dir", rename = "user-config-dir")]
+    pub user_config_dir: PathBuf,
 }
 
 /// Returns the default path for the rootfs configuration file.
@@ -99,6 +112,17 @@ fn default_sysroot_dir() -> PathBuf {
     "bin/sysroot".into()
 }
 
+/// Returns the default path for the cache directory.
+fn default_cache_root_dir() -> PathBuf {
+    set_used_default();
+    "bin/dadk_cache".into()
+}
+
+fn default_user_config_dir() -> PathBuf {
+    set_used_default();
+    "user/dadk/config".into()
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -111,10 +135,12 @@ mod tests {
         let toml_content = r#"
             [metadata]
             arch = "x86_64"
-            rootfs_config = "config/rootfs-x86_64.toml"
-            hypervisor_config = "config/hypervisor-x86_64.toml"
-            boot_config = "config/boot-x86_64.toml"
-            sysroot_dir = "bin/sysroot"
+            rootfs-config = "config/rootfs-x86_64.toml"
+            hypervisor-config = "config/hypervisor-x86_64.toml"
+            boot-config = "config/boot-x86_64.toml"
+            sysroot-dir = "bin/sysroot"
+            cache-root-dir = "bin/dadk_cache"
+            user-config-dir = "user/dadk/config"
         "#;
 
         let mut temp_file = NamedTempFile::new()?;

+ 9 - 1
dadk-config/src/user/mod.rs

@@ -1 +1,9 @@
-
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum UserCleanLevel {
+    /// 清理所有用户程序构建缓存
+    All,
+    /// 只在用户程序源码目录下清理
+    InSrc,
+    /// 只清理用户程序输出目录
+    Output,
+}

+ 11 - 4
dadk-config/templates/dadk-manifest.toml

@@ -6,13 +6,20 @@
 arch = "x86_64"
 
 # Hypervisor config path
-hypervisor_config = "config/hypervisor.toml"
+hypervisor-config = "config/hypervisor.toml"
 
 # RootFS config path
-rootfs_config = "config/rootfs.toml"
+rootfs-config = "config/rootfs.toml"
 
 # Boot config path
-boot_config = "config/boot.toml"
+boot-config = "config/boot.toml"
 
 # System root directory folder (DADK will copy the files in this directory to the root directory of the disk image)
-sysroot_dir = "bin/sysroot"
+sysroot-dir = "bin/sysroot"
+
+# DADK Root Cache directory path
+cache-root-dir = "bin/dadk_cache"
+
+# User configuration directory path
+# 这个字段只是临时用于兼容旧版本,v0.2版本重构完成后会删除
+user-config-dir = "user/apps/dadk/config"

+ 3 - 1
dadk-user/Cargo.toml

@@ -4,8 +4,10 @@ version = "0.1.11"
 edition = "2021"
 
 [dependencies]
+anyhow = { version = "1.0.90", features = ["std", "backtrace"] }
 chrono = { version = "=0.4.35", features = ["serde"] }
 clap = { version = "=4.5.20", features = ["derive"] }
+dadk-config = { path = "../dadk-config" }
 derive_builder = "0.20.0"
 lazy_static = "1.4.0"
 log = "0.4.17"
@@ -17,4 +19,4 @@ toml = "0.8.12"
 zip = "2.2"
 
 [dev-dependencies]
-test_base = { path = "../crates/test_base" }
+test_base = { path = "../crates/test_base" }

+ 0 - 57
dadk-user/src/console/clean.rs

@@ -1,57 +0,0 @@
-use std::{fmt::Display, str::FromStr};
-
-use clap::{Args, Subcommand};
-
-/// 清理缓存的级别
-#[derive(Debug, Args, Clone, Copy, PartialEq, Eq)]
-pub struct CleanArg {
-    #[arg(default_value = "src")]
-    /// 清理缓存的级别
-    ///
-    /// all:清理所有缓存
-    ///
-    /// src:在源码目录内运行clean命令
-    ///
-    /// target:清理DADK输出目录
-    ///
-    /// cache:清理DADK缓存目录(下载的源码、编译好的库等)
-    pub level: CleanLevel,
-}
-
-#[derive(Debug, Subcommand, Clone, Copy, PartialEq, Eq)]
-pub enum CleanLevel {
-    /// 清理所有缓存
-    All,
-    /// 在源码目录内运行clean命令
-    Src,
-    /// 清理DADK输出目录
-    Target,
-    /// 清理DADK缓存目录(下载的源码、编译好的库等)
-    Cache,
-}
-
-impl FromStr for CleanLevel {
-    type Err = String;
-
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        let s = s.to_ascii_lowercase();
-        match s.as_str() {
-            "all" => Ok(CleanLevel::All),
-            "src" => Ok(CleanLevel::Src),
-            "target" => Ok(CleanLevel::Target),
-            "cache" => Ok(CleanLevel::Cache),
-            _ => Err(format!("Unknown clean level: {}", s)),
-        }
-    }
-}
-
-impl Display for CleanLevel {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            CleanLevel::All => write!(f, "all"),
-            CleanLevel::Src => write!(f, "src"),
-            CleanLevel::Target => write!(f, "target"),
-            CleanLevel::Cache => write!(f, "cache"),
-        }
-    }
-}

+ 0 - 93
dadk-user/src/console/mod.rs

@@ -1,93 +0,0 @@
-//! # DADK控制台
-//!
-//! DADK控制台能够让用户通过命令行交互的方式使用DADK。
-//!
-//! ## 创建配置文件
-//!
-//! DADK控制台提供了一个命令,用于创建一个配置文件。您可以通过以下命令创建一个配置文件:
-//!
-//! ```bash
-//! dadk new
-//! ```
-//!
-
-pub mod clean;
-
-use std::path::PathBuf;
-
-use clap::{Parser, Subcommand};
-
-use crate::parser::task::TargetArch;
-
-use self::clean::CleanArg;
-
-#[derive(Debug, Parser, Clone)]
-#[command(author, version, about)]
-pub struct CommandLineArgs {
-    /// DragonOS sysroot在主机上的路径
-    #[arg(short, long, value_parser = parse_check_dir_exists)]
-    pub sysroot_dir: Option<PathBuf>,
-    /// DADK任务配置文件所在目录
-    #[arg(short, long, value_parser = parse_check_dir_exists)]
-    pub config_dir: Option<PathBuf>,
-
-    /// 要执行的操作
-    #[command(subcommand)]
-    pub action: Action,
-
-    /// DADK缓存根目录
-    #[arg(long, value_parser = parse_check_dir_exists)]
-    pub cache_dir: Option<PathBuf>,
-
-    /// DADK任务并行线程数量
-    #[arg(short, long)]
-    pub thread: Option<usize>,
-
-    /// 目标架构,可选: ["aarch64", "x86_64", "riscv64", "riscv32"]
-    #[arg(long, value_parser = parse_target_arch)]
-    pub target_arch: Option<TargetArch>,
-}
-
-/// @brief 检查目录是否存在
-fn parse_check_dir_exists(path: &str) -> Result<PathBuf, String> {
-    let path = PathBuf::from(path);
-    if !path.exists() {
-        return Err(format!("Path '{}' not exists", path.display()));
-    }
-    if !path.is_dir() {
-        return Err(format!("Path '{}' is not a directory", path.display()));
-    }
-
-    return Ok(path);
-}
-
-fn parse_target_arch(s: &str) -> Result<TargetArch, String> {
-    let x = TargetArch::try_from(s);
-    if x.is_err() {
-        return Err(format!("Invalid target arch: {}", s));
-    }
-    return Ok(x.unwrap());
-}
-
-#[derive(Debug, Subcommand, Clone, Copy, PartialEq, Eq)]
-pub enum Action {
-    /// 构建所有项目
-    Build,
-    /// 清理缓存
-    Clean(CleanArg),
-    /// 安装到DragonOS sysroot
-    Install,
-    /// 尚不支持
-    Uninstall,
-}
-
-#[allow(dead_code)]
-#[derive(Debug)]
-pub enum ConsoleError {
-    CommandError(String),
-    IOError(std::io::Error),
-    /// 错误次数超过限制
-    RetryLimitExceeded(String),
-    /// 无效的输入
-    InvalidInput(String),
-}

+ 12 - 4
dadk-user/src/context.rs

@@ -4,15 +4,13 @@ use std::{
     sync::{Arc, Mutex, Weak},
 };
 
+use dadk_config::{common::target_arch::TargetArch, user::UserCleanLevel};
 use derive_builder::Builder;
 use log::error;
 #[cfg(test)]
 use test_base::{global::BaseGlobalTestContext, test_context::TestContext};
 
-use crate::{
-    console::Action, executor::cache::cache_root_init, parser::task::TargetArch,
-    scheduler::task_deque::TASK_DEQUE,
-};
+use crate::{executor::cache::cache_root_init, scheduler::task_deque::TASK_DEQUE};
 
 #[derive(Debug, Builder)]
 #[builder(setter(into))]
@@ -124,6 +122,16 @@ impl DadkUserExecuteContextBuilder {
     }
 }
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum Action {
+    /// 构建所有项目
+    Build,
+    /// 清理缓存
+    Clean(UserCleanLevel),
+    /// 安装到DragonOS sysroot
+    Install,
+}
+
 #[cfg(test)]
 pub struct DadkExecuteContextTestBuildX86_64V1 {
     context: Arc<DadkUserExecuteContext>,

+ 2 - 3
dadk-user/src/executor/cache.rs

@@ -11,7 +11,7 @@ use crate::{
         task_log::TaskLog,
     },
     scheduler::SchedEntity,
-    utils::lazy_init::Lazy,
+    utils::{lazy_init::Lazy, path::abs_path},
 };
 
 use super::ExecutorError;
@@ -143,8 +143,7 @@ impl CacheDir {
                 )
             }
         };
-
-        return PathBuf::from(cache_dir);
+        abs_path(&PathBuf::from(cache_dir))
     }
 
     pub fn build_dir(entity: Arc<SchedEntity>) -> Result<PathBuf, ExecutorError> {

+ 12 - 15
dadk-user/src/executor/mod.rs

@@ -6,18 +6,18 @@ use std::{
     sync::{Arc, RwLock},
 };
 
+use dadk_config::user::UserCleanLevel;
 use log::{debug, error, info, warn};
 
 use crate::{
-    console::{clean::CleanLevel, Action},
-    context::DadkUserExecuteContext,
+    context::{Action, DadkUserExecuteContext},
     executor::cache::CacheDir,
     parser::{
         task::{CodeSource, PrebuiltSource, TaskEnv, TaskType},
         task_log::{BuildStatus, InstallStatus, TaskLog},
     },
     scheduler::{SchedEntities, SchedEntity},
-    utils::file::FileUtils,
+    utils::{file::FileUtils, path::abs_path},
 };
 
 use self::cache::{CacheDirType, TaskDataDir};
@@ -133,8 +133,6 @@ impl Executor {
                 task_log.clean_build_status();
                 task_log.clean_install_status();
             }
-
-            _ => {}
         }
 
         self.task_data_dir
@@ -166,9 +164,6 @@ impl Executor {
                     );
                 }
             }
-            _ => {
-                error!("Unsupported action: {:?}", self.action);
-            }
         }
 
         return Ok(());
@@ -234,7 +229,7 @@ impl Executor {
             in_dragonos_path = in_dragonos_path[count_leading_slashes..].to_string();
         }
         // 拼接最终的安装路径
-        let install_path = self.dragonos_sysroot.join(in_dragonos_path);
+        let install_path = abs_path(&self.dragonos_sysroot.join(in_dragonos_path));
         debug!("install_path: {:?}", install_path);
         // 创建安装路径
         std::fs::create_dir_all(&install_path).map_err(|e| {
@@ -257,7 +252,7 @@ impl Executor {
 
     fn clean(&self) -> Result<(), ExecutorError> {
         let level = if let Action::Clean(l) = self.action {
-            l.level
+            l
         } else {
             panic!(
                 "BUG: clean() called with non-clean action. executor details: {:?}",
@@ -265,15 +260,17 @@ impl Executor {
             );
         };
         info!(
-            "Cleaning task: {}, level={level}",
+            "Cleaning task: {}, level={level:?}",
             self.entity.task().name_version()
         );
 
         let r: Result<(), ExecutorError> = match level {
-            CleanLevel::All => self.clean_all(),
-            CleanLevel::Src => self.clean_src(),
-            CleanLevel::Target => self.clean_target(),
-            CleanLevel::Cache => self.clean_cache(),
+            UserCleanLevel::All => self.clean_all(),
+            UserCleanLevel::InSrc => self.clean_src(),
+            UserCleanLevel::Output => {
+                self.clean_target()?;
+                self.clean_cache()
+            }
         };
 
         if let Err(e) = r {

+ 4 - 14
dadk-user/src/lib.rs

@@ -98,30 +98,20 @@ extern crate test_base;
 
 use std::{path::PathBuf, process::exit, sync::Arc};
 
+use context::DadkUserExecuteContext;
 use log::info;
 use parser::task::DADKTask;
 
-use crate::{
-    console::CommandLineArgs, context::DadkUserExecuteContextBuilder, scheduler::Scheduler,
-};
+use crate::scheduler::Scheduler;
 
-pub mod console;
-mod context;
+pub mod context;
 pub mod executor;
 pub mod parser;
 mod scheduler;
 pub mod static_resources;
 mod utils;
 
-pub fn dadk_user_main(args: CommandLineArgs) {
-    let context = DadkUserExecuteContextBuilder::default()
-        .sysroot_dir(args.sysroot_dir)
-        .config_dir(args.config_dir)
-        .action(args.action)
-        .thread_num(args.thread)
-        .cache_dir(args.cache_dir)
-        .build()
-        .expect("Failed to build execute context");
+pub fn dadk_user_main(context: DadkUserExecuteContext) {
     let context = Arc::new(context);
     context.init(context.clone());
     // DragonOS sysroot在主机上的路径

+ 2 - 1
dadk-user/src/parser/config.rs

@@ -1,10 +1,11 @@
 use std::path::PathBuf;
 
+use dadk_config::common::target_arch::TargetArch;
 use serde::de::Error;
 use toml::Value;
 
 use super::{
-    task::{Dependency, TargetArch, TaskEnv},
+    task::{Dependency, TaskEnv},
     InnerParserError, ParserError,
 };
 

+ 2 - 81
dadk-user/src/parser/task.rs

@@ -1,6 +1,7 @@
 use std::path::PathBuf;
 
-use serde::{de::Error, Deserialize, Deserializer, Serialize};
+use dadk_config::common::target_arch::TargetArch;
+use serde::{de::Error, Deserialize, Serialize};
 
 use crate::executor::source::{ArchiveSource, GitSource, LocalSource};
 
@@ -565,83 +566,3 @@ impl TaskEnv {
         return Ok(());
     }
 }
-
-/// 目标处理器架构
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-pub enum TargetArch {
-    Aarch64,
-    X86_64,
-    RiscV64,
-    RiscV32,
-}
-
-impl TargetArch {
-    /// 期望的目标处理器架构(如果修改了枚举,那一定要修改这里)
-    pub const EXPECTED: [&'static str; 4] = ["aarch64", "x86_64", "riscv64", "riscv32"];
-}
-
-impl Default for TargetArch {
-    fn default() -> Self {
-        TargetArch::X86_64
-    }
-}
-
-impl TryFrom<&str> for TargetArch {
-    type Error = String;
-
-    fn try_from(value: &str) -> Result<Self, Self::Error> {
-        match value.trim().to_ascii_lowercase().as_str() {
-            "aarch64" => Ok(TargetArch::Aarch64),
-            "x86_64" => Ok(TargetArch::X86_64),
-            "riscv64" => Ok(TargetArch::RiscV64),
-            "riscv32" => Ok(TargetArch::RiscV32),
-            _ => Err(format!("Unknown target arch: {}", value)),
-        }
-    }
-}
-
-impl Into<&str> for TargetArch {
-    fn into(self) -> &'static str {
-        match self {
-            TargetArch::Aarch64 => "aarch64",
-            TargetArch::X86_64 => "x86_64",
-            TargetArch::RiscV64 => "riscv64",
-            TargetArch::RiscV32 => "riscv32",
-        }
-    }
-}
-
-impl Into<String> for TargetArch {
-    fn into(self) -> String {
-        let x: &str = self.into();
-        x.to_string()
-    }
-}
-
-impl<'de> Deserialize<'de> for TargetArch {
-    fn deserialize<D>(deserializer: D) -> Result<TargetArch, D::Error>
-    where
-        D: Deserializer<'de>,
-    {
-        let s = String::deserialize(deserializer)?;
-
-        let r = TargetArch::try_from(s.as_str());
-        match r {
-            Ok(v) => Ok(v),
-            Err(_) => Err(serde::de::Error::invalid_value(
-                serde::de::Unexpected::Str(s.as_str()),
-                &format!("Expected one of {:?}", TargetArch::EXPECTED).as_str(),
-            )),
-        }
-    }
-}
-
-impl Serialize for TargetArch {
-    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
-    where
-        S: serde::Serializer,
-    {
-        let string: String = Into::into(*self);
-        serializer.serialize_str(string.as_str())
-    }
-}

+ 1 - 3
dadk-user/src/scheduler/mod.rs

@@ -13,8 +13,7 @@ use std::{
 use log::{error, info};
 
 use crate::{
-    console::Action,
-    context::DadkUserExecuteContext,
+    context::{Action, DadkUserExecuteContext},
     executor::{target::Target, Executor},
     parser::task::DADKTask,
 };
@@ -450,7 +449,6 @@ impl Scheduler {
                 self.run_with_topo_sort()?;
             }
             Action::Clean(_) => self.run_without_topo_sort()?,
-            _ => unimplemented!(),
         }
 
         return Ok(());

+ 1 - 1
dadk-user/src/scheduler/task_deque.rs

@@ -4,7 +4,7 @@ use std::{
     thread::JoinHandle,
 };
 
-use crate::{console::Action, scheduler::TID_EID};
+use crate::{context::Action, scheduler::TID_EID};
 
 use super::{SchedEntity, Scheduler};
 

+ 2 - 1
dadk-user/src/scheduler/tests.rs

@@ -1,3 +1,4 @@
+use dadk_config::common::target_arch::TargetArch;
 use test_base::{
     global::BaseGlobalTestContext,
     test_context::{self as test_context, test_context},
@@ -7,7 +8,7 @@ use crate::{
     context::{
         DadkExecuteContextTestBuildRiscV64V1, DadkExecuteContextTestBuildX86_64V1, TestContextExt,
     },
-    parser::{task::TargetArch, Parser},
+    parser::Parser,
 };
 
 use super::*;

+ 1 - 0
dadk-user/src/utils/mod.rs

@@ -1,3 +1,4 @@
 pub mod file;
 pub mod lazy_init;
+pub mod path;
 pub mod stdio;

+ 10 - 0
dadk-user/src/utils/path.rs

@@ -0,0 +1,10 @@
+use std::path::PathBuf;
+
+/// 获取给定路径的绝对路径
+pub fn abs_path(path: &PathBuf) -> PathBuf {
+    if path.is_absolute() {
+        path.to_path_buf()
+    } else {
+        std::env::current_dir().unwrap().join(path)
+    }
+}

+ 2 - 1
dadk-user/tests/test_parse_dadk_user_config.rs

@@ -1,11 +1,12 @@
 use std::path::PathBuf;
 
+use dadk_config::common::target_arch::TargetArch;
 use dadk_user::{
     executor::source::{ArchiveSource, GitSource, LocalSource},
     parser::{
         task::{
             BuildConfig, CleanConfig, CodeSource, DADKTask, Dependency, InstallConfig,
-            PrebuiltSource, TargetArch, TaskEnv, TaskType,
+            PrebuiltSource, TaskEnv, TaskType,
         },
         Parser,
     },

+ 10 - 0
dadk/Cargo.toml

@@ -19,9 +19,19 @@ name = "dadk"
 path = "src/main.rs"
 doc = true
 
+# 这个target与上面的内容一样,
+# 只是为了方便在开发,测试时使用(不会跟正式版本的dadk冲突)
+[[bin]]
+name = "dadk-insiders"
+path = "src/main.rs"
+doc = true
+
 
 [dependencies]
 anyhow = { version = "1.0.90", features = ["std", "backtrace"] }
+clap = { version = "4.5.20", features = ["derive"] }
+dadk-config = { path = "../dadk-config" }
 dadk-user = { path = "../dadk-user" }
+derive_builder = "0.20.0"
 env_logger = "0.11.5"
 log = "0.4.22"

+ 17 - 0
dadk/src/actions/mod.rs

@@ -0,0 +1,17 @@
+use crate::context::DADKExecContext;
+
+pub mod user;
+
+pub fn run(ctx: DADKExecContext) {
+    match &ctx.command.action {
+        crate::console::Action::Kernel => {
+            unimplemented!("kernel command has not implemented for run yet.")
+        }
+        crate::console::Action::Rootfs(_rootfs_command) => {
+            unimplemented!("rootfs command has not implemented for run yet.")
+        }
+        crate::console::Action::User(user_command) => {
+            user::run(&ctx, user_command).expect("Run user action error.")
+        }
+    }
+}

+ 23 - 0
dadk/src/actions/user.rs

@@ -0,0 +1,23 @@
+use anyhow::Result;
+use dadk_user::dadk_user_main;
+
+use crate::{console::user::UserCommand, context::DADKExecContext};
+
+pub(super) fn run(ctx: &DADKExecContext, cmd: &UserCommand) -> Result<()> {
+    let config_dir = ctx.user_config_dir()?;
+    let cache_root_dir = ctx.cache_root_dir()?;
+    let sysroot_dir = ctx.sysroot_dir()?;
+    let dadk_user_action: dadk_user::context::Action = cmd.clone().into();
+
+    let context = dadk_user::context::DadkUserExecuteContextBuilder::default()
+        .sysroot_dir(sysroot_dir)
+        .config_dir(config_dir)
+        .action(dadk_user_action)
+        .thread_num(1)
+        .cache_dir(cache_root_dir)
+        .target_arch(ctx.target_arch())
+        .build()
+        .expect("Failed to build execute context");
+    dadk_user_main(context);
+    Ok(())
+}

+ 0 - 6
dadk/src/console.rs

@@ -1,6 +0,0 @@
-use dadk_user::clap::Parser;
-use dadk_user::console::CommandLineArgs;
-
-pub fn parse_commandline_args() -> CommandLineArgs {
-    CommandLineArgs::parse()
-}

+ 38 - 0
dadk/src/console/mod.rs

@@ -0,0 +1,38 @@
+use clap::{Parser, Subcommand};
+use rootfs::RootFSCommand;
+use user::UserCommand;
+
+pub mod rootfs;
+#[cfg(test)]
+mod tests;
+pub mod user;
+
+#[derive(Debug, Parser, Clone)]
+#[command(author, version, about)]
+pub struct CommandLineArgs {
+    /// 要执行的操作
+    #[command(subcommand)]
+    pub action: Action,
+
+    /// dadk manifest 配置文件的路径
+    #[arg(
+        short = 'f',
+        long = "manifest",
+        default_value = "dadk-manifest.toml",
+        global = true
+    )]
+    pub manifest_path: String,
+
+    /// DADK 的工作目录
+    #[arg(short = 'w', long = "workdir", default_value = ".", global = true)]
+    pub workdir: String,
+}
+
+#[derive(Debug, Subcommand, Clone, PartialEq, Eq)]
+pub enum Action {
+    Kernel,
+    #[command(subcommand, name = "rootfs")]
+    Rootfs(RootFSCommand),
+    #[command(subcommand, name = "user")]
+    User(UserCommand),
+}

+ 16 - 0
dadk/src/console/rootfs.rs

@@ -0,0 +1,16 @@
+use clap::{Parser, ValueEnum};
+
+// 定义一个枚举类型 RootFSCommand,表示根文件系统操作命令
+#[derive(Debug, Parser, Clone, PartialEq, Eq, ValueEnum)]
+pub enum RootFSCommand {
+    /// 创建根文件系统(磁盘镜像)
+    Create,
+    /// 删除根文件系统(磁盘镜像)
+    Delete,
+    /// 删除系统根目录(sysroot文件夹)
+    DeleteSysroot,
+    /// 挂载根文件系统(磁盘镜像)
+    Mount,
+    /// 卸载根文件系统(磁盘镜像)
+    Unmount,
+}

+ 64 - 0
dadk/src/console/tests.rs

@@ -0,0 +1,64 @@
+use user::UserCleanLevel;
+
+use super::*;
+
+#[test]
+fn test_command_line_args_default() {
+    let args = CommandLineArgs::parse_from(&["dadk", "kernel"]);
+    assert_eq!(args.action, Action::Kernel);
+    assert_eq!(args.manifest_path, "dadk-manifest.toml");
+}
+
+#[test]
+fn test_command_line_args_with_manifest() {
+    // test short
+    let args = CommandLineArgs::parse_from(&["dadk", "-f", "custom-manifest.toml", "kernel"]);
+    assert_eq!(args.action, Action::Kernel);
+    assert_eq!(args.manifest_path, "custom-manifest.toml");
+    // test long
+    let args =
+        CommandLineArgs::parse_from(&["dadk", "--manifest", "custom-manifest.toml", "kernel"]);
+    assert_eq!(args.action, Action::Kernel);
+    assert_eq!(args.manifest_path, "custom-manifest.toml");
+}
+
+#[test]
+fn test_command_line_args_rootfs_subcommand() {
+    let args = CommandLineArgs::parse_from(&["dadk", "rootfs", "create"]);
+    assert!(matches!(args.action, Action::Rootfs(RootFSCommand::Create)));
+}
+
+#[test]
+fn test_command_line_args_user() {
+    let args = CommandLineArgs::parse_from(&["dadk", "user", "build"]);
+
+    assert!(matches!(args.action, Action::User(UserCommand::Build)));
+}
+
+/// 该函数测试CommandLineArgs解析器是否正确解析`dadk user clean`命令
+#[test]
+fn test_command_line_args_user_clean() {
+    let args = CommandLineArgs::parse_from(&["dadk", "user", "clean"]);
+    assert!(matches!(args.action, Action::User(UserCommand::Clean(_))));
+    if let Action::User(UserCommand::Clean(args)) = args.action {
+        assert_eq!(args.level, UserCleanLevel::All);
+    } else {
+        panic!("Expected UserCommand::Clean");
+    }
+
+    // 检查 `--level` 参数
+    let args = CommandLineArgs::parse_from(&["dadk", "user", "clean", "--level", "in-src"]);
+    if let Action::User(UserCommand::Clean(args)) = args.action {
+        assert_eq!(args.level, UserCleanLevel::InSrc);
+    } else {
+        panic!("Expected UserCommand::Clean");
+    }
+
+    // 检查 `--task` 参数
+    let args = CommandLineArgs::parse_from(&["dadk", "user", "clean", "--task", "a-0.1.0"]);
+    if let Action::User(UserCommand::Clean(args)) = args.action {
+        assert_eq!(args.task, Some("a-0.1.0".to_string()));
+    } else {
+        panic!("Expected UserCommand::Clean");
+    }
+}

+ 74 - 0
dadk/src/console/user.rs

@@ -0,0 +1,74 @@
+use clap::{Parser, Subcommand, ValueEnum};
+
+#[derive(Debug, Subcommand, Clone, PartialEq, Eq)]
+pub enum UserCommand {
+    Build,
+    Clean(UserCleanCommand),
+    Install,
+}
+
+#[derive(Debug, Parser, Clone, PartialEq, Eq)]
+pub struct UserCleanCommand {
+    /// 清理级别
+    #[clap(long, default_value = "all")]
+    pub level: UserCleanLevel,
+    /// 要清理的task
+    #[clap(long)]
+    pub task: Option<String>,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
+pub enum UserCleanLevel {
+    /// 清理所有用户程序构建缓存
+    All,
+    /// 只在用户程序源码目录下清理
+    InSrc,
+    /// 只清理用户程序输出目录
+    Output,
+}
+
+impl Into<dadk_config::user::UserCleanLevel> for UserCleanLevel {
+    fn into(self) -> dadk_config::user::UserCleanLevel {
+        match self {
+            UserCleanLevel::All => dadk_config::user::UserCleanLevel::All,
+            UserCleanLevel::InSrc => dadk_config::user::UserCleanLevel::InSrc,
+            UserCleanLevel::Output => dadk_config::user::UserCleanLevel::Output,
+        }
+    }
+}
+
+impl Into<dadk_user::context::Action> for UserCommand {
+    fn into(self) -> dadk_user::context::Action {
+        match self {
+            UserCommand::Build => dadk_user::context::Action::Build,
+            UserCommand::Install => dadk_user::context::Action::Install,
+            UserCommand::Clean(args) => dadk_user::context::Action::Clean(args.level.into()),
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+
+    use super::*;
+
+    #[test]
+    fn test_user_clean_level_from_str() {
+        // Test valid cases
+        assert_eq!(
+            UserCleanLevel::from_str("all", true).unwrap(),
+            UserCleanLevel::All
+        );
+        assert_eq!(
+            UserCleanLevel::from_str("in-src", true).unwrap(),
+            UserCleanLevel::InSrc
+        );
+        assert_eq!(
+            UserCleanLevel::from_str("output", true).unwrap(),
+            UserCleanLevel::Output
+        );
+
+        // Test invalid case
+        assert!(UserCleanLevel::from_str("invalid", true).is_err());
+    }
+}

+ 24 - 0
dadk/src/context/manifest.rs

@@ -0,0 +1,24 @@
+use std::{path::PathBuf, str::FromStr};
+
+use crate::utils::abs_path;
+
+use super::DADKExecContextBuilder;
+use anyhow::{anyhow, Result};
+use dadk_config::manifest::DadkManifestFile;
+
+pub(super) fn parse_manifest(builder: &mut DADKExecContextBuilder) -> Result<()> {
+    let manifest_path = PathBuf::from_str(&builder.command.as_ref().unwrap().manifest_path)
+        .map_err(|e| anyhow::anyhow!("Failed to get manifest path: {}", e))?;
+
+    let workdir = builder.command.as_ref().unwrap().workdir.clone();
+
+    // 将相对路径转换为基于workdir的绝对路径
+    let manifest_path = abs_path(&PathBuf::from(workdir)).join(manifest_path);
+
+    if !manifest_path.exists() || !manifest_path.is_file() {
+        return Err(anyhow!("Manifest path does not exist or is not a file"));
+    }
+    let dadk_manifest_file = DadkManifestFile::load(&manifest_path)?;
+    builder.manifest = Some(dadk_manifest_file);
+    Ok(())
+}

+ 86 - 0
dadk/src/context/mod.rs

@@ -0,0 +1,86 @@
+use std::{cell::OnceCell, path::PathBuf};
+
+use anyhow::Result;
+use clap::Parser;
+use dadk_config::{
+    common::target_arch::TargetArch, manifest::DadkManifestFile, rootfs::RootFSConfigFile,
+};
+use derive_builder::Builder;
+use manifest::parse_manifest;
+
+use crate::{
+    console::CommandLineArgs,
+    utils::{abs_path, check_dir_exists},
+};
+
+mod manifest;
+
+/// DADK的执行上下文
+#[derive(Debug, Clone, Builder)]
+pub struct DADKExecContext {
+    pub command: CommandLineArgs,
+    /// DADK manifest file
+    pub manifest: DadkManifestFile,
+
+    /// RootFS config file
+    rootfs: OnceCell<RootFSConfigFile>,
+}
+
+pub fn build_exec_context() -> Result<DADKExecContext> {
+    let mut builder = DADKExecContextBuilder::create_empty();
+    builder.command(CommandLineArgs::parse());
+    builder.rootfs(OnceCell::new());
+    parse_manifest(&mut builder).expect("Failed to parse manifest");
+    let ctx = builder.build()?;
+    ctx.setup_workdir().expect("Failed to setup workdir");
+    Ok(ctx)
+}
+
+impl DADKExecContext {
+    /// 获取工作目录的绝对路径
+    pub fn workdir(&self) -> PathBuf {
+        abs_path(&PathBuf::from(&self.command.workdir))
+    }
+
+    /// 设置进程的工作目录
+    fn setup_workdir(&self) -> Result<()> {
+        std::env::set_current_dir(&self.workdir()).expect("Failed to set current directory");
+        Ok(())
+    }
+    /// Get rootfs configuration
+    pub fn rootfs(&self) -> &RootFSConfigFile {
+        self.rootfs.get_or_init(|| {
+            RootFSConfigFile::load(&self.manifest.metadata.rootfs_config)
+                .expect("Failed to load rootfs config")
+        })
+    }
+
+    /// Get sysroot directory
+    ///
+    /// If the directory does not exist, or the path is not a folder, an error is returned
+    pub fn sysroot_dir(&self) -> Result<PathBuf> {
+        check_dir_exists(&self.manifest.metadata.sysroot_dir)
+            .map(|p| p.clone())
+            .map_err(|e| anyhow::anyhow!("Failed to get sysroot dir: {}", e))
+    }
+
+    /// Get cache root directory
+    ///
+    /// If the directory does not exist, or the path is not a folder, an error is returned
+    pub fn cache_root_dir(&self) -> Result<PathBuf> {
+        check_dir_exists(&self.manifest.metadata.cache_root_dir)
+            .map(|p| p.clone())
+            .map_err(|e| anyhow::anyhow!("Failed to get cache root dir: {}", e))
+    }
+
+    #[deprecated]
+    pub fn user_config_dir(&self) -> Result<PathBuf> {
+        check_dir_exists(&self.manifest.metadata.user_config_dir)
+            .map(|p| p.clone())
+            .map_err(|e| anyhow::anyhow!("Failed to get user config dir: {}", e))
+    }
+
+    pub fn target_arch(&self) -> TargetArch {
+        self.manifest.metadata.arch
+    }
+}

+ 10 - 9
dadk/src/lib.rs

@@ -1,14 +1,15 @@
-use console::parse_commandline_args;
-use dadk_user::dadk_user_main;
-use log::info;
-
-extern crate anyhow;
+use context::build_exec_context;
 
+mod actions;
 mod console;
+mod context;
+mod utils;
 
-pub fn dadk_main() {
-    let args = parse_commandline_args();
-    info!("DADK run with args: {:?}", &args);
+extern crate anyhow;
 
-    dadk_user_main(args);
+pub fn dadk_main() {
+    // dadk_user_main();
+    let exec_ctx = build_exec_context().expect("Failed to build execution context");
+    log::debug!("Execution context: {:?}", exec_ctx);
+    actions::run(exec_ctx);
 }

+ 24 - 0
dadk/src/utils.rs

@@ -0,0 +1,24 @@
+use std::path::PathBuf;
+
+use anyhow::{anyhow, Result};
+
+/// 检查目录是否存在
+pub(super) fn check_dir_exists<'a>(path: &'a PathBuf) -> Result<&'a PathBuf> {
+    if !path.exists() {
+        return Err(anyhow!("Path '{}' not exists", path.display()));
+    }
+    if !path.is_dir() {
+        return Err(anyhow!("Path '{}' is not a directory", path.display()));
+    }
+
+    return Ok(path);
+}
+
+/// 获取给定路径的绝对路径
+pub fn abs_path(path: &PathBuf) -> PathBuf {
+    if path.is_absolute() {
+        path.to_path_buf()
+    } else {
+        std::env::current_dir().unwrap().join(path)
+    }
+}

+ 25 - 0
tests/data/dadk-manifest.toml

@@ -0,0 +1,25 @@
+# Configuration template placed in the root directory of the DragonOS workspace
+# Named `dadk-manifest.toml`
+
+[metadata]
+# Target architecture. Options: x86_64, riscv64
+arch = "x86_64"
+
+# Hypervisor config path
+hypervisor-config = "config/hypervisor.toml"
+
+# RootFS config path
+rootfs-config = "config/rootfs.toml"
+
+# Boot config path
+boot-config = "config/boot.toml"
+
+# System root directory folder (DADK will copy the files in this directory to the root directory of the disk image)
+sysroot-dir = "fake_dragonos_sysroot"
+
+# DADK Root Cache directory path
+cache-root-dir = "fake_dadk_cache_root"
+
+# User configuration directory path
+# 这个字段只是临时用于兼容旧版本,v0.2版本重构完成后会删除
+user-config-dir = "dadk_config_v1"

+ 0 - 1
tests/data/dadk_config_v1/app_all_target_arch_0_1_0.dadk

@@ -27,7 +27,6 @@
   "install_once": false,
   "target_arch": [
     "riscv64",
-    "riscv32",
     "x86_64",
     "aarch64"
   ]

+ 1 - 1
tests/data/dadk_config_v2/app_all_target_arch_0_2_0.toml

@@ -3,7 +3,7 @@ version = "0.2.0"
 description = "An app targets to all arch"
 build-once = false
 install-once = false
-target-arch = ["riscv64", "riscv32", "x86_64", "aarch64"]
+target-arch = ["riscv64", "x86_64", "aarch64"]
 
 [task-type]
 type = "build_from_source"