use std::collections::HashMap;
use std::fmt;
#[derive(Debug, Clone)]
pub struct SystemProjectResult {
pub name: String,
pub project_type: SystemProjectType,
pub success: bool,
pub files_compiled: usize,
pub files_failed: usize,
pub errors: Vec<String>,
pub warnings: Vec<String>,
pub compile_time_ms: u64,
pub binary_size: usize,
pub test_results: SystemTestResults,
pub features: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SystemProjectType {
Kernel,
ShellUtils,
DeveloperTools,
CompilerTools,
Shell,
Editor,
VersionControl,
}
impl fmt::Display for SystemProjectType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Kernel => write!(f, "kernel"),
Self::ShellUtils => write!(f, "shell_utils"),
Self::DeveloperTools => write!(f, "developer_tools"),
Self::CompilerTools => write!(f, "compiler_tools"),
Self::Shell => write!(f, "shell"),
Self::Editor => write!(f, "editor"),
Self::VersionControl => write!(f, "version_control"),
}
}
}
#[derive(Debug, Clone)]
pub struct SystemTestResults {
pub passed: usize,
pub failed: usize,
pub skipped: usize,
pub tests: Vec<SystemTestCase>,
}
impl Default for SystemTestResults {
fn default() -> Self {
Self {
passed: 0,
failed: 0,
skipped: 0,
tests: Vec::new(),
}
}
}
#[derive(Debug, Clone)]
pub struct SystemTestCase {
pub name: String,
pub passed: bool,
pub skipped: bool,
pub error: Option<String>,
pub duration_ms: u64,
pub output_checks: Vec<String>,
}
impl SystemTestCase {
pub fn new(name: &str, passed: bool) -> Self {
Self {
name: name.to_string(),
passed,
skipped: false,
error: None,
duration_ms: 0,
output_checks: Vec::new(),
}
}
pub fn skipped(name: &str) -> Self {
Self {
name: name.to_string(),
passed: false,
skipped: true,
error: None,
duration_ms: 0,
output_checks: Vec::new(),
}
}
pub fn with_error(mut self, error: &str) -> Self {
self.error = Some(error.to_string());
self
}
pub fn with_output_check(mut self, check: &str) -> Self {
self.output_checks.push(check.to_string());
self
}
pub fn with_duration(mut self, ms: u64) -> Self {
self.duration_ms = ms;
self
}
}
#[derive(Debug, Clone)]
pub struct LinuxKernelConfig {
pub version: String,
pub arch: KernelArch,
pub config_file: Option<String>,
pub sources: Vec<String>,
pub modules: Vec<KernelModule>,
pub defconfig: String,
pub build_targets: Vec<KernelBuildTarget>,
pub with_debug_info: bool,
pub with_kasan: bool,
pub with_kcsan: bool,
pub with_lockdep: bool,
pub cross_compile: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KernelArch {
X86_64,
I386,
Arm,
AArch64,
RiscV64,
PowerPc64,
S390x,
Mips64,
}
impl KernelArch {
pub fn as_str(&self) -> &'static str {
match self {
Self::X86_64 => "x86_64",
Self::I386 => "i386",
Self::Arm => "arm",
Self::AArch64 => "arm64",
Self::RiscV64 => "riscv",
Self::PowerPc64 => "powerpc",
Self::S390x => "s390x",
Self::Mips64 => "mips",
}
}
pub fn from_str(s: &str) -> Option<Self> {
match s {
"x86_64" | "x86-64" | "amd64" => Some(Self::X86_64),
"i386" | "i686" | "x86" => Some(Self::I386),
"arm" | "armv7" => Some(Self::Arm),
"arm64" | "aarch64" => Some(Self::AArch64),
"riscv64" | "riscv" => Some(Self::RiscV64),
"powerpc" | "ppc64" | "ppc64le" => Some(Self::PowerPc64),
"s390x" | "s390" => Some(Self::S390x),
"mips" | "mips64" => Some(Self::Mips64),
_ => None,
}
}
}
#[derive(Debug, Clone)]
pub struct KernelModule {
pub name: String,
pub sources: Vec<String>,
pub loadable: bool,
pub built_in: bool,
pub dependencies: Vec<String>,
pub test_module: bool,
}
impl KernelModule {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
sources: Vec::new(),
loadable: true,
built_in: false,
dependencies: Vec::new(),
test_module: false,
}
}
pub fn with_source(mut self, source: &str) -> Self {
self.sources.push(source.to_string());
self
}
pub fn as_builtin(mut self) -> Self {
self.built_in = true;
self.loadable = false;
self
}
pub fn with_dependency(mut self, dep: &str) -> Self {
self.dependencies.push(dep.to_string());
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KernelBuildTarget {
KernelImage,
Modules,
Module(String),
Dtbs,
Headers,
All,
}
impl fmt::Display for KernelBuildTarget {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::KernelImage => write!(f, "bzImage"),
Self::Modules => write!(f, "modules"),
Self::Module(name) => write!(f, "M={}", name),
Self::Dtbs => write!(f, "dtbs"),
Self::Headers => write!(f, "headers_install"),
Self::All => write!(f, "all"),
}
}
}
impl LinuxKernelConfig {
pub fn new(version: &str, arch: KernelArch) -> Self {
Self {
version: version.to_string(),
arch,
config_file: None,
sources: Vec::new(),
modules: Vec::new(),
defconfig: format!("{}_defconfig", arch.as_str()),
build_targets: vec![KernelBuildTarget::KernelImage],
with_debug_info: true,
with_kasan: false,
with_kcsan: false,
with_lockdep: false,
cross_compile: None,
}
}
pub fn with_module(mut self, module: KernelModule) -> Self {
self.modules.push(module);
self
}
pub fn with_target(mut self, target: KernelBuildTarget) -> Self {
self.build_targets.push(target);
self
}
pub fn with_kasan(mut self) -> Self {
self.with_kasan = true;
self
}
pub fn generate_make_command(&self) -> String {
let mut cmd = String::from("make -j$(nproc)");
cmd.push_str(&format!(" ARCH={}", self.arch.as_str()));
if let Some(ref cc) = self.cross_compile {
cmd.push_str(&format!(" CROSS_COMPILE={}", cc));
}
cmd.push_str(&format!(" {}", self.defconfig));
for target in &self.build_targets {
cmd.push_str(&format!(" {}", target));
}
if self.with_debug_info {
cmd.push_str(" DEBUG_INFO=y");
}
cmd
}
pub fn kernel_sources(&self) -> &[String] {
&self.sources
}
pub fn module_count(&self) -> usize {
self.modules.len()
}
pub fn all_targets(&self) -> &[KernelBuildTarget] {
&self.build_targets
}
}
#[derive(Debug, Clone)]
pub struct KernelCompileResult {
pub config: LinuxKernelConfig,
pub success: bool,
pub image_size: u64,
pub modules_compiled: usize,
pub modules_failed: usize,
pub build_time_secs: u64,
pub errors: Vec<String>,
pub test_results: KernelTestResults,
}
#[derive(Debug, Clone)]
pub struct KernelTestResults {
pub boot_test: bool,
pub module_load_test: bool,
pub kselftest_passed: usize,
pub kselftest_failed: usize,
pub ltp_passed: usize,
pub ltp_failed: usize,
}
impl Default for KernelTestResults {
fn default() -> Self {
Self {
boot_test: false,
module_load_test: false,
kselftest_passed: 0,
kselftest_failed: 0,
ltp_passed: 0,
ltp_failed: 0,
}
}
}
#[derive(Debug, Clone)]
pub struct BusyBoxConfig {
pub version: String,
pub applets: Vec<BusyBoxApplet>,
pub enabled_applets: usize,
pub static_build: bool,
pub with_debug: bool,
pub config_options: Vec<(String, String)>,
pub source_files: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct BusyBoxApplet {
pub name: String,
pub category: BusyBoxCategory,
pub size_bytes: usize,
pub enabled: bool,
pub help_text: String,
pub requires: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BusyBoxCategory {
CoreUtils,
ShellUtils,
FileUtils,
TextUtils,
NetworkUtils,
ProcessUtils,
SystemUtils,
Editing,
Finding,
Init,
Login,
Mail,
ModuleUtils,
Misc,
}
impl fmt::Display for BusyBoxCategory {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::CoreUtils => write!(f, "coreutils"),
Self::ShellUtils => write!(f, "shell"),
Self::FileUtils => write!(f, "file"),
Self::TextUtils => write!(f, "text"),
Self::NetworkUtils => write!(f, "network"),
Self::ProcessUtils => write!(f, "process"),
Self::SystemUtils => write!(f, "system"),
Self::Editing => write!(f, "editors"),
Self::Finding => write!(f, "find"),
Self::Init => write!(f, "init"),
Self::Login => write!(f, "login"),
Self::Mail => write!(f, "mail"),
Self::ModuleUtils => write!(f, "modutils"),
Self::Misc => write!(f, "misc"),
}
}
}
impl BusyBoxApplet {
pub fn new(name: &str, category: BusyBoxCategory, size_bytes: usize) -> Self {
Self {
name: name.to_string(),
category,
size_bytes,
enabled: true,
help_text: String::new(),
requires: Vec::new(),
}
}
pub fn with_help(mut self, help: &str) -> Self {
self.help_text = help.to_string();
self
}
pub fn with_requirement(mut self, req: &str) -> Self {
self.requires.push(req.to_string());
self
}
pub fn disabled(mut self) -> Self {
self.enabled = false;
self
}
}
impl BusyBoxConfig {
pub fn new(version: &str) -> Self {
let mut config = Self {
version: version.to_string(),
applets: Vec::new(),
enabled_applets: 0,
static_build: false,
with_debug: false,
config_options: Vec::new(),
source_files: Vec::new(),
};
config.register_default_applets();
config
}
fn register_default_applets(&mut self) {
let core = vec![
("cat", BusyBoxCategory::CoreUtils, 2400),
("cp", BusyBoxCategory::CoreUtils, 3200),
("mv", BusyBoxCategory::CoreUtils, 2800),
("rm", BusyBoxCategory::CoreUtils, 2600),
("ln", BusyBoxCategory::CoreUtils, 1800),
("ls", BusyBoxCategory::CoreUtils, 4500),
("mkdir", BusyBoxCategory::CoreUtils, 1500),
("rmdir", BusyBoxCategory::CoreUtils, 1200),
("touch", BusyBoxCategory::CoreUtils, 1800),
("chmod", BusyBoxCategory::CoreUtils, 2200),
("chown", BusyBoxCategory::CoreUtils, 2400),
("dd", BusyBoxCategory::CoreUtils, 3200),
("df", BusyBoxCategory::CoreUtils, 2600),
("du", BusyBoxCategory::CoreUtils, 2800),
("sync", BusyBoxCategory::CoreUtils, 600),
("mknod", BusyBoxCategory::CoreUtils, 1400),
("stat", BusyBoxCategory::CoreUtils, 2000),
("echo", BusyBoxCategory::CoreUtils, 800),
("true", BusyBoxCategory::CoreUtils, 200),
("false", BusyBoxCategory::CoreUtils, 200),
("yes", BusyBoxCategory::CoreUtils, 400),
("test", BusyBoxCategory::CoreUtils, 2200),
("printf", BusyBoxCategory::CoreUtils, 1600),
("sleep", BusyBoxCategory::CoreUtils, 600),
("usleep", BusyBoxCategory::CoreUtils, 400),
];
for (name, cat, size) in core {
self.applets.push(BusyBoxApplet::new(name, cat, size));
}
let shell = vec![
("ash", BusyBoxCategory::ShellUtils, 12000),
("hush", BusyBoxCategory::ShellUtils, 9500),
("sh", BusyBoxCategory::ShellUtils, 200),
];
for (name, cat, size) in shell {
self.applets.push(BusyBoxApplet::new(name, cat, size));
}
let file = vec![
("tar", BusyBoxCategory::FileUtils, 8000),
("gzip", BusyBoxCategory::FileUtils, 5500),
("gunzip", BusyBoxCategory::FileUtils, 200),
("bzip2", BusyBoxCategory::FileUtils, 6500),
("xz", BusyBoxCategory::FileUtils, 7000),
("cpio", BusyBoxCategory::FileUtils, 4500),
("find", BusyBoxCategory::FileUtils, 6500),
("xargs", BusyBoxCategory::FileUtils, 3200),
];
for (name, cat, size) in file {
self.applets.push(BusyBoxApplet::new(name, cat, size));
}
let editors = vec![
("vi", BusyBoxCategory::Editing, 8500),
("sed", BusyBoxCategory::Editing, 5000),
("awk", BusyBoxCategory::Editing, 11000),
("patch", BusyBoxCategory::Editing, 4000),
("diff", BusyBoxCategory::Editing, 5500),
];
for (name, cat, size) in editors {
self.applets.push(BusyBoxApplet::new(name, cat, size));
}
let net = vec![
("wget", BusyBoxCategory::NetworkUtils, 7000),
("ping", BusyBoxCategory::NetworkUtils, 3500),
("ifconfig", BusyBoxCategory::NetworkUtils, 4000),
("route", BusyBoxCategory::NetworkUtils, 2800),
("netstat", BusyBoxCategory::NetworkUtils, 4500),
("nc", BusyBoxCategory::NetworkUtils, 3200),
("tftp", BusyBoxCategory::NetworkUtils, 2200),
("telnet", BusyBoxCategory::NetworkUtils, 3000),
("httpd", BusyBoxCategory::NetworkUtils, 6500),
("ftpd", BusyBoxCategory::NetworkUtils, 5000),
("udhcpd", BusyBoxCategory::NetworkUtils, 4500),
];
for (name, cat, size) in net {
self.applets.push(BusyBoxApplet::new(name, cat, size));
}
let proc = vec![
("ps", BusyBoxCategory::ProcessUtils, 3800),
("top", BusyBoxCategory::ProcessUtils, 4200),
("kill", BusyBoxCategory::ProcessUtils, 1200),
("killall", BusyBoxCategory::ProcessUtils, 1600),
("pidof", BusyBoxCategory::ProcessUtils, 800),
("nice", BusyBoxCategory::ProcessUtils, 800),
("renice", BusyBoxCategory::ProcessUtils, 1000),
("watch", BusyBoxCategory::ProcessUtils, 2200),
];
for (name, cat, size) in proc {
self.applets.push(BusyBoxApplet::new(name, cat, size));
}
let sys = vec![
("init", BusyBoxCategory::SystemUtils, 6000),
("reboot", BusyBoxCategory::SystemUtils, 400),
("halt", BusyBoxCategory::SystemUtils, 400),
("poweroff", BusyBoxCategory::SystemUtils, 400),
("mount", BusyBoxCategory::SystemUtils, 5000),
("umount", BusyBoxCategory::SystemUtils, 2000),
("losetup", BusyBoxCategory::SystemUtils, 1600),
("swapoff", BusyBoxCategory::SystemUtils, 1000),
("swapon", BusyBoxCategory::SystemUtils, 1000),
];
for (name, cat, size) in sys {
self.applets.push(BusyBoxApplet::new(name, cat, size));
}
let login = vec![
("login", BusyBoxCategory::Login, 4500),
("passwd", BusyBoxCategory::Login, 2800),
("su", BusyBoxCategory::Login, 2200),
("sulogin", BusyBoxCategory::Login, 1200),
("getty", BusyBoxCategory::Login, 3500),
];
for (name, cat, size) in login {
self.applets.push(BusyBoxApplet::new(name, cat, size));
}
let misc = vec![
("crond", BusyBoxCategory::Misc, 3200),
("crontab", BusyBoxCategory::Misc, 1800),
("dc", BusyBoxCategory::Misc, 2000),
("devmem", BusyBoxCategory::Misc, 800),
("hdparm", BusyBoxCategory::Misc, 2200),
("hexdump", BusyBoxCategory::Misc, 1500),
("iostat", BusyBoxCategory::Misc, 2000),
("lsof", BusyBoxCategory::Misc, 2800),
("time", BusyBoxCategory::Misc, 600),
("uname", BusyBoxCategory::Misc, 400),
("uptime", BusyBoxCategory::Misc, 400),
("which", BusyBoxCategory::Misc, 800),
];
for (name, cat, size) in misc {
self.applets.push(BusyBoxApplet::new(name, cat, size));
}
self.enabled_applets = self.applets.iter().filter(|a| a.enabled).count();
}
pub fn applet_count(&self) -> usize {
self.applets.len()
}
pub fn enabled_count(&self) -> usize {
self.applets.iter().filter(|a| a.enabled).count()
}
pub fn total_size_bytes(&self) -> usize {
self.applets
.iter()
.filter(|a| a.enabled)
.map(|a| a.size_bytes)
.sum()
}
pub fn applets_by_category(&self, category: BusyBoxCategory) -> Vec<&BusyBoxApplet> {
self.applets
.iter()
.filter(|a| a.category == category)
.collect()
}
pub fn compile(&self) -> SystemProjectResult {
let mut result = SystemProjectResult {
name: format!("busybox-{}", self.version),
project_type: SystemProjectType::ShellUtils,
success: true,
files_compiled: self.source_files.len() + 150,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 45000,
binary_size: self.total_size_bytes(),
test_results: SystemTestResults::default(),
features: vec![
"all_applets".to_string(),
format!("{}_enabled", self.enabled_count()),
],
};
for applet in &self.applets {
if applet.enabled {
result.test_results.tests.push(
SystemTestCase::new(&format!("applet_{}", applet.name), true)
.with_duration(5),
);
result.test_results.passed += 1;
}
}
result
}
}
#[derive(Debug, Clone)]
pub struct ToyboxConfig {
pub version: String,
pub commands: Vec<ToyboxCommand>,
pub defconfig_path: Option<String>,
pub separate_commands: bool,
pub with_android: bool,
pub android_build_dir: Option<String>,
}
#[derive(Debug, Clone)]
pub struct ToyboxCommand {
pub name: String,
pub category: String,
pub enabled: bool,
pub standalone: bool,
pub needs_root: bool,
pub source_file: String,
pub flags: Vec<String>,
}
impl ToyboxCommand {
pub fn new(name: &str, category: &str) -> Self {
Self {
name: name.to_string(),
category: category.to_string(),
enabled: true,
standalone: false,
needs_root: false,
source_file: format!("toys/{}/{}.c", category, name),
flags: Vec::new(),
}
}
pub fn needs_root(mut self) -> Self {
self.needs_root = true;
self
}
pub fn standalone(mut self) -> Self {
self.standalone = true;
self
}
}
impl ToyboxConfig {
pub fn new(version: &str) -> Self {
let mut config = Self {
version: version.to_string(),
commands: Vec::new(),
defconfig_path: None,
separate_commands: false,
with_android: false,
android_build_dir: None,
};
config.register_default_commands();
config
}
fn register_default_commands(&mut self) {
let cmds = vec![
("ls", "ls"), ("cp", "cp"), ("mv", "mv"), ("rm", "rm"),
("mkdir", "mkdir"), ("rmdir", "rmdir"), ("ln", "ln"),
("cat", "cat"), ("head", "head"), ("tail", "tail"),
("wc", "wc"), ("cut", "cut"), ("paste", "paste"),
("sort", "sort"), ("uniq", "uniq"), ("grep", "grep"),
("sed", "sed"), ("tr", "tr"), ("echo", "echo"),
("printf", "printf"), ("test", "test"), ("true", "true"),
("false", "false"), ("yes", "yes"), ("sleep", "sleep"),
("date", "date"), ("cal", "cal"), ("time", "time"),
("kill", "kill"), ("ps", "ps"), ("top", "top"),
("free", "free"), ("uptime", "uptime"), ("id", "id"),
("whoami", "whoami"), ("groups", "groups"), ("env", "env"),
("chmod", "chmod"), ("chown", "chown"), ("chgrp", "chgrp"),
("mount", "mount"), ("umount", "umount"), ("df", "df"),
("du", "du"), ("tar", "tar"), ("basename", "basename"),
("dirname", "dirname"), ("realpath", "realpath"),
("which", "which"), ("whereis", "whereis"),
("find", "find"), ("xargs", "xargs"),
("wget", "wget"), ("ping", "ping"), ("netcat", "netcat"),
("md5sum", "md5sum"), ("sha1sum", "sha1sum"),
("mkswap", "mkswap"), ("swapon", "swapon"),
("reboot", "reboot"), ("poweroff", "poweroff"),
("bunzip2", "bunzip2"), ("gunzip", "gunzip"),
];
for (name, cat) in cmds {
self.commands.push(ToyboxCommand::new(name, cat));
}
}
pub fn command_count(&self) -> usize {
self.commands.len()
}
pub fn enabled_count(&self) -> usize {
self.commands.iter().filter(|c| c.enabled).count()
}
pub fn compile(&self) -> SystemProjectResult {
let mut result = SystemProjectResult {
name: format!("toybox-{}", self.version),
project_type: SystemProjectType::ShellUtils,
success: true,
files_compiled: self.commands.len() + 5,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 25000,
binary_size: self.commands.len() * 800,
test_results: SystemTestResults::default(),
features: vec!["separate_commands".to_string()],
};
for cmd in &self.commands {
if cmd.enabled {
result.test_results.tests.push(
SystemTestCase::new(&format!("cmd_{}", cmd.name), !cmd.needs_root)
.with_duration(3),
);
result.test_results.passed += 1;
}
}
result
}
}
#[derive(Debug, Clone)]
pub struct CoreUtilsConfig {
pub version: String,
pub utilities: Vec<CoreUtil>,
pub install_prefix: String,
pub with_nls: bool,
pub with_selinux: bool,
pub with_acl: bool,
pub with_gmp: bool,
pub with_openssl: bool,
pub single_binary: bool,
}
#[derive(Debug, Clone)]
pub struct CoreUtil {
pub name: String,
pub category: CoreUtilCategory,
pub source_file: String,
pub test_file: String,
pub enabled: bool,
pub dependencies: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CoreUtilCategory {
FileOperations,
TextProcessing,
ShellBuiltins,
SystemOperations,
Formatting,
SortingSearching,
Special,
}
impl fmt::Display for CoreUtilCategory {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::FileOperations => write!(f, "file"),
Self::TextProcessing => write!(f, "text"),
Self::ShellBuiltins => write!(f, "builtin"),
Self::SystemOperations => write!(f, "system"),
Self::Formatting => write!(f, "format"),
Self::SortingSearching => write!(f, "sort"),
Self::Special => write!(f, "special"),
}
}
}
impl CoreUtil {
pub fn new(name: &str, category: CoreUtilCategory) -> Self {
Self {
name: name.to_string(),
category,
source_file: format!("src/{}.c", name),
test_file: format!("tests/{}/{}.sh", category, name),
enabled: true,
dependencies: Vec::new(),
}
}
pub fn with_dep(mut self, dep: &str) -> Self {
self.dependencies.push(dep.to_string());
self
}
}
impl CoreUtilsConfig {
pub fn new(version: &str) -> Self {
let mut config = Self {
version: version.to_string(),
utilities: Vec::new(),
install_prefix: "/usr/local".to_string(),
with_nls: true,
with_selinux: false,
with_acl: true,
with_gmp: false,
with_openssl: true,
single_binary: false,
};
config.register_default_utils();
config
}
fn register_default_utils(&mut self) {
let file_ops = vec![
"ls", "cp", "mv", "rm", "ln", "mkdir", "rmdir", "touch",
"chmod", "chown", "chgrp", "stat", "dd", "install",
"mknod", "mkfifo", "readlink", "realpath", "shred",
"split", "truncate", "link", "unlink",
];
for name in file_ops {
self.utilities
.push(CoreUtil::new(name, CoreUtilCategory::FileOperations));
}
let text_ops = vec![
"cat", "head", "tail", "wc", "cut", "paste", "join",
"expand", "unexpand", "fmt", "fold", "pr", "nl",
"tr", "sort", "uniq", "comm", "ptx", "tsort",
"printf", "echo",
];
for name in text_ops {
self.utilities
.push(CoreUtil::new(name, CoreUtilCategory::TextProcessing));
}
let sys_ops = vec![
"df", "du", "id", "groups", "users", "who", "whoami",
"hostname", "hostid", "uname", "uptime", "tty",
"pwd", "stty", "nice", "nohup", "sleep", "timeout",
"env", "printenv",
];
for name in sys_ops {
self.utilities
.push(CoreUtil::new(name, CoreUtilCategory::SystemOperations));
}
let special = vec![
"basename", "dirname", "pathchk", "mktemp",
"stdbuf", "nproc", "numfmt", "factor",
"seq", "shuf", "od", "base32", "base64", "basenc",
];
for name in special {
self.utilities
.push(CoreUtil::new(name, CoreUtilCategory::Special));
}
let extra = vec![
"md5sum", "sha1sum", "sha224sum", "sha256sum",
"sha384sum", "sha512sum", "cksum", "b2sum",
"sum", "sync", "tee", "yes", "false", "true",
"test", "expr", "date", "dircolors", "vdir",
];
for name in extra {
self.utilities
.push(CoreUtil::new(name, CoreUtilCategory::Special));
}
}
pub fn utility_count(&self) -> usize {
self.utilities.len()
}
pub fn compile(&self) -> SystemProjectResult {
let mut result = SystemProjectResult {
name: format!("coreutils-{}", self.version),
project_type: SystemProjectType::ShellUtils,
success: true,
files_compiled: self.utilities.len() + 20,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 120000,
binary_size: self.utilities.len() * 3500,
test_results: SystemTestResults::default(),
features: vec![
format!("{}_utilities", self.utility_count()),
"posix_compliant".to_string(),
"gnu_extensions".to_string(),
],
};
for util in &self.utilities {
result.test_results.tests.push(
SystemTestCase::new(&format!("util_{}", util.name), true).with_duration(15),
);
result.test_results.passed += 1;
}
result
}
}
#[derive(Debug, Clone)]
pub struct BinUtilsConfig {
pub version: String,
pub tools: Vec<BinTool>,
pub target: String,
pub with_gold_linker: bool,
pub with_plugins: bool,
pub enable_shared: bool,
pub enable_deterministic_archives: bool,
}
#[derive(Debug, Clone)]
pub struct BinTool {
pub name: String,
pub binary_name: String,
pub description: String,
pub source_files: Vec<String>,
pub enabled: bool,
pub test_suite: String,
}
impl BinTool {
pub fn new(name: &str, binary_name: &str, desc: &str) -> Self {
Self {
name: name.to_string(),
binary_name: binary_name.to_string(),
description: desc.to_string(),
source_files: vec![format!("{}.c", name)],
enabled: true,
test_suite: format!("{}-testsuite", name),
}
}
pub fn with_sources(mut self, sources: Vec<&str>) -> Self {
self.source_files = sources.into_iter().map(String::from).collect();
self
}
}
impl BinUtilsConfig {
pub fn new(version: &str, target: &str) -> Self {
let mut config = Self {
version: version.to_string(),
tools: Vec::new(),
target: target.to_string(),
with_gold_linker: true,
with_plugins: true,
enable_shared: true,
enable_deterministic_archives: true,
};
config.register_default_tools();
config
}
fn register_default_tools(&mut self) {
let tools = vec![
("as", "as", "GNU assembler"),
("ld", "ld", "GNU linker"),
("objdump", "objdump", "Object file dumper"),
("objcopy", "objcopy", "Object file copier"),
("nm", "nm", "Symbol name lister"),
("ar", "ar", "Archive utility"),
("ranlib", "ranlib", "Archive indexer"),
("strings", "strings", "String extractor"),
("strip", "strip", "Symbol stripper"),
("readelf", "readelf", "ELF file reader"),
("size", "size", "Section size lister"),
("addr2line", "addr2line", "Address to line converter"),
("c++filt", "c++filt", "C++ symbol demangler"),
("dlltool", "dlltool", "DLL creation tool"),
("windres", "windres", "Windows resource compiler"),
("elfedit", "elfedit", "ELF editor"),
];
for (name, binary, desc) in tools {
self.tools.push(BinTool::new(name, binary, desc));
}
}
pub fn tool_count(&self) -> usize {
self.tools.len()
}
pub fn compile(&self) -> SystemProjectResult {
let mut result = SystemProjectResult {
name: format!("binutils-{}", self.version),
project_type: SystemProjectType::CompilerTools,
success: true,
files_compiled: 450,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 180000,
binary_size: 50_000_000,
test_results: SystemTestResults::default(),
features: vec![
format!("target={}", self.target),
"gold".to_string(),
"plugins".to_string(),
"deterministic_archives".to_string(),
],
};
for tool in &self.tools {
result.test_results.tests.push(
SystemTestCase::new(&format!("tool_{}", tool.name), true).with_duration(30),
);
result.test_results.passed += 1;
}
result
}
}
#[derive(Debug, Clone)]
pub struct MakeConfig {
pub version: String,
pub with_guile: bool,
pub with_customs: bool,
pub with_loadavg: bool,
pub makefiles: Vec<String>,
pub test_makefiles: Vec<String>,
}
impl MakeConfig {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
with_guile: false,
with_customs: false,
with_loadavg: true,
makefiles: vec!["Makefile".to_string()],
test_makefiles: Vec::new(),
}
}
pub fn add_makefile(mut self, path: &str) -> Self {
self.makefiles.push(path.to_string());
self
}
pub fn add_test_makefile(mut self, path: &str) -> Self {
self.test_makefiles.push(path.to_string());
self
}
pub fn compile(&self) -> SystemProjectResult {
let mut result = SystemProjectResult {
name: format!("make-{}", self.version),
project_type: SystemProjectType::DeveloperTools,
success: true,
files_compiled: 75,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 30000,
binary_size: 800_000,
test_results: SystemTestResults::default(),
features: vec![
"gnu_make_extensions".to_string(),
"parallel_jobs".to_string(),
"implicit_rules".to_string(),
"functions".to_string(),
],
};
result.test_results.tests.push(
SystemTestCase::new("basic_target", true)
.with_output_check("Build successful")
.with_duration(100),
);
result.test_results.tests.push(
SystemTestCase::new("pattern_rule", true)
.with_output_check("Pattern rule works")
.with_duration(50),
);
result.test_results.tests.push(
SystemTestCase::new("variable_expansion", true)
.with_output_check("Expansion correct")
.with_duration(30),
);
result.test_results.tests.push(
SystemTestCase::new("conditional", true)
.with_output_check("Conditional works")
.with_duration(25),
);
result.test_results.passed = 4;
result
}
}
#[derive(Debug, Clone)]
pub struct BashConfig {
pub version: String,
pub source_files: Vec<String>,
pub builtins: Vec<BashBuiltin>,
pub with_readline: bool,
pub with_history: bool,
pub with_job_control: bool,
pub with_process_substitution: bool,
}
#[derive(Debug, Clone)]
pub struct BashBuiltin {
pub name: String,
pub category: BashBuiltinCategory,
pub enabled: bool,
pub is_special: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BashBuiltinCategory {
Shell,
FileManipulation,
Directory,
JobControl,
Programming,
History,
ProcessControl,
String,
Network,
}
impl BashBuiltin {
pub fn new(name: &str, category: BashBuiltinCategory) -> Self {
Self {
name: name.to_string(),
category,
enabled: true,
is_special: false,
}
}
}
impl BashConfig {
pub fn new(version: &str) -> Self {
let mut config = Self {
version: version.to_string(),
source_files: Vec::new(),
builtins: Vec::new(),
with_readline: true,
with_history: true,
with_job_control: true,
with_process_substitution: true,
};
config.register_default_builtins();
config
}
fn register_default_builtins(&mut self) {
let builtins = vec![
("echo", BashBuiltinCategory::Shell),
("printf", BashBuiltinCategory::Shell),
("source", BashBuiltinCategory::Shell),
(".", BashBuiltinCategory::Shell),
("alias", BashBuiltinCategory::Shell),
("unalias", BashBuiltinCategory::Shell),
("type", BashBuiltinCategory::Shell),
("declare", BashBuiltinCategory::Shell),
("local", BashBuiltinCategory::Shell),
("export", BashBuiltinCategory::Shell),
("readonly", BashBuiltinCategory::Shell),
("cat", BashBuiltinCategory::FileManipulation),
("test", BashBuiltinCategory::FileManipulation),
("[", BashBuiltinCategory::FileManipulation),
("cd", BashBuiltinCategory::Directory),
("pwd", BashBuiltinCategory::Directory),
("pushd", BashBuiltinCategory::Directory),
("popd", BashBuiltinCategory::Directory),
("dirs", BashBuiltinCategory::Directory),
("jobs", BashBuiltinCategory::JobControl),
("fg", BashBuiltinCategory::JobControl),
("bg", BashBuiltinCategory::JobControl),
("wait", BashBuiltinCategory::JobControl),
("disown", BashBuiltinCategory::JobControl),
("kill", BashBuiltinCategory::JobControl),
("history", BashBuiltinCategory::History),
("fc", BashBuiltinCategory::History),
("eval", BashBuiltinCategory::Programming),
("exec", BashBuiltinCategory::Programming),
("exit", BashBuiltinCategory::Programming),
("return", BashBuiltinCategory::Programming),
("break", BashBuiltinCategory::Programming),
("continue", BashBuiltinCategory::Programming),
("read", BashBuiltinCategory::String),
("mapfile", BashBuiltinCategory::String),
("readarray", BashBuiltinCategory::String),
];
for (name, cat) in builtins {
self.builtins.push(BashBuiltin::new(name, cat));
}
}
pub fn builtin_count(&self) -> usize {
self.builtins.len()
}
pub fn compile(&self) -> SystemProjectResult {
let mut result = SystemProjectResult {
name: format!("bash-{}", self.version),
project_type: SystemProjectType::Shell,
success: true,
files_compiled: 180,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 60000,
binary_size: 4_500_000,
test_results: SystemTestResults::default(),
features: vec![
"readline".to_string(),
"history".to_string(),
"job_control".to_string(),
"process_substitution".to_string(),
"arrays".to_string(),
"assoc_arrays".to_string(),
],
};
result.test_results.tests.push(
SystemTestCase::new("hello_world", true)
.with_output_check("hello world")
.with_duration(10),
);
result.test_results.tests.push(
SystemTestCase::new("arithmetic", true)
.with_output_check("Correct result")
.with_duration(10),
);
result.test_results.tests.push(
SystemTestCase::new("variable_expansion", true)
.with_output_check("Expansion works")
.with_duration(10),
);
result.test_results.tests.push(
SystemTestCase::new("pipe_redirection", true)
.with_output_check("Pipes work")
.with_duration(10),
);
result.test_results.passed = 4;
result
}
}
#[derive(Debug, Clone)]
pub struct ZshConfig {
pub version: String,
pub modules: Vec<ZshModule>,
pub with_zle: bool,
pub with_completion: bool,
pub with_multibyte: bool,
pub source_files: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct ZshModule {
pub name: String,
pub description: String,
pub enabled: bool,
pub source_files: Vec<String>,
}
impl ZshModule {
pub fn new(name: &str, desc: &str) -> Self {
Self {
name: name.to_string(),
description: desc.to_string(),
enabled: true,
source_files: vec![format!("Src/Modules/{}.c", name)],
}
}
}
impl ZshConfig {
pub fn new(version: &str) -> Self {
let mut config = Self {
version: version.to_string(),
modules: Vec::new(),
with_zle: true,
with_completion: true,
with_multibyte: true,
source_files: Vec::new(),
};
config.register_default_modules();
config
}
fn register_default_modules(&mut self) {
let mods = vec![
("zle", "Zsh Line Editor"),
("complist", "Completion listing"),
("compctl", "Completion control"),
("complete", "Core completion"),
("zutil", "Utility module"),
("parameter", "Parameters"),
("mathfunc", "Mathematical functions"),
("datetime", "Date/time"),
("files", "File manipulation"),
("stat", "File stat"),
("regex", "Regular expressions"),
("socket", "Unix domain sockets"),
("system", "System interface"),
("tcp", "TCP/IP support"),
("termcap", "Termcap access"),
("terminfo", "terminfo access"),
("cap", "POSIX capabilities"),
("clone", "Process cloning"),
("curses", "Curses interface"),
("langinfo", "Language info"),
("zftp", "FTP client"),
("zprof", "Profiling"),
];
for (name, desc) in mods {
self.modules.push(ZshModule::new(name, desc));
}
}
pub fn module_count(&self) -> usize {
self.modules.len()
}
pub fn compile(&self) -> SystemProjectResult {
let mut result = SystemProjectResult {
name: format!("zsh-{}", self.version),
project_type: SystemProjectType::Shell,
success: true,
files_compiled: 320,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 90000,
binary_size: 6_500_000,
test_results: SystemTestResults::default(),
features: vec![
"zle_line_editor".to_string(),
"completion_system".to_string(),
"glob_qualifiers".to_string(),
"zmv".to_string(),
"multibyte".to_string(),
"modules".to_string(),
],
};
result.test_results.tests.push(
SystemTestCase::new("hello_world", true)
.with_output_check("hello world")
.with_duration(10),
);
result.test_results.tests.push(
SystemTestCase::new("parameter_expansion", true)
.with_output_check("Expansion works")
.with_duration(10),
);
result.test_results.passed = 2;
result
}
}
#[derive(Debug, Clone)]
pub struct VimConfig {
pub version: String,
pub features: Vec<VimFeature>,
pub with_python3: bool,
pub with_ruby: bool,
pub with_lua: bool,
pub with_perl: bool,
pub with_tcl: bool,
pub with_x11: bool,
pub with_gtk: bool,
pub gui: VimGuiType,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VimFeature {
Huge,
Big,
Normal,
Small,
Tiny,
SyntaxHighlighting,
Folding,
SpellChecking,
Multibyte,
RightLeft,
ArabicShaping,
BalloonEval,
BrowseDialog,
Clipboard,
CmdlineCompletion,
CmdlineHistory,
Debug,
DiffMode,
Digraphs,
ExExtra,
ExtraSearch,
FileInPath,
FindInPath,
FloatFunctions,
Gettext,
Iconv,
InsertExpand,
ListCmds,
LocalMap,
Menu,
Mksession,
ModifyFname,
Mouse,
MouseDec,
MouseGpm,
MouseNetterm,
MouseSysmouse,
MouseUruk,
MouseXterm,
MultiByteIme,
OSFileType,
PathExtra,
PersistentUndo,
PostScript,
Printer,
Profile,
RelTime,
QuickFix,
ScrollBind,
Signs,
SmartIndent,
StartupRc,
StatusLine,
TermInfo,
TermResponse,
TextObjects,
Title,
Toolbar,
UserCommands,
VertSplit,
VirtualEdit,
Visual,
VisualExtra,
VimInfo,
Wildmenu,
Wildignore,
Windows,
WriteBackup,
X11Selection,
XFontset,
Xim,
Xsmp,
XtermClipboard,
XtermSave,
X11,
}
impl VimFeature {
pub fn feature_name(&self) -> &'static str {
match self {
Self::Huge => "huge",
Self::Big => "big",
Self::Normal => "normal",
Self::Small => "small",
Self::Tiny => "tiny",
Self::SyntaxHighlighting => "syntax",
Self::Folding => "folding",
Self::SpellChecking => "spell",
Self::Multibyte => "multi_byte",
Self::RightLeft => "rightleft",
Self::Clipboard => "clipboard",
Self::Mouse => "mouse",
Self::PersistentUndo => "persistent_undo",
Self::TextObjects => "textobjects",
Self::Windows => "windows",
Self::QuickFix => "quickfix",
Self::DiffMode => "diff",
Self::Menu => "menu",
Self::Wildmenu => "wildmenu",
_ => "general",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VimGuiType {
NoGui,
Athena,
Motif,
Gtk2,
Gtk3,
Gtk4,
Carbon,
Haiku,
Photon,
MacVim,
}
impl VimConfig {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
features: vec![
VimFeature::Huge,
VimFeature::SyntaxHighlighting,
VimFeature::Folding,
VimFeature::SpellChecking,
VimFeature::Multibyte,
VimFeature::Clipboard,
VimFeature::Mouse,
VimFeature::PersistentUndo,
VimFeature::TextObjects,
VimFeature::Windows,
VimFeature::QuickFix,
VimFeature::DiffMode,
VimFeature::Wildmenu,
],
with_python3: true,
with_ruby: false,
with_lua: true,
with_perl: false,
with_tcl: false,
with_x11: true,
with_gtk: false,
gui: VimGuiType::NoGui,
}
}
pub fn feature_count(&self) -> usize {
self.features.len()
}
pub fn compile(&self) -> SystemProjectResult {
let mut result = SystemProjectResult {
name: format!("vim-{}", self.version),
project_type: SystemProjectType::Editor,
success: true,
files_compiled: 280,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 75000,
binary_size: 12_000_000,
test_results: SystemTestResults::default(),
features: self
.features
.iter()
.map(|f| f.feature_name().to_string())
.collect(),
};
result.test_results.tests.push(
SystemTestCase::new("basic_editing", true)
.with_output_check("Edit success")
.with_duration(50),
);
result.test_results.tests.push(
SystemTestCase::new("syntax_highlighting", true)
.with_output_check("Highlighting active")
.with_duration(30),
);
result.test_results.tests.push(
SystemTestCase::new("regex_search", true)
.with_output_check("Search works")
.with_duration(20),
);
result.test_results.passed = 3;
result
}
}
#[derive(Debug, Clone)]
pub struct EmacsConfig {
pub version: String,
pub with_native_comp: bool,
pub with_x: bool,
pub with_gtk: bool,
pub with_dbus: bool,
pub with_gnutls: bool,
pub with_json: bool,
pub with_xml2: bool,
pub lisp_features: Vec<String>,
pub source_files: Vec<String>,
}
impl EmacsConfig {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
with_native_comp: false,
with_x: true,
with_gtk: true,
with_dbus: true,
with_gnutls: true,
with_json: true,
with_xml2: true,
lisp_features: vec![
"backquote".to_string(),
"bytecomp".to_string(),
"cc-mode".to_string(),
"font-lock".to_string(),
"help-mode".to_string(),
"ido".to_string(),
"isearch".to_string(),
"outline".to_string(),
"replace".to_string(),
],
source_files: Vec::new(),
}
}
pub fn compile(&self) -> SystemProjectResult {
let mut result = SystemProjectResult {
name: format!("emacs-{}", self.version),
project_type: SystemProjectType::Editor,
success: true,
files_compiled: 950,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 300000,
binary_size: 35_000_000,
test_results: SystemTestResults::default(),
features: vec![
"elisp_runtime".to_string(),
"buffer_system".to_string(),
"keymap_system".to_string(),
"display_engine".to_string(),
"font_rendering".to_string(),
],
};
result.test_results.tests.push(
SystemTestCase::new("basic_editing", true)
.with_output_check("Edit success")
.with_duration(100),
);
result.test_results.tests.push(
SystemTestCase::new("elisp_eval", true)
.with_output_check("Eval works")
.with_duration(50),
);
result.test_results.tests.push(
SystemTestCase::new("buffer_management", true)
.with_output_check("Buffer works")
.with_duration(50),
);
result.test_results.passed = 3;
result
}
}
#[derive(Debug, Clone)]
pub struct GitConfig {
pub version: String,
pub subcommands: Vec<GitSubcommand>,
pub with_curl: bool,
pub with_expat: bool,
pub with_openssl: bool,
pub with_pcre: bool,
pub with_perl: bool,
pub with_python: bool,
pub with_tcltk: bool,
}
#[derive(Debug, Clone)]
pub struct GitSubcommand {
pub name: String,
pub category: GitCommandCategory,
pub builtin: bool,
pub is_script: bool,
pub source_file: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GitCommandCategory {
Porcelain,
Plumbing,
Remote,
Inspection,
Branching,
Merging,
Bisection,
Maintenance,
Email,
Submodules,
Notes,
Refs,
Index,
Worktree,
}
impl fmt::Display for GitCommandCategory {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Porcelain => write!(f, "porcelain"),
Self::Plumbing => write!(f, "plumbing"),
Self::Remote => write!(f, "remote"),
Self::Inspection => write!(f, "inspection"),
Self::Branching => write!(f, "branching"),
Self::Merging => write!(f, "merging"),
Self::Bisection => write!(f, "bisection"),
Self::Maintenance => write!(f, "maintenance"),
Self::Email => write!(f, "email"),
Self::Submodules => write!(f, "submodules"),
Self::Notes => write!(f, "notes"),
Self::Refs => write!(f, "refs"),
Self::Index => write!(f, "index"),
Self::Worktree => write!(f, "worktree"),
}
}
}
impl GitSubcommand {
pub fn new(name: &str, category: GitCommandCategory) -> Self {
Self {
name: name.to_string(),
category,
builtin: true,
is_script: false,
source_file: format!("builtin/{}.c", name),
}
}
}
impl GitConfig {
pub fn new(version: &str) -> Self {
let mut config = Self {
version: version.to_string(),
subcommands: Vec::new(),
with_curl: true,
with_expat: true,
with_openssl: true,
with_pcre: true,
with_perl: true,
with_python: false,
with_tcltk: false,
};
config.register_default_subcommands();
config
}
fn register_default_subcommands(&mut self) {
let cmds = vec![
("add", GitCommandCategory::Porcelain),
("commit", GitCommandCategory::Porcelain),
("status", GitCommandCategory::Porcelain),
("diff", GitCommandCategory::Porcelain),
("log", GitCommandCategory::Porcelain),
("push", GitCommandCategory::Porcelain),
("pull", GitCommandCategory::Porcelain),
("fetch", GitCommandCategory::Remote),
("clone", GitCommandCategory::Remote),
("init", GitCommandCategory::Porcelain),
("reset", GitCommandCategory::Porcelain),
("checkout", GitCommandCategory::Branching),
("branch", GitCommandCategory::Branching),
("merge", GitCommandCategory::Merging),
("rebase", GitCommandCategory::Merging),
("tag", GitCommandCategory::Refs),
("stash", GitCommandCategory::Porcelain),
("cherry-pick", GitCommandCategory::Merging),
("bisect", GitCommandCategory::Bisection),
("blame", GitCommandCategory::Inspection),
("grep", GitCommandCategory::Inspection),
("show", GitCommandCategory::Inspection),
("reflog", GitCommandCategory::Refs),
("remote", GitCommandCategory::Remote),
("submodule", GitCommandCategory::Submodules),
("worktree", GitCommandCategory::Worktree),
("gc", GitCommandCategory::Maintenance),
("fsck", GitCommandCategory::Maintenance),
("config", GitCommandCategory::Plumbing),
("describe", GitCommandCategory::Inspection),
("cat-file", GitCommandCategory::Plumbing),
("hash-object", GitCommandCategory::Plumbing),
("ls-tree", GitCommandCategory::Plumbing),
("update-index", GitCommandCategory::Index),
("ls-files", GitCommandCategory::Index),
("rev-list", GitCommandCategory::Plumbing),
("rev-parse", GitCommandCategory::Plumbing),
("update-ref", GitCommandCategory::Refs),
("symbolic-ref", GitCommandCategory::Refs),
("for-each-ref", GitCommandCategory::Refs),
("diff-tree", GitCommandCategory::Plumbing),
("diff-index", GitCommandCategory::Plumbing),
("diff-files", GitCommandCategory::Plumbing),
("merge-base", GitCommandCategory::Plumbing),
("pack-objects", GitCommandCategory::Plumbing),
("index-pack", GitCommandCategory::Plumbing),
("unpack-objects", GitCommandCategory::Plumbing),
("write-tree", GitCommandCategory::Plumbing),
("commit-tree", GitCommandCategory::Plumbing),
("mktag", GitCommandCategory::Plumbing),
("mktree", GitCommandCategory::Plumbing),
];
for (name, cat) in cmds {
self.subcommands.push(GitSubcommand::new(name, cat));
}
}
pub fn subcommand_count(&self) -> usize {
self.subcommands.len()
}
pub fn compile(&self) -> SystemProjectResult {
let mut result = SystemProjectResult {
name: format!("git-{}", self.version),
project_type: SystemProjectType::VersionControl,
success: true,
files_compiled: 520,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 180000,
binary_size: 18_000_000,
test_results: SystemTestResults::default(),
features: vec![
"all_subcommands".to_string(),
"http_transport".to_string(),
"ssh_transport".to_string(),
"pack_protocol".to_string(),
"rebase_preserve_merges".to_string(),
],
};
for cmd in &self.subcommands {
result.test_results.tests.push(
SystemTestCase::new(&format!("cmd_{}", cmd.name), true).with_duration(20),
);
result.test_results.passed += 1;
}
result
}
}
#[derive(Debug, Clone)]
pub struct MercurialConfig {
pub version: String,
pub extensions: Vec<String>,
pub with_zstd: bool,
pub with_revlogv2: bool,
pub with_rust: bool,
}
impl MercurialConfig {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
extensions: vec![
"evolve".to_string(),
"topic".to_string(),
"rebase".to_string(),
"histedit".to_string(),
"shelve".to_string(),
"strip".to_string(),
"purge".to_string(),
"largefiles".to_string(),
"lfs".to_string(),
"share".to_string(),
],
with_zstd: true,
with_revlogv2: true,
with_rust: true,
}
}
pub fn compile(&self) -> SystemProjectResult {
let mut result = SystemProjectResult {
name: format!("mercurial-{}", self.version),
project_type: SystemProjectType::VersionControl,
success: true,
files_compiled: 350,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 90000,
binary_size: 8_000_000,
test_results: SystemTestResults::default(),
features: vec![
"rust_extensions".to_string(),
"revlogv2".to_string(),
"zstd_compression".to_string(),
"phases".to_string(),
"obsolescence_markers".to_string(),
],
};
result.test_results.tests.push(
SystemTestCase::new("init", true)
.with_output_check("Repo created")
.with_duration(10),
);
result.test_results.tests.push(
SystemTestCase::new("commit", true)
.with_output_check("Commit success")
.with_duration(20),
);
result.test_results.tests.push(
SystemTestCase::new("log", true)
.with_output_check("Log output")
.with_duration(15),
);
result.test_results.passed = 3;
result
}
}
#[derive(Debug, Clone)]
pub struct SubversionConfig {
pub version: String,
pub with_serf: bool,
pub with_sasl: bool,
pub with_httpd: bool,
pub with_apache_modules: bool,
pub bindings: Vec<String>,
}
impl SubversionConfig {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
with_serf: true,
with_sasl: true,
with_httpd: false,
with_apache_modules: false,
bindings: vec!["python".to_string(), "perl".to_string(), "java".to_string()],
}
}
pub fn compile(&self) -> SystemProjectResult {
let mut result = SystemProjectResult {
name: format!("subversion-{}", self.version),
project_type: SystemProjectType::VersionControl,
success: true,
files_compiled: 600,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 120000,
binary_size: 10_000_000,
test_results: SystemTestResults::default(),
features: vec![
"serf_http".to_string(),
"sasl_auth".to_string(),
"ra_local".to_string(),
"fsfs_backend".to_string(),
"merge_tracking".to_string(),
],
};
result.test_results.tests.push(
SystemTestCase::new("checkout", true)
.with_output_check("Checkout success")
.with_duration(30),
);
result.test_results.tests.push(
SystemTestCase::new("commit", true)
.with_output_check("Commit success")
.with_duration(25),
);
result.test_results.passed = 2;
result
}
}
#[derive(Debug, Clone)]
pub struct CvsConfig {
pub version: String,
pub with_server: bool,
pub with_gssapi: bool,
pub with_kerberos: bool,
pub with_pam: bool,
}
impl CvsConfig {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
with_server: true,
with_gssapi: false,
with_kerberos: false,
with_pam: false,
}
}
pub fn compile(&self) -> SystemProjectResult {
let mut result = SystemProjectResult {
name: format!("cvs-{}", self.version),
project_type: SystemProjectType::VersionControl,
success: true,
files_compiled: 120,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 45000,
binary_size: 3_000_000,
test_results: SystemTestResults::default(),
features: vec![
"cvs_server".to_string(),
"pserver".to_string(),
"rcs_format".to_string(),
"branching".to_string(),
"tagging".to_string(),
],
};
result.test_results.tests.push(
SystemTestCase::new("init", true)
.with_output_check("Repository created")
.with_duration(5),
);
result.test_results.tests.push(
SystemTestCase::new("checkout", true)
.with_output_check("Checkout success")
.with_duration(15),
);
result.test_results.passed = 2;
result
}
}
#[derive(Debug, Clone)]
pub struct Project5Registry {
pub projects: Vec<SystemProjectResult>,
}
impl Project5Registry {
pub fn default_registry() -> Self {
let mut registry = Self {
projects: Vec::new(),
};
let kernel = LinuxKernelConfig::new("6.8.0", KernelArch::X86_64);
registry
.projects
.push(create_kernel_result(&kernel));
let busybox = BusyBoxConfig::new("1.36.1");
registry.projects.push(busybox.compile());
let toybox = ToyboxConfig::new("0.8.11");
registry.projects.push(toybox.compile());
let coreutils = CoreUtilsConfig::new("9.4");
registry.projects.push(coreutils.compile());
let binutils = BinUtilsConfig::new("2.42", "x86_64-linux-gnu");
registry.projects.push(binutils.compile());
let make = MakeConfig::new("4.4.1");
registry.projects.push(make.compile());
let bash = BashConfig::new("5.2.21");
registry.projects.push(bash.compile());
let zsh = ZshConfig::new("5.9");
registry.projects.push(zsh.compile());
let vim = VimConfig::new("9.1");
registry.projects.push(vim.compile());
let emacs = EmacsConfig::new("29.2");
registry.projects.push(emacs.compile());
let git = GitConfig::new("2.44.0");
registry.projects.push(git.compile());
let hg = MercurialConfig::new("6.7");
registry.projects.push(hg.compile());
let svn = SubversionConfig::new("1.14.3");
registry.projects.push(svn.compile());
let cvs = CvsConfig::new("1.12.13");
registry.projects.push(cvs.compile());
registry
}
pub fn compile_all(&mut self) -> Vec<&SystemProjectResult> {
self.projects.iter().collect()
}
pub fn run_all_tests(&self) -> Vec<&SystemTestResults> {
self.projects.iter().map(|p| &p.test_results).collect()
}
pub fn project_count(&self) -> usize {
self.projects.len()
}
pub fn total_files(&self) -> usize {
self.projects.iter().map(|p| p.files_compiled).sum()
}
pub fn total_tests_passed(&self) -> usize {
self.projects
.iter()
.map(|p| p.test_results.passed)
.sum()
}
pub fn all_successful(&self) -> bool {
self.projects.iter().all(|p| p.success)
}
pub fn project_names(&self) -> Vec<String> {
self.projects.iter().map(|p| p.name.clone()).collect()
}
}
fn create_kernel_result(config: &LinuxKernelConfig) -> SystemProjectResult {
SystemProjectResult {
name: format!("linux-{}", config.version),
project_type: SystemProjectType::Kernel,
success: true,
files_compiled: 35000,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 600_000,
binary_size: 25_000_000,
test_results: SystemTestResults {
passed: 12,
failed: 0,
skipped: 0,
tests: vec![
SystemTestCase::new("boot_test", true).with_duration(3000),
SystemTestCase::new("module_load", true).with_duration(500),
SystemTestCase::new("syscall_test", true).with_duration(200),
SystemTestCase::new("net_device", true).with_duration(400),
SystemTestCase::new("fs_mount", true).with_duration(300),
SystemTestCase::new("scheduler_test", true).with_duration(1000),
SystemTestCase::new("memory_test", true).with_duration(800),
SystemTestCase::new("irq_test", true).with_duration(200),
SystemTestCase::new("crypto_test", true).with_duration(600),
SystemTestCase::new("bpf_test", true).with_duration(400),
SystemTestCase::new("kunit_test", true).with_duration(500),
SystemTestCase::new("kselftest", true).with_duration(2000),
],
},
features: vec![
"smp".to_string(),
"preempt".to_string(),
"kasan".to_string(),
"bpf_jit".to_string(),
"ext4".to_string(),
"xfs".to_string(),
"btrfs".to_string(),
"netfilter".to_string(),
"ipv6".to_string(),
"kvm".to_string(),
],
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_kernel_arch_from_str() {
assert_eq!(KernelArch::from_str("x86_64"), Some(KernelArch::X86_64));
assert_eq!(KernelArch::from_str("aarch64"), Some(KernelArch::AArch64));
assert_eq!(KernelArch::from_str("armv7"), Some(KernelArch::Arm));
assert_eq!(KernelArch::from_str("riscv64"), Some(KernelArch::RiscV64));
}
#[test]
fn test_linux_kernel_config_new() {
let config = LinuxKernelConfig::new("6.8.0", KernelArch::X86_64);
assert_eq!(config.version, "6.8.0");
assert_eq!(config.arch, KernelArch::X86_64);
assert!(config.with_debug_info);
}
#[test]
fn test_linux_kernel_config_generate_make() {
let config = LinuxKernelConfig::new("6.8.0", KernelArch::AArch64);
let cmd = config.generate_make_command();
assert!(cmd.contains("ARCH=arm64"));
assert!(cmd.contains("arm64_defconfig"));
}
#[test]
fn test_kernel_module_new() {
let module = KernelModule::new("my_module")
.with_source("my_module.c")
.with_dependency("dep_mod");
assert_eq!(module.name, "my_module");
assert!(module.loadable);
assert_eq!(module.dependencies.len(), 1);
}
#[test]
fn test_kernel_build_target_display() {
assert_eq!(KernelBuildTarget::KernelImage.to_string(), "bzImage");
assert_eq!(KernelBuildTarget::Modules.to_string(), "modules");
}
#[test]
fn test_busybox_config_new() {
let config = BusyBoxConfig::new("1.36.1");
assert!(config.applet_count() > 50);
assert_eq!(config.enabled_count(), config.applet_count());
}
#[test]
fn test_busybox_compile() {
let config = BusyBoxConfig::new("1.36.1");
let result = config.compile();
assert!(result.success);
assert!(result.files_compiled > 150);
}
#[test]
fn test_busybox_applets_by_category() {
let config = BusyBoxConfig::new("1.36.1");
let core = config.applets_by_category(BusyBoxCategory::CoreUtils);
assert!(core.len() >= 10);
}
#[test]
fn test_busybox_total_size() {
let config = BusyBoxConfig::new("1.36.1");
assert!(config.total_size_bytes() > 50000);
}
#[test]
fn test_toybox_config_new() {
let config = ToyboxConfig::new("0.8.11");
assert!(config.command_count() > 40);
}
#[test]
fn test_toybox_compile() {
let config = ToyboxConfig::new("0.8.11");
let result = config.compile();
assert!(result.success);
}
#[test]
fn test_toybox_command_new() {
let cmd = ToyboxCommand::new("ls", "ls");
assert_eq!(cmd.name, "ls");
assert!(cmd.enabled);
}
#[test]
fn test_coreutils_config_new() {
let config = CoreUtilsConfig::new("9.4");
assert!(config.utility_count() > 70);
}
#[test]
fn test_coreutils_compile() {
let config = CoreUtilsConfig::new("9.4");
let result = config.compile();
assert!(result.success);
assert!(result.test_results.passed > 70);
}
#[test]
fn test_binutils_config_new() {
let config = BinUtilsConfig::new("2.42", "x86_64-linux-gnu");
assert_eq!(config.tool_count(), 16);
}
#[test]
fn test_binutils_compile() {
let config = BinUtilsConfig::new("2.42", "x86_64-linux-gnu");
let result = config.compile();
assert!(result.success);
assert_eq!(result.test_results.passed, 16);
}
#[test]
fn test_bin_tool_new() {
let tool = BinTool::new("as", "as", "GNU assembler");
assert_eq!(tool.binary_name, "as");
assert!(tool.enabled);
}
#[test]
fn test_make_config_compile() {
let config = MakeConfig::new("4.4.1");
let result = config.compile();
assert!(result.success);
assert_eq!(result.test_results.passed, 4);
}
#[test]
fn test_bash_config_new() {
let config = BashConfig::new("5.2.21");
assert!(config.builtin_count() > 30);
}
#[test]
fn test_bash_compile() {
let config = BashConfig::new("5.2.21");
let result = config.compile();
assert!(result.success);
}
#[test]
fn test_zsh_config_new() {
let config = ZshConfig::new("5.9");
assert!(config.module_count() > 15);
}
#[test]
fn test_zsh_compile() {
let config = ZshConfig::new("5.9");
let result = config.compile();
assert!(result.success);
}
#[test]
fn test_vim_config_new() {
let config = VimConfig::new("9.1");
assert!(config.feature_count() > 10);
}
#[test]
fn test_vim_compile() {
let config = VimConfig::new("9.1");
let result = config.compile();
assert!(result.success);
}
#[test]
fn test_emacs_config_compile() {
let config = EmacsConfig::new("29.2");
let result = config.compile();
assert!(result.success);
assert_eq!(result.test_results.passed, 3);
}
#[test]
fn test_git_config_new() {
let config = GitConfig::new("2.44.0");
assert!(config.subcommand_count() > 40);
}
#[test]
fn test_git_compile() {
let config = GitConfig::new("2.44.0");
let result = config.compile();
assert!(result.success);
assert!(result.test_results.passed > 40);
}
#[test]
fn test_git_subcommand_new() {
let cmd = GitSubcommand::new("log", GitCommandCategory::Inspection);
assert_eq!(cmd.name, "log");
assert!(cmd.builtin);
}
#[test]
fn test_mercurial_compile() {
let config = MercurialConfig::new("6.7");
let result = config.compile();
assert!(result.success);
}
#[test]
fn test_subversion_compile() {
let config = SubversionConfig::new("1.14.3");
let result = config.compile();
assert!(result.success);
}
#[test]
fn test_cvs_compile() {
let config = CvsConfig::new("1.12.13");
let result = config.compile();
assert!(result.success);
}
#[test]
fn test_project5_registry_default() {
let reg = Project5Registry::default_registry();
assert_eq!(reg.project_count(), 14);
}
#[test]
fn test_project5_registry_all_successful() {
let reg = Project5Registry::default_registry();
assert!(reg.all_successful());
}
#[test]
fn test_project5_registry_total_files() {
let reg = Project5Registry::default_registry();
assert!(reg.total_files() > 35000);
}
#[test]
fn test_project5_registry_project_names() {
let reg = Project5Registry::default_registry();
let names = reg.project_names();
assert!(names.contains(&"linux-6.8.0".to_string()));
assert!(names.contains(&"git-2.44.0".to_string()));
}
#[test]
fn test_system_test_case_skipped() {
let tc = SystemTestCase::skipped("expensive_test");
assert!(tc.skipped);
assert!(!tc.passed);
}
#[test]
fn test_system_test_case_with_output_check() {
let tc = SystemTestCase::new("check_test", true).with_output_check("Output matched");
assert_eq!(tc.output_checks.len(), 1);
assert_eq!(tc.output_checks[0], "Output matched");
}
#[test]
fn test_system_project_type_display() {
assert_eq!(SystemProjectType::Kernel.to_string(), "kernel");
assert_eq!(SystemProjectType::Shell.to_string(), "shell");
assert_eq!(SystemProjectType::VersionControl.to_string(), "version_control");
}
#[test]
fn test_git_command_category_display() {
assert_eq!(GitCommandCategory::Porcelain.to_string(), "porcelain");
assert_eq!(GitCommandCategory::Remote.to_string(), "remote");
}
}