1pub mod app_error;
2pub mod args;
3pub mod binengine;
4pub mod conf;
5pub mod job;
6pub mod lock;
7pub mod pm;
8pub mod report;
9pub mod toolchain;
10pub mod x;
11
12pub use app_error::AppError;
13use args::Commands;
14use home::home_dir;
15pub use o_core::engine;
16use o_core::engine::JSEngine;
17pub use o_core::error;
18use std::fs;
19use std::path::PathBuf;
20
21use crate::args::ToolChainCommand;
22use crate::binengine::BinEngine;
23use crate::pm::global_install;
24use crate::report::Report;
25
26pub fn process(args: Commands, toolchain: Option<&str>) -> Result<(), AppError> {
27 match args {
28 Commands::Run { path } => {
29 let toolchain_name = toolchain.unwrap_or("").trim().to_string();
30 let selected_toolchain = select_toolchain(&toolchain_name)?;
31 run(&path, &toolchain_name, selected_toolchain)
32 }
33 Commands::Toolchain { command } => {
34 let report = run_toolchain(command)?;
35 report::print(&report);
36 Ok(())
37 }
38 Commands::Install { global, package } => {
39 if global {
40 let report =
41 global_install(package.as_deref()).map_err(AppError::PackageManager)?;
42 report::print(&report);
43 Ok(())
44 } else {
45 let report = pm::install().map_err(AppError::PackageManager)?;
46 report::print(&report);
47 Ok(())
48 }
49 }
50 Commands::Uninstall { name } => {
51 let report = pm::uninstall(&name).map_err(AppError::PackageManager)?;
52 report::print(&report);
53 Ok(())
54 }
55 Commands::Job { name } => {
56 job::run(&name).map_err(AppError::Job)?;
57 Ok(())
58 }
59 }
60}
61
62fn run_toolchain(command: ToolChainCommand) -> Result<Report, AppError> {
63 match command {
64 ToolChainCommand::Add { user, repo } => {
65 let mut installed =
66 toolchain::install("github.com", &user, &repo).map_err(|source| {
67 AppError::InstallToolchain {
68 user: user.clone(),
69 repo: repo.clone(),
70 source: source.to_string(),
71 }
72 })?;
73 installed.push("bin");
74 installed.push(&repo);
75 let mut target = home_dir().ok_or(AppError::HomeDirUnavailable)?;
76 target.push(".config");
77 target.push("o-");
78 target.push("toolchains");
79 target.push("bin");
80 target.push(&repo);
81 if let Some(parent) = target.parent() {
82 fs::create_dir_all(parent).map_err(|source| AppError::CreateDir {
83 path: parent.to_path_buf(),
84 source,
85 })?;
86 }
87 fs::rename(&installed, &target).map_err(|source| AppError::MoveToolchain {
88 from: installed.clone(),
89 to: target.clone(),
90 source,
91 })?;
92
93 Ok(Report::new(format!("installed toolchain `{repo}`"))
94 .detail(format!("source: {user}/{repo}"))
95 .detail(format!("binary: {}", target.display())))
96 }
97 ToolChainCommand::Remove { toolchain } => {
98 let mut target = home::home_dir().ok_or(AppError::HomeDirUnavailable)?;
99 target.push(".config");
100 target.push("o-");
101 target.push("toolchains");
102 target.push("bin");
103 target.push(&toolchain);
104 fs::remove_file(&target).map_err(|source| AppError::RemoveToolchain {
105 path: target.clone(),
106 source,
107 })?;
108
109 Ok(Report::new(format!("removed toolchain `{toolchain}`"))
110 .detail(format!("path: {}", target.display())))
111 }
112 }
113}
114
115fn select_toolchain(toolchain: &str) -> Result<Box<dyn JSEngine>, AppError> {
116 let toolchain = toolchain.trim();
117 if toolchain.is_empty() {
118 return Err(AppError::MissingToolchainSelection);
119 }
120
121 let path = resolve_toolchain_path(toolchain)?;
122 if !path.is_file() {
123 return Err(AppError::ToolchainNotInstalled {
124 toolchain: toolchain.to_string(),
125 path,
126 });
127 }
128
129 Ok(Box::new(BinEngine::new(
130 path.to_string_lossy().into_owned(),
131 )))
132}
133
134fn run(path: &str, toolchain_name: &str, toolchain: Box<dyn JSEngine>) -> Result<(), AppError> {
135 let file = match fs::read_to_string(path) {
136 Ok(file) => file,
137 Err(source) => {
138 return Err(AppError::ReadScript {
139 path: PathBuf::from(path),
140 source,
141 });
142 }
143 };
144
145 if let Err(err) = toolchain.run(&file, path) {
146 return Err(AppError::ToolchainExecution {
147 toolchain: toolchain_name.to_string(),
148 message: err.to_string(),
149 });
150 }
151
152 Ok(())
153}
154
155fn resolve_toolchain_path(name: &str) -> Result<PathBuf, AppError> {
156 let mut toolchain: PathBuf = home_dir().ok_or(AppError::HomeDirUnavailable)?;
157 toolchain.push(".config");
158 toolchain.push("o-");
159 toolchain.push("toolchains");
160 toolchain.push("bin");
161 toolchain.push(name);
162 Ok(toolchain)
163}