xref: /DADK/dadk-user/src/lib.rs (revision 73779f3d0abacaf05aae9b67820e68f4bb9cf53f)
1 //! # DADK - DragonOS Application Development Kit
2 //! # DragonOS 应用开发工具
3 //!
4 //! ## 简介
5 //!
6 //! DADK是一个用于开发DragonOS应用的工具包,设计目的是为了让开发者能够更加方便的开发DragonOS应用。
7 //!
8 //! ### DADK做什么?
9 //!
10 //! - 自动配置libc等编译用户程序所需的环境
11 //! - 自动处理软件库的依赖关系
12 //! - 自动处理软件库的编译
13 //! - 一键将软件库安装到DragonOS系统中
14 //!
15 //! ### DADK不做什么?
16 //!
17 //! - DADK不会帮助开发者编写代码
18 //! - DADK不提供任何开发DragonOS应用所需的API。这部分工作由libc等库来完成
19 //!
20 //! ## License
21 //!
22 //! DADK is licensed under the [GPLv2 License](https://www.gnu.org/licenses/old-licenses/gpl-2.0.html).
23 //!
24 //! ## 快速开始
25 //!
26 //! ### 安装DADK
27 //!
28 //! DADK是一个Rust程序,您可以通过Cargo来安装DADK。
29 //!
30 //! ```shell
31 //! # 从GitHub安装最新版
32 //! cargo install --git https://github.com/DragonOS-Community/DADK.git
33 //!
34 //! # 从crates.io下载
35 //! cargo install dadk
36 //!
37 //! ```
38 //!
39 //! ## DADK的工作原理
40 //!
41 //! DADK使用(任务名,任务版本)来标识每个构建目标。当使用DADK构建DragonOS应用时,DADK会根据用户的配置文件,自动完成以下工作:
42 //!
43 //! - 解析配置文件,生成DADK任务列表
44 //! - 根据DADK任务列表,进行拓扑排序。这一步会自动处理软件库的依赖关系。
45 //! - 收集环境变量信息,并根据DADK任务列表,设置全局环境变量、任务环境变量。
46 //! - 根据拓扑排序后的DADK任务列表,自动执行任务。
47 //!
48 //! ### DADK与环境变量
49 //!
50 //! 环境变量的设置是DADK能正常工作的关键因素之一,您可以在您的编译脚本中,通过引用环境变量,来获得其他软件库的编译信息。
51 //! 这是使得您的应用能够自动依赖其他软件库的关键一步。
52 //!
53 //! 只要您的编译脚本能够正确地引用环境变量,DADK就能够自动处理软件库的依赖关系。
54 //!
55 //! DADK会设置以下全局环境变量:
56 //!
57 //! - `DADK_CACHE_ROOT`:DADK的缓存根目录。您可以在编译脚本中,通过引用该环境变量,来获得DADK的缓存根目录。
58 //! - `DADK_BUILD_CACHE_DIR_任务名_任务版本`:DADK的任务构建结果缓存目录。当您要引用其他软件库的构建结果时,可以通过该环境变量来获得。
59 //! 同时,您也要在构建您的app时,把构建结果放到您的软件库的构建结果缓存目录(通过对应的环境变量获得)中。
60 //! - `DADK_SOURCE_CACHE_DIR_任务名_任务版本`:DADK的某个任务的源码目录。当您要引用其他软件库的源码目录时,可以通过该环境变量来获得。
61 //!
62 //! 同时,DADK会为每个任务设置其自身在配置文件中指定的环境变量。
63 //!
64 //! #### 全局环境变量命名格式
65 //!
66 //! 全局环境变量中的任务名和任务版本,都会被转换为大写字母,并对特殊字符进行替换。替换表如下:
67 //!
68 //! | 原字符 | 替换字符 |
69 //! | ------ | -------- |
70 //! | `.`    | `_`      |
71 //! | `-`    | `_`      |
72 //! | `\t`   | `_`      |
73 //! | 空格   | `_`      |
74 //! | `+`    | `_`      |
75 //! | `*`    | `_`      |
76 //!
77 //! **举例**:对于任务`libc-0.1.0`,其构建结果的全局环境变量名为`DADK_BUILD_CACHE_DIR_LIBC_0_1_0`。
78 //!
79 //!
80 //! ## TODO
81 //!
82 //! - 支持从在线归档文件下载源码、构建好的软件库
83 //! - 支持自动更新
84 //! - 完善clean命令的逻辑
85 
86 #![feature(extract_if)]
87 #![feature(io_error_more)]
88 
89 #[macro_use]
90 extern crate lazy_static;
91 extern crate log;
92 extern crate serde;
93 extern crate serde_json;
94 
95 #[cfg(test)]
96 extern crate test_base;
97 
98 use std::{path::PathBuf, process::exit, sync::Arc};
99 
100 use clap::Parser;
101 
102 use log::{error, info};
103 use parser::task::DADKTask;
104 
105 use crate::{
106     console::{interactive::InteractiveConsole, CommandLineArgs},
107     context::DadkUserExecuteContextBuilder,
108     scheduler::Scheduler,
109 };
110 
111 mod console;
112 mod context;
113 mod executor;
114 pub mod parser;
115 mod scheduler;
116 pub mod static_resources;
117 mod utils;
118 
119 pub fn dadk_user_main() {
120     let args = CommandLineArgs::parse();
121 
122     info!("DADK run with args: {:?}", &args);
123 
124     let context = DadkUserExecuteContextBuilder::default()
125         .sysroot_dir(args.sysroot_dir)
126         .config_dir(args.config_dir)
127         .action(args.action)
128         .thread_num(args.thread)
129         .cache_dir(args.cache_dir)
130         .build()
131         .expect("Failed to build execute context");
132     let context = Arc::new(context);
133     context.init(context.clone());
134     // DragonOS sysroot在主机上的路径
135 
136     info!(
137         "DragonOS sysroot dir: {}",
138         context
139             .sysroot_dir()
140             .map_or_else(|| "None".to_string(), |d| d.display().to_string())
141     );
142     info!(
143         "Config dir: {}",
144         context
145             .config_dir()
146             .map_or_else(|| "None".to_string(), |d| d.display().to_string())
147     );
148     info!("Action: {:?}", context.action());
149     info!(
150         "Thread num: {}",
151         context.thread_num().map_or_else(|| 0, |t| t)
152     );
153 
154     match context.action() {
155         console::Action::New => {
156             let r = InteractiveConsole::new(
157                 context.sysroot_dir().cloned(),
158                 context.config_dir().cloned(),
159                 *context.action(),
160             )
161             .run();
162             if r.is_err() {
163                 error!("Failed to run interactive console: {:?}", r.unwrap_err());
164                 exit(1);
165             }
166             exit(0);
167         }
168         _ => {}
169     }
170 
171     let mut parser = parser::Parser::new(context.config_dir().unwrap().clone());
172     let r = parser.parse();
173     if r.is_err() {
174         exit(1);
175     }
176     let tasks: Vec<(PathBuf, DADKTask)> = r.unwrap();
177     // info!("Parsed tasks: {:?}", tasks);
178 
179     let scheduler = Scheduler::new(
180         context.clone(),
181         context.sysroot_dir().cloned().unwrap(),
182         *context.action(),
183         tasks,
184     );
185     if scheduler.is_err() {
186         exit(1);
187     }
188 
189     let r = scheduler.unwrap().run();
190     if r.is_err() {
191         exit(1);
192     }
193 }
194