From 3b13da7064caaf5b6c6b88d42995c849bf03ecf9 Mon Sep 17 00:00:00 2001 From: Nick Mitchell Date: Fri, 31 Jan 2025 13:31:52 -0500 Subject: [PATCH] feat: embed PDL interpreter into react (tauri) app builds ```shell PDL run ``` Signed-off-by: Nick Mitchell --- pdl-live-react/package.json | 8 +- pdl-live-react/src-tauri/src/lib.rs | 132 ++++++++++++++--------- pdl-live-react/src-tauri/tauri.conf.json | 13 +++ 3 files changed, 99 insertions(+), 54 deletions(-) diff --git a/pdl-live-react/package.json b/pdl-live-react/package.json index 21980b8ae..861e7ac46 100644 --- a/pdl-live-react/package.json +++ b/pdl-live-react/package.json @@ -6,7 +6,7 @@ "scripts": { "dev": "vite", "build": "tsc && vite build", - "build:app": "npm run tauri build", + "build:app": "npm run prep_interpreter && npm run tauri build", "lint": "eslint .", "format": "prettier --write 'tests/**/*.ts' 'src/**/*.{ts,tsx,css}' && (cd src-tauri && cargo fmt)", "tauri": "tauri", @@ -14,8 +14,10 @@ "test:ui": "playwright install --with-deps && playwright test", "types": "(cd .. && python -m src.pdl.pdl --schema > src/pdl/pdl-schema.json) && json2ts ../src/pdl/pdl-schema.json src/pdl_ast.d.ts --unreachableDefinitions", "test": "concurrently -n 'quality,playwright' 'npm run test:quality' 'npm run test:ui'", - "view": "./src-tauri/target/debug/PDL view", - "start": "npm run tauri dev" + "pdl": "./src-tauri/target/debug/PDL", + "view": "npm run pdl view", + "prep_interpreter": "if [ ! -d .venv ]; then python3.12 -mvenv .venv; source .venv/bin/activate; pip install -e ..; fi", + "start": "npm run prep_interpreter && npm run tauri dev" }, "dependencies": { "@patternfly/react-code-editor": "^6.1.0", diff --git a/pdl-live-react/src-tauri/src/lib.rs b/pdl-live-react/src-tauri/src/lib.rs index 077995235..40eadb7df 100644 --- a/pdl-live-react/src-tauri/src/lib.rs +++ b/pdl-live-react/src-tauri/src/lib.rs @@ -1,9 +1,15 @@ -use serde_json::Value; +use std::env::args_os; use std::fs::read; -use std::path::Path; +use std::io::{BufRead, BufReader}; +use std::path::{Path, PathBuf}; +use std::process::{exit, Command, Stdio}; + +use serde_json::Value; use urlencoding::encode; use tauri::ipc::Response; +use tauri::path::BaseDirectory; +use tauri::Manager; use tauri_plugin_cli::CliExt; // Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ @@ -21,65 +27,55 @@ pub fn run() { app.handle().plugin(tauri_plugin_cli::init())?; // Default to GUI if the app was opened with no CLI args. - if std::env::args_os().count() <= 1 { + if args_os().count() <= 1 { gui(app.handle().clone(), "".to_owned())?; } match app.cli().matches() { // `matches` here is a Struct with { args, subcommand }. // `args` is `HashMap` where `ArgData` is a struct with { value, occurrences }. // `subcommand` is `Option>` where `SubcommandMatches` is a struct with { name, matches }. - Ok(matches) => { - match matches.subcommand { - Some(subcommand_matches) => { - match subcommand_matches.name.as_str() { - "view" => { - match subcommand_matches.matches.args.get("trace") { - Some(trace) => { - match &trace.value { - Value::String(trace_file) => { - // app.handle().plugin(tauri_plugin_fs::init())?; - - //let src = Path::new(trace_file); - //let name = src.file_name().unwrap(); - //let tmp = app.path().app_local_data_dir().join("mytraces").join(name); - //fs::copy(src, &tmp)?; + Ok(matches) => match matches.subcommand { + Some(subcommand_matches) => match subcommand_matches.name.as_str() { + "run" => { + if let Some(source) = subcommand_matches.matches.args.get("source") { + if let Value::String(source_file_path) = &source.value { + let interpreter_path = app + .path() + .resolve("interpreter/", BaseDirectory::Resource)?; - // allowed access to the trace directory - // let src = Path::new(&trace_file); - //let canon = fs::canonicalize(src)?; - //let abs = canon.as_path(); - //println!("!!!!!!!!!!!! {:?}", abs); - //let src = &abs.display().to_string(); - - let encoded = encode(trace_file); - gui( - app.handle().clone(), - Path::new("/local") - .join(encoded.as_ref()) - .display() - .to_string(), - )? - } - _ => { - println!("Usage: view "); - std::process::exit(1) - } - } - } - _ => { - println!("Usage: view "); - std::process::exit(1) - } - } + eval_pdl_program(source_file_path.clone(), interpreter_path)?; + exit(0) } - _ => {} } + println!("Usage: run "); + exit(1) } - None => {} - } - //println!(" {:?}", matches); - //gui(app.handle().clone(), "".to_owned())?; - } + "view" => match subcommand_matches.matches.args.get("trace") { + Some(trace) => match &trace.value { + Value::String(trace_file) => { + let encoded = encode(trace_file); + gui( + app.handle().clone(), + Path::new("/local") + .join(encoded.as_ref()) + .display() + .to_string(), + )? + } + _ => { + println!("Usage: view "); + exit(1) + } + }, + _ => { + println!("Usage: view "); + exit(1) + } + }, + _ => {} + }, + None => {} + }, Err(_) => {} } Ok(()) @@ -101,3 +97,37 @@ fn gui(app: tauri::AppHandle, path: String) -> Result<(), tauri::Error> { .build()?; Ok(()) } + +#[cfg(desktop)] +fn eval_pdl_program( + source_file_path: String, + interpreter_path: PathBuf, +) -> Result<(), tauri::Error> { + println!("Evaluating {:?}", source_file_path); + //let interp = interpreter_path.display().to_string() + let activate = interpreter_path.join("bin/activate").display().to_string(); + let mut child = Command::new("sh") + .args([ + "-c", + &[ + "source", + activate.as_str(), + "; pdl", + source_file_path.as_str(), + ] + .join(" "), + ]) + .stdout(Stdio::piped()) + .spawn() + .unwrap(); + + let stdout = child.stdout.take().unwrap(); + + // Stream output. + let lines = BufReader::new(stdout).lines(); + for line in lines { + println!("{}", line.unwrap()); + } + + Ok(()) +} diff --git a/pdl-live-react/src-tauri/tauri.conf.json b/pdl-live-react/src-tauri/tauri.conf.json index 5f1b6f13e..b6d29b218 100644 --- a/pdl-live-react/src-tauri/tauri.conf.json +++ b/pdl-live-react/src-tauri/tauri.conf.json @@ -20,6 +20,16 @@ "args": [ ], "subcommands": { + "run": { + "description": "Run a PDL program", + "args": [ + { + "name": "source", + "index": 1, + "takesValue": true + } + ] + }, "view": { "description": "View a trace", "args": [ @@ -36,6 +46,9 @@ "bundle": { "active": true, "targets": "all", + "resources": { + "../.venv/": "interpreter/" + }, "icon": [ "icons/32x32.png", "icons/128x128.png",