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