Files
windmill/backend/parsers/windmill-parser-wasm/build.nu
Ruben Fiszel a46aa641f9 feat: add R language support (#8263)
* feat: add R language support

Add R as a new supported scripting language in Windmill, following the
same pattern used for Ruby. Includes:

- Backend: ScriptLang::Rlang enum variant, DB migration, tree-sitter-r
  parser crate with tests, WASM parser binding, R executor with NSJail
  sandboxing, job dispatch and signature parsing
- Frontend: language picker, R icon, syntax highlighting, editor bar
  insertions (Sys.getenv, get_variable, get_resource), schema inference,
  init code template, BETA badge
- CLI: .r extension mapping, sync support, bootstrap template

R scripts use `main <- function(...)` syntax, jsonlite for JSON
serialization, and system curl for the Windmill client helper.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add R package resolution and installation

Parse library()/require() calls from R scripts to extract dependencies.
Resolve versions from CRAN, cache lockfiles in pip_resolution_cache,
and install packages to a shared R library cache. The run step sets
R_LIBS_USER so installed packages are available to the script.

- Parser: parse_r_requirements() extracts package names from AST
- Executor: resolve() generates lockfile, install() installs from CRAN
- Worker lockfiles: wire up R resolve for dependency jobs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add nsjail sandboxing for R resolve and install phases

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: fix R get_variable/get_resource and add sandbox annotation + e2e tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: fix R arg inference with JS fallback parser and get_variable/get_resource

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix flake

* nsjail

* nits

* fix: R install improvements - suppress verbose output, flat lockfile logging, Dockerfile R support, rlimits

- Suppress renv verbose output during resolve and install (controlled by #verbose annotation)
- Filter renv from install list (already loaded, causes noisy restart message)
- Log compact "resolved N packages" instead of full renv.lock JSON
- Add R (r-base, r-cran-renv) to DockerfileFull and DockerfileFullEe
- Use disable_rl for nsjail install config (R compiles from source)
- Reduce default concurrency from 20 to 5
- Add rlang to openflow.openapi.yaml
- Fix MainArgSignature (no_main_func -> auto_kind) after main merge

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* final

* fix: remove accidental R install from multiplayer Dockerfile

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: remove R from Windows build and DockerfileExtra

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: rename R migration to avoid timestamp collision with trigger_filter_logic

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* all

* fix: R install improvements - suppress verbose output, flat lockfile logging, Dockerfile R support, rlimits

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: add clear error when Rscript binary is missing

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: fix type errors in R fallback parser, use format! in wrap(), add R system prompts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: pyranota <pyra@duck.com>
2026-04-01 06:11:37 +00:00

164 lines
4.0 KiB
Nu
Executable File

#!/usr/bin/env nu
const targets = [
{
ident: "ts", # OUT_DIR inferred from this
desc: "Bun and Deno"
features: "ts-parser",
env: "default", # available: default, tree-sitter
}, {
ident: "regex",
desc: "Sql languages, Graphql and Bash/Powershell"
features: "sql-parser,graphql-parser,bash-parser",
env: "default",
}, {
ident: "py",
desc: "Python",
features: "py-parser",
env: "default",
}, {
ident: "go",
desc: "Go (Go-lang)",
features: "go-parser",
env: "default",
}, {
ident: "php",
desc: "Php",
features: "php-parser",
env: "default",
}, {
ident: "rust",
desc: "Rust",
features: "rust-parser",
env: "default",
}, {
ident: "yaml",
desc: "Ansible",
features: "ansible-parser",
env: "default",
}, {
ident: "csharp",
desc: "C#",
features: "csharp-parser",
env: "tree-sitter",
}, {
ident: "nu",
desc: "Nu (Nushell)",
features: "nu-parser",
env: "tree-sitter",
}, {
ident: "java",
desc: "Java",
features: "java-parser",
env: "tree-sitter",
}, {
ident: "ruby",
desc: "Ruby",
features: "ruby-parser",
env: "tree-sitter",
}, {
ident: "r",
desc: "R",
features: "r-parser",
env: "tree-sitter",
},
{
ident: "wac",
desc: "Workflow-as-Code",
features: "wac-parser",
env: "default",
}, {
ident: "asset",
desc: "Asset parsers (TS, Python, SQL) with SQL AST",
features: "asset-parser",
env: "default",
},
{
ident: "py-imports",
desc: "Python imports"
features: "py-imports-parser",
env: "default",
},
# ^^^ Add new entry here ^^^
];
# NOTE: This is legacy command for building all, but it is not more used
# #-# full pkg
# OUT_DIR="pkg"
# wasm-pack build --release --target web --out-dir $OUT_DIR --all-features \
# -Z build-std=panic_abort,std -Z build-std-features=panic_immediate_abort
# Build all separately
def 'main all' [ --no-opt(-n), --cli, --node ] {
if ($no_opt) {
if ($node) {
$targets | each { main $in.ident -n --node }
} else if ($cli) {
$targets | each { main $in.ident -n --cli }
} else {
$targets | each { main $in.ident -n }
}
} else {
if ($node) {
$targets | each { main $in.ident --node }
} else if ($cli) {
$targets | each { main $in.ident --cli }
} else {
$targets | each { main $in.ident }
}
}
}
# Build specific language
def main [
target: string, # Language, e.g.: py, ts, rust
--no-opt(-n), # Compile in debug mode for dev
--cli # Compile and place binaries in cli.
--node
] {
let t = $targets | where ident == $target;
if ($t | is-empty) {
let pretty = $targets | each {|t| $"• ($t.ident) - ($t.desc)"} | str join "\n";
panic $"Target '($target)' does not exist\n\nAvailable targets:\n($pretty)"
} else {
let t = $t | get 0;
mut profile = "";
mut tar = "";
if ($node) {
$env.OUT_DIR = $"node-pkg-($t.ident)"
$tar = "nodejs"
} else if ($cli) {
$env.OUT_DIR = $"../../../cli/wasm/($t.ident)"
$tar = "deno"
} else {
$env.OUT_DIR = $"pkg-($t.ident)"
$tar = "web"
}
if ($no_opt) {
$profile = "--no-opt"
} else {
$profile = "--release"
}
print $"Building in ($profile) mode ($env.OUT_DIR)"
match $t.env {
"default" => {
wasm-pack build --weak-refs ($profile) --target ($tar) --out-dir $env.OUT_DIR --features ($t.features) -Z build-std=panic_abort,std
},
"tree-sitter" => {
$env.CFLAGS_wasm32_unknown_unknown = $"-I(pwd)/wasm-sysroot -Wbad-function-cast -Wcast-function-type -fno-builtin"
$env.RUSTFLAGS = "-Zwasm-c-abi=spec"
wasm-pack build ($profile) --target ($tar) --out-dir $env.OUT_DIR --features $t.features
},
_ => { panic $"Unknown env template: ($t.env)" },
}
if ($cli) {
rm $"($env.OUT_DIR)/.gitignore"
} else {
let p = $"($env.OUT_DIR)/package.json"
open $p | update name $"windmill-parser-wasm-($t.ident)" | save -f $p
}
}
}