Skip to content

Commit ff99265

Browse files
committed
fix(r2x): fixed discoverability.
1 parent 496f59e commit ff99265

21 files changed

Lines changed: 612 additions & 7 deletions

File tree

crates/r2x-ast/src/extractor/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ impl PluginExtractor {
176176

177177
for plugin_match in root.find_all("$PLUGIN($$$ARGS)") {
178178
let env = plugin_match.get_env();
179-
let Some(callee) = env.get_match("$PLUGIN") else {
179+
let Some(callee) = env.get_match("PLUGIN") else {
180180
continue;
181181
};
182182
let callee_text = callee.text();

crates/r2x-cli/src/commands/python.rs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,84 @@ fn handle_python_show(_opts: GlobalOpts) {
356356
#[cfg(test)]
357357
mod tests {
358358
use super::*;
359+
use std::fs;
360+
use std::io;
361+
use std::path::Path;
362+
use tempfile::TempDir;
363+
364+
struct TestConfigGuard {
365+
_dir: TempDir,
366+
}
367+
368+
impl Drop for TestConfigGuard {
369+
fn drop(&mut self) {
370+
std::env::remove_var("R2X_CONFIG");
371+
}
372+
}
373+
374+
fn setup_test_config() -> TestConfigGuard {
375+
let dir = TempDir::new().expect("tempdir");
376+
let base = dir.path();
377+
let config_path = base.join("r2x.toml");
378+
let cache_path = base.join("cache");
379+
let venv_path = base.join(".venv");
380+
let uv_path = if cfg!(windows) {
381+
base.join("uv.bat")
382+
} else {
383+
base.join("uv")
384+
};
385+
386+
fs::create_dir_all(&cache_path).unwrap();
387+
fs::create_dir_all(&venv_path).unwrap();
388+
create_fake_python(&venv_path).unwrap();
389+
write_stub_uv(&uv_path).unwrap();
390+
391+
let config_contents = format!(
392+
"cache_path = \"{}\"\nuv_path = \"{}\"\nvenv_path = \"{}\"\npython_version = \"3.12\"\n",
393+
cache_path.to_string_lossy(),
394+
uv_path.to_string_lossy(),
395+
venv_path.to_string_lossy()
396+
);
397+
398+
fs::write(&config_path, config_contents).unwrap();
399+
std::env::set_var("R2X_CONFIG", &config_path);
400+
401+
TestConfigGuard { _dir: dir }
402+
}
403+
404+
#[cfg(unix)]
405+
fn write_stub_uv(path: &Path) -> io::Result<()> {
406+
use std::os::unix::fs::PermissionsExt;
407+
fs::write(path, "#!/bin/sh\nexit 0\n")?;
408+
let mut perms = fs::metadata(path)?.permissions();
409+
perms.set_mode(0o755);
410+
fs::set_permissions(path, perms)
411+
}
412+
413+
#[cfg(windows)]
414+
fn write_stub_uv(path: &Path) -> io::Result<()> {
415+
fs::write(path, "@echo off\r\nexit /b 0\r\n")
416+
}
417+
418+
#[cfg(unix)]
419+
fn create_fake_python(venv_path: &Path) -> io::Result<()> {
420+
use std::os::unix::fs::PermissionsExt;
421+
let bin = venv_path.join("bin");
422+
fs::create_dir_all(&bin)?;
423+
let python = bin.join("python");
424+
fs::write(&python, "#!/bin/sh\nexit 0\n")?;
425+
let mut perms = fs::metadata(&python)?.permissions();
426+
perms.set_mode(0o755);
427+
fs::set_permissions(python, perms)
428+
}
429+
430+
#[cfg(windows)]
431+
fn create_fake_python(venv_path: &Path) -> io::Result<()> {
432+
let scripts = venv_path.join("Scripts");
433+
fs::create_dir_all(&scripts)?;
434+
fs::write(scripts.join("python.exe"), [])?;
435+
Ok(())
436+
}
359437

360438
fn normal_opts() -> GlobalOpts {
361439
GlobalOpts {
@@ -367,6 +445,7 @@ mod tests {
367445

368446
#[test]
369447
fn test_python_install() {
448+
let _guard = setup_test_config();
370449
handle_python(
371450
PythonAction::Install {
372451
version: Some("3.12".to_string()),
@@ -377,35 +456,49 @@ mod tests {
377456

378457
#[test]
379458
fn test_python_install_no_version() {
459+
let _guard = setup_test_config();
380460
handle_python(PythonAction::Install { version: None }, normal_opts());
381461
}
382462

383463
#[test]
384464
fn test_python_path() {
465+
let _guard = setup_test_config();
385466
handle_python(PythonAction::Path, normal_opts());
386467
}
387468

388469
#[test]
389470
fn test_python_show() {
471+
let _guard = setup_test_config();
390472
handle_python(PythonAction::Show, normal_opts());
391473
}
392474

393475
#[test]
394476
fn test_venv_create() {
477+
let _guard = setup_test_config();
395478
handle_venv(None, false, normal_opts());
396479
}
397480

398481
#[test]
399482
fn test_venv_create_skip_confirm() {
483+
let _guard = setup_test_config();
400484
handle_venv(None, true, normal_opts());
401485
}
402486

403487
#[test]
404488
fn test_venv_path() {
489+
let _guard = setup_test_config();
405490
handle_venv(
406491
Some(VenvAction::Path { new_path: None }),
407492
false,
408493
normal_opts(),
409494
);
410495
}
496+
497+
#[test]
498+
fn test_venv_create_yes_flag() {
499+
let _guard = setup_test_config();
500+
std::env::set_var("R2X_VENV_YES", "1");
501+
handle_venv(None, false, normal_opts());
502+
std::env::remove_var("R2X_VENV_YES");
503+
}
411504
}

crates/r2x-cli/src/commands/run/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::GlobalOpts;
55
use clap::Parser;
66
use pipeline::handle_pipeline_mode;
77
use plugin::handle_plugin_command;
8-
use r2x_manifest::runtime::RuntimeBindings;
8+
use r2x_manifest::{runtime::RuntimeBindings, PluginKind};
99
use r2x_python::plugin_invoker::PluginInvocationTimings;
1010
use std::time::Duration;
1111

@@ -114,7 +114,9 @@ pub fn handle_run(cmd: RunCommand, opts: GlobalOpts) -> Result<(), RunError> {
114114
pub(super) fn build_call_target(bindings: &RuntimeBindings) -> Result<String, RunError> {
115115
let target = match bindings.implementation_type {
116116
r2x_manifest::ImplementationType::Class => {
117-
if let Some(call_method) = &bindings.call_method {
117+
if bindings.plugin_kind == PluginKind::Upgrader {
118+
format!("{}:{}", bindings.entry_module, bindings.entry_name)
119+
} else if let Some(call_method) = &bindings.call_method {
118120
format!("{}:{}.{}", bindings.entry_module, bindings.entry_name, call_method)
119121
} else {
120122
format!("{}:{}", bindings.entry_module, bindings.entry_name)

crates/r2x-cli/src/commands/run/pipeline.rs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -413,8 +413,9 @@ fn build_plugin_config(
413413
}
414414
}
415415

416-
let mut final_config = serde_json::Map::new();
417-
if bindings.implementation_type == r2x_manifest::ImplementationType::Class {
416+
let mut final_config = serde_json::Map::new();
417+
let mut store_value_for_folder: Option<serde_json::Value> = None;
418+
if bindings.implementation_type == r2x_manifest::ImplementationType::Class {
418419
let mut config_class_params = serde_json::Map::new();
419420
let mut constructor_params = serde_json::Map::new();
420421
let config_param_names: HashSet<String> = bindings
@@ -486,8 +487,39 @@ fn build_plugin_config(
486487
}
487488
};
488489

490+
store_value_for_folder = Some(store_value.clone());
489491
final_config.insert("data_store".to_string(), store_value);
490492
}
493+
494+
if bindings.entry_parameters.iter().any(|p| p.name == "folder_path")
495+
&& !final_config.contains_key("folder_path")
496+
{
497+
let explicit_folder = if let serde_json::Value::Object(ref yaml_map) = yaml_config {
498+
yaml_map
499+
.get("folder_path")
500+
.or_else(|| yaml_map.get("store_path"))
501+
.or_else(|| yaml_map.get("path"))
502+
.cloned()
503+
} else {
504+
None
505+
};
506+
507+
let folder_value = explicit_folder
508+
.or_else(|| {
509+
store_value_for_folder.as_ref().and_then(|value| match value {
510+
serde_json::Value::String(s) => Some(serde_json::Value::String(s.clone())),
511+
_ => None,
512+
})
513+
})
514+
.or_else(|| {
515+
inherited_store_path
516+
.map(|path| serde_json::Value::String(path.to_string()))
517+
});
518+
519+
if let Some(value) = folder_value {
520+
final_config.insert("folder_path".to_string(), value);
521+
}
522+
}
491523
} else if let serde_json::Value::Object(ref yaml_map) = yaml_config {
492524
final_config.extend(yaml_map.clone());
493525
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
cache_path = "/tmp/r2x-cache"
22
uv_path = "/Users/psanchez/.local/bin/uv"
3+
python_version = "3.12"

0 commit comments

Comments
 (0)