forked from AbleOS/ableos
183 lines
8.1 KiB
Rust
183 lines
8.1 KiB
Rust
use std::{fs, File};
|
|
use rlisp_library::{Environ, Expr, RispError, parse_eval};
|
|
use crate::packages::{Package, Dependency};
|
|
|
|
pub fn extend_environ<'a>(mut env: Environ<'a>) -> Environ<'a> {
|
|
// Function to create a package
|
|
env.data.insert(
|
|
"package".to_string(),
|
|
Expr::Func(|args: &[Expr]| -> Result<Expr, RispError> {
|
|
if args.len() < 5 {
|
|
return Err(RispError::Reason("package requires name, authors, version, dependencies, and build command".to_string()));
|
|
}
|
|
|
|
let name = match &args[0] {
|
|
Expr::Str(s) => s.clone(),
|
|
_ => return Err(RispError::Reason("package name must be a string".to_string())),
|
|
};
|
|
|
|
let authors = match &args[1] {
|
|
Expr::List(l) => l.iter()
|
|
.map(|a| match a {
|
|
Expr::Str(s) => s.clone(),
|
|
_ => return Err(RispError::Reason("authors must be strings".to_string())),
|
|
})
|
|
.collect(),
|
|
_ => return Err(RispError::Reason("authors must be a list".to_string())),
|
|
};
|
|
|
|
let version = match &args[2] {
|
|
Expr::Str(s) => s.clone(),
|
|
_ => return Err(RispError::Reason("version must be a string".to_string())),
|
|
};
|
|
|
|
let dependencies = match &args[3] {
|
|
Expr::List(l) => l.iter()
|
|
.map(|d| match d {
|
|
Expr::List(dep_list) => {
|
|
if dep_list.len() != 2 {
|
|
return Err(RispError::Reason("dependency must have type and source".to_string()));
|
|
}
|
|
let dep_type = match &dep_list[0] {
|
|
Expr::Symbol(s) => s.clone(),
|
|
_ => return Err(RispError::Reason("dependency type must be a symbol".to_string())),
|
|
};
|
|
let source = match &dep_list[1] {
|
|
Expr::Str(s) => s.clone(),
|
|
_ => return Err(RispError::Reason("dependency source must be a string".to_string())),
|
|
};
|
|
match dep_type.as_str() {
|
|
"library" => Ok(Dependency::Library { source }),
|
|
"binary" => Ok(Dependency::Binary { source }),
|
|
"source" => Ok(Dependency::Source { source }),
|
|
_ => Err(RispError::Reason(format!("Unknown dependency type: {}", dep_type))),
|
|
}
|
|
}
|
|
_ => Err(RispError::Reason("dependency must be a list".to_string())),
|
|
})
|
|
.collect::<Result<Vec<Dependency>, RispError>>()?,
|
|
_ => return Err(RispError::Reason("dependencies must be a list".to_string())),
|
|
};
|
|
|
|
let build_command = match &args[4] {
|
|
Expr::Str(s) => s.clone(),
|
|
_ => return Err(RispError::Reason("build command must be a string".to_string())),
|
|
};
|
|
|
|
let package = Package::new(name, authors, version, dependencies, build_command);
|
|
|
|
// Store the package in the environment
|
|
env.data.insert(
|
|
"current_package".to_string(),
|
|
Expr::Custom(Box::new(package))
|
|
);
|
|
|
|
Ok(Expr::Bool(true))
|
|
}),
|
|
);
|
|
|
|
// Function to get the current package
|
|
env.data.insert(
|
|
"get-package".to_string(),
|
|
Expr::Func(|_args: &[Expr]| -> Result<Expr, RispError> {
|
|
match env.data.get("current_package") {
|
|
Some(pkg) => Ok(pkg.clone()),
|
|
None => Err(RispError::Reason("No package is currently defined".to_string())),
|
|
}
|
|
}),
|
|
);
|
|
|
|
// Package installation function
|
|
env.data.insert(
|
|
"pkg-install".to_string(),
|
|
Expr::Func(|args: &[Expr]| -> Result<Expr, RispError> {
|
|
if args.len() != 2 {
|
|
return Err(RispError::Reason("pkg-install requires repo name and package name".to_string()));
|
|
}
|
|
|
|
let repo_name = match &args[0] {
|
|
Expr::Str(s) => s.clone(),
|
|
_ => return Err(RispError::Reason("repo name must be a string".to_string())),
|
|
};
|
|
|
|
let pkg_name = match &args[1] {
|
|
Expr::Str(s) => s.clone(),
|
|
_ => return Err(RispError::Reason("package name must be a string".to_string())),
|
|
};
|
|
|
|
println!("Installing package {} from repo {}", pkg_name, repo_name);
|
|
|
|
// Create package directory structure
|
|
let pkg_dir = format!("out/programs/{}", pkg_name);
|
|
fs::create_dir_all(&pkg_dir).unwrap();
|
|
fs::create_dir_all(format!("{}/src", pkg_dir)).unwrap();
|
|
|
|
// If package is from :src repo, copy source files
|
|
if repo_name == ":src" {
|
|
// Try original name first
|
|
let src_path = format!("sysdata/programs/{}", pkg_name);
|
|
let underscored_name = pkg_name.replace('-', "_");
|
|
let src_path_alt = format!("sysdata/programs/{}", underscored_name);
|
|
|
|
let (found_path, found_name) = if fs::metadata(&src_path).is_ok() {
|
|
(src_path, pkg_name.clone())
|
|
} else if fs::metadata(&src_path_alt).is_ok() {
|
|
println!("Found source directory with underscored name at {}", src_path_alt);
|
|
(src_path_alt, underscored_name)
|
|
} else {
|
|
return Err(RispError::Reason(format!(
|
|
"Source directory not found for package {} at {} or {}",
|
|
pkg_name, src_path, src_path_alt
|
|
)));
|
|
};
|
|
|
|
// Copy all files from source directory
|
|
for entry in fs::read_dir(&found_path).unwrap() {
|
|
let entry = entry.unwrap();
|
|
let path = entry.path();
|
|
if path.is_file() {
|
|
let file_name = path.file_name().unwrap().to_str().unwrap();
|
|
let dest_path = format!("{}/{}", pkg_dir, file_name);
|
|
println!("Copying {} to {}", path.display(), dest_path);
|
|
fs::copy(&path, &dest_path).unwrap();
|
|
}
|
|
}
|
|
|
|
// Copy contents of src directory if it exists
|
|
let src_src_path = format!("sysdata/programs/{}/src", found_name);
|
|
if fs::metadata(&src_src_path).is_ok() {
|
|
for entry in fs::read_dir(&src_src_path).unwrap() {
|
|
let entry = entry.unwrap();
|
|
let path = entry.path();
|
|
if path.is_file() {
|
|
let file_name = path.file_name().unwrap().to_str().unwrap();
|
|
let dest_path = format!("{}/src/{}", pkg_dir, file_name);
|
|
println!("Copying {} to {}", path.display(), dest_path);
|
|
fs::copy(&path, &dest_path).unwrap();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Read and evaluate meta.rl directly
|
|
let meta_path = format!("sysdata/programs/{}/meta.rl", found_name);
|
|
if let Ok(meta_content) = fs::read_to_string(&meta_path) {
|
|
println!("Evaluating meta.rl for package {}", pkg_name);
|
|
if let Err(e) = parse_eval(&meta_content, &mut env.clone()) {
|
|
println!("Warning: Failed to evaluate meta.rl: {}", e);
|
|
}
|
|
} else {
|
|
println!("Warning: No meta.rl found for package {}", pkg_name);
|
|
}
|
|
|
|
// Create empty app.axe file
|
|
let app_path = format!("{}/app.axe", pkg_dir);
|
|
File::create(app_path).unwrap();
|
|
}
|
|
|
|
Ok(Expr::Bool(true))
|
|
}),
|
|
);
|
|
|
|
env
|
|
}
|