adding changes to the scripts tab, also added more capabilities
This commit is contained in:
+198
-9
@@ -68,6 +68,131 @@ pub fn execute_command(cmd: &str, args: &[&str], timeout_secs: u64) -> Result<Ex
|
||||
}
|
||||
}
|
||||
|
||||
pub fn detect_language(code: &str) -> &'static str {
|
||||
let trimmed = code.trim();
|
||||
let first_line = trimmed.lines().next().unwrap_or("").trim();
|
||||
|
||||
// Shebang detection
|
||||
if first_line.starts_with("#!/") {
|
||||
if first_line.contains("python") || first_line.contains("python3") {
|
||||
return "python";
|
||||
}
|
||||
if first_line.contains("bash") {
|
||||
return "bash";
|
||||
}
|
||||
if first_line.contains("sh") && !first_line.contains("bash") {
|
||||
return "bash";
|
||||
}
|
||||
if first_line.contains("ruby") {
|
||||
return "ruby";
|
||||
}
|
||||
if first_line.contains("perl") {
|
||||
return "perl";
|
||||
}
|
||||
if first_line.contains("node") {
|
||||
return "node";
|
||||
}
|
||||
}
|
||||
|
||||
// Rust: fn main, println!, use std, let mut
|
||||
if trimmed.contains("fn main")
|
||||
|| (trimmed.contains("println!") && trimmed.contains("fn "))
|
||||
|| trimmed.contains("use std::")
|
||||
{
|
||||
return "rust";
|
||||
}
|
||||
|
||||
// Go: package main, func main, import (, fmt.
|
||||
if (trimmed.contains("package main") && trimmed.contains("func main"))
|
||||
|| trimmed.contains("import (")
|
||||
|| trimmed.starts_with("package ")
|
||||
{
|
||||
return "go";
|
||||
}
|
||||
|
||||
// C/C++: #include
|
||||
if trimmed.contains("#include <") {
|
||||
if trimmed.contains("iostream") || trimmed.contains("std::") || trimmed.contains("using namespace") {
|
||||
return "cpp";
|
||||
}
|
||||
return "c";
|
||||
}
|
||||
|
||||
// PowerShell: Cmdlets (Get-*, Write-*), Param(, $var =, common aliases
|
||||
let ps_score = [
|
||||
"Write-Host", "Get-Process", "Get-Service", "Get-ChildItem", "Param(",
|
||||
"Write-Output", "Write-Error", "Get-Item", "Set-Item", "New-Item",
|
||||
"Remove-Item", "ForEach-Object", "Where-Object", "Select-Object",
|
||||
"| ForEach-Object", "foreach ($", "function ", "Export-Csv",
|
||||
].iter().filter(|&&kw| trimmed.contains(kw)).count();
|
||||
if ps_score >= 2 || (trimmed.starts_with("#requires") || trimmed.starts_with("<#")) {
|
||||
return "powershell";
|
||||
}
|
||||
if trimmed.contains("$") && (trimmed.contains("Write-Host") || trimmed.contains("Write-Output")) {
|
||||
return "powershell";
|
||||
}
|
||||
|
||||
// Python: import, def, print(, class, if __name__, @
|
||||
let py_score = [
|
||||
"import ", "from ", "def ", "class ", "print(",
|
||||
"if __name__", "elif ", "except ", "with ", "as ",
|
||||
"lambda ", "yield ", "async def", "await ",
|
||||
].iter().filter(|&&kw| trimmed.contains(kw)).count();
|
||||
if py_score >= 3 {
|
||||
return "python";
|
||||
}
|
||||
|
||||
// Node.js/JavaScript: require(, console.log, module.exports, process., =>
|
||||
let js_score = [
|
||||
"require(", "console.log", "module.exports", "process.env",
|
||||
"=>", "const ", "let ", "var ", "function(", "async (",
|
||||
"document.", "window.", "export default", "import ",
|
||||
].iter().filter(|&&kw| trimmed.contains(kw)).count();
|
||||
if js_score >= 2 {
|
||||
return "node";
|
||||
}
|
||||
|
||||
// Ruby: def, end, puts, attr_accessor, require ', class .. <
|
||||
let rb_score = [
|
||||
"def ", "\nend", "puts ", "require '", "attr_accessor",
|
||||
"attr_reader", "attr_writer", "do |", "=>", "::",
|
||||
].iter().filter(|&&kw| trimmed.contains(kw)).count();
|
||||
if rb_score >= 2 {
|
||||
return "ruby";
|
||||
}
|
||||
|
||||
// Perl: use strict, my $, sub, shift, print "
|
||||
let pl_score = [
|
||||
"use strict", "use warnings", "my $", "sub ", "shift",
|
||||
"print \"", "print '", "chomp", "foreach my", "while (<",
|
||||
].iter().filter(|&&kw| trimmed.contains(kw)).count();
|
||||
if pl_score >= 2 {
|
||||
return "perl";
|
||||
}
|
||||
|
||||
// Bash: if [, $#, fi, done, then, case, esac, redirects
|
||||
let sh_score = [
|
||||
"if [", "if [[", "$#", "\nfi", "\ndone", "\nthen",
|
||||
"case ", "esac", ">&2", "2>&1", "#!/", "echo \"",
|
||||
"while read", "for i in", "do\n", "$((", "${",
|
||||
].iter().filter(|&&kw| trimmed.contains(kw)).count();
|
||||
if sh_score >= 2 {
|
||||
return "bash";
|
||||
}
|
||||
|
||||
// CMD/BAT: @echo, setlocal, %var%, REM
|
||||
let cmd_score = [
|
||||
"@echo", "echo off", "setlocal", "endlocal", "%",
|
||||
"REM ", "rem ", "color ", "title ", "exit /b",
|
||||
"if not", "if defined", "set \"", ">nul",
|
||||
].iter().filter(|&&kw| trimmed.contains(kw)).count();
|
||||
if cmd_score >= 2 {
|
||||
return "cmd";
|
||||
}
|
||||
|
||||
"python"
|
||||
}
|
||||
|
||||
pub fn execute_script(language: &str, code: &str, timeout_secs: u64) -> Result<ExecutionResult> {
|
||||
let (interpreter, ext) = match language.to_lowercase().as_str() {
|
||||
"python" | "py" => ("python", ".py"),
|
||||
@@ -78,13 +203,16 @@ pub fn execute_script(language: &str, code: &str, timeout_secs: u64) -> Result<E
|
||||
"perl" => ("perl", ".pl"),
|
||||
"node" | "javascript" | "js" => ("node", ".js"),
|
||||
"rust" => return compile_and_run_rust(code, timeout_secs),
|
||||
_ => return Err(anyhow::anyhow!("Unsupported language: {}. Supported: python, bash, powershell, cmd, ruby, perl, node, rust", language)),
|
||||
"go" | "golang" => return compile_and_run_go(code, timeout_secs),
|
||||
"c" => return compile_and_run_c_cpp(code, timeout_secs, "c"),
|
||||
"cpp" | "c++" | "cxx" => return compile_and_run_c_cpp(code, timeout_secs, "cpp"),
|
||||
_ => return Err(anyhow::anyhow!("Unsupported language: {}. Supported: python, bash, powershell, cmd, ruby, perl, node, rust, go, c, cpp", language)),
|
||||
};
|
||||
|
||||
let temp_dir = std::env::temp_dir().join("airust_scripts");
|
||||
std::fs::create_dir_all(&temp_dir)?;
|
||||
let script_path = temp_dir.join(format!("script_{}{}", std::process::id(), ext));
|
||||
|
||||
|
||||
let mut file = std::fs::File::create(&script_path)?;
|
||||
file.write_all(code.as_bytes())?;
|
||||
drop(file);
|
||||
@@ -102,10 +230,10 @@ pub fn execute_script(language: &str, code: &str, timeout_secs: u64) -> Result<E
|
||||
fn compile_and_run_rust(code: &str, timeout_secs: u64) -> Result<ExecutionResult> {
|
||||
let temp_dir = std::env::temp_dir().join("airust_scripts");
|
||||
std::fs::create_dir_all(&temp_dir)?;
|
||||
|
||||
|
||||
let source_path = temp_dir.join(format!("script_{}.rs", std::process::id()));
|
||||
let bin_path = temp_dir.join(format!("script_{}", std::process::id()));
|
||||
|
||||
|
||||
let mut file = std::fs::File::create(&source_path)?;
|
||||
file.write_all(code.as_bytes())?;
|
||||
drop(file);
|
||||
@@ -122,11 +250,69 @@ fn compile_and_run_rust(code: &str, timeout_secs: u64) -> Result<ExecutionResult
|
||||
});
|
||||
}
|
||||
|
||||
let run_result = if cfg!(windows) {
|
||||
execute_command(bin_path.to_str().unwrap(), &[], timeout_secs)
|
||||
} else {
|
||||
execute_command(&bin_path.to_str().unwrap(), &[], timeout_secs)
|
||||
};
|
||||
let run_result = execute_command(bin_path.to_str().unwrap(), &[], timeout_secs);
|
||||
|
||||
let _ = std::fs::remove_file(&source_path);
|
||||
let _ = std::fs::remove_file(&bin_path);
|
||||
run_result
|
||||
}
|
||||
|
||||
fn compile_and_run_go(code: &str, timeout_secs: u64) -> Result<ExecutionResult> {
|
||||
let temp_dir = std::env::temp_dir().join("airust_scripts");
|
||||
std::fs::create_dir_all(&temp_dir)?;
|
||||
|
||||
let source_path = temp_dir.join(format!("script_{}.go", std::process::id()));
|
||||
let bin_path = temp_dir.join(format!("script_{}.exe", std::process::id()));
|
||||
|
||||
let mut file = std::fs::File::create(&source_path)?;
|
||||
file.write_all(code.as_bytes())?;
|
||||
drop(file);
|
||||
|
||||
let compile = execute_command("go", &["build", "-o", bin_path.to_str().unwrap(), source_path.to_str().unwrap()], timeout_secs)?;
|
||||
if !compile.success {
|
||||
return Ok(ExecutionResult {
|
||||
command: "go build".to_string(),
|
||||
exit_code: compile.exit_code,
|
||||
stdout: String::new(),
|
||||
stderr: compile.stderr,
|
||||
duration_ms: compile.duration_ms,
|
||||
success: false,
|
||||
});
|
||||
}
|
||||
|
||||
let run_result = execute_command(bin_path.to_str().unwrap(), &[], timeout_secs);
|
||||
|
||||
let _ = std::fs::remove_file(&source_path);
|
||||
let _ = std::fs::remove_file(&bin_path);
|
||||
run_result
|
||||
}
|
||||
|
||||
fn compile_and_run_c_cpp(code: &str, timeout_secs: u64, lang: &str) -> Result<ExecutionResult> {
|
||||
let temp_dir = std::env::temp_dir().join("airust_scripts");
|
||||
std::fs::create_dir_all(&temp_dir)?;
|
||||
|
||||
let ext = if lang == "cpp" { ".cpp" } else { ".c" };
|
||||
let source_path = temp_dir.join(format!("script_{}{}", std::process::id(), ext));
|
||||
let bin_path = temp_dir.join(format!("script_{}.exe", std::process::id()));
|
||||
|
||||
let mut file = std::fs::File::create(&source_path)?;
|
||||
file.write_all(code.as_bytes())?;
|
||||
drop(file);
|
||||
|
||||
let compiler = if lang == "cpp" { "g++" } else { "gcc" };
|
||||
let compile = execute_command(compiler, &[source_path.to_str().unwrap(), "-o", bin_path.to_str().unwrap()], timeout_secs)?;
|
||||
if !compile.success {
|
||||
return Ok(ExecutionResult {
|
||||
command: format!("{} (compile)", compiler),
|
||||
exit_code: compile.exit_code,
|
||||
stdout: String::new(),
|
||||
stderr: compile.stderr,
|
||||
duration_ms: compile.duration_ms,
|
||||
success: false,
|
||||
});
|
||||
}
|
||||
|
||||
let run_result = execute_command(bin_path.to_str().unwrap(), &[], timeout_secs);
|
||||
|
||||
let _ = std::fs::remove_file(&source_path);
|
||||
let _ = std::fs::remove_file(&bin_path);
|
||||
@@ -144,5 +330,8 @@ pub fn list_supported_languages() -> Vec<String> {
|
||||
"ruby".to_string(),
|
||||
"perl".to_string(),
|
||||
"rust".to_string(),
|
||||
"go".to_string(),
|
||||
"c".to_string(),
|
||||
"cpp".to_string(),
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user