Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 46 additions & 16 deletions .github/workflows/examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ jobs:
lang: asc
- name: web-leptos
lang: rust
- name: nodejs-express-api
lang: nodejs

runs-on: ${{ matrix.os }}

Expand Down Expand Up @@ -74,6 +72,25 @@ jobs:
with:
go-version: 'stable'

- name: Install TinyGo (Linux)
if: matrix.example.lang == 'go' && runner.os == 'Linux'
run: |
TINYGO_VERSION=0.33.0
wget -q "https://github.com/tinygo-org/tinygo/releases/download/v${TINYGO_VERSION}/tinygo${TINYGO_VERSION}.linux-amd64.tar.gz"
tar -xzf "tinygo${TINYGO_VERSION}.linux-amd64.tar.gz"
echo "$(pwd)/tinygo/bin" >> $GITHUB_PATH
shell: bash

- name: Install TinyGo (Windows)
if: matrix.example.lang == 'go' && runner.os == 'Windows'
run: |
$version = "0.33.0"
$url = "https://github.com/tinygo-org/tinygo/releases/download/v${version}/tinygo${version}.windows-amd64.zip"
Invoke-WebRequest -Uri $url -OutFile "tinygo.zip"
Expand-Archive -Path "tinygo.zip" -DestinationPath "."
Add-Content $env:GITHUB_PATH "$(Get-Location)\tinygo\bin"
shell: powershell

- name: Install Node.js
if: matrix.example.lang == 'asc' || matrix.example.lang == 'nodejs'
uses: actions/setup-node@v4
Expand All @@ -84,7 +101,7 @@ jobs:
if: matrix.example.lang == 'asc'
run: npm install -g assemblyscript

- name: Install Emscripten
- name: Install Emscripten (Linux)
if: matrix.example.lang == 'c' && runner.os == 'Linux'
run: |
git clone https://github.com/emscripten-core/emsdk.git
Expand All @@ -99,6 +116,11 @@ jobs:
cd emsdk
.\emsdk install latest
.\emsdk activate latest
# Add emscripten to PATH so bash subprocesses (used by make) can find emcc
$emsdkPath = (Get-Item ".\emsdk").FullName
Add-Content $env:GITHUB_PATH "$emsdkPath\upstream\emscripten"
Add-Content $env:GITHUB_PATH "$emsdkPath\node\current\bin"
shell: powershell

- name: Install wasm-bindgen-cli
if: matrix.example.lang == 'rust'
Expand All @@ -116,20 +138,25 @@ jobs:
env:
SKIP_UI_BUILD: 1

# Install waspy plugin for Python examples
- name: Install waspy plugin
if: matrix.example.lang == 'python'
# Install plugins for languages that need them
- name: Install waspy plugin (Linux)
if: matrix.example.lang == 'python' && runner.os == 'Linux'
run: ./target/release/wasmrun plugin install waspy
shell: bash

- name: Install waspy plugin (Windows)
if: matrix.example.lang == 'python' && runner.os == 'Windows'
run: .\target\release\wasmrun.exe plugin install waspy
shell: powershell

# Test example compilation
- name: Test ${{ matrix.example.name }} (Linux)
if: runner.os == 'Linux'
run: |
if [ "${{ matrix.example.lang }}" = "c" ]; then
source ./emsdk/emsdk_env.sh
fi
timeout 60 ./target/release/wasmrun compile examples/${{ matrix.example.name }} -o /tmp/wasmrun_test_${{ matrix.example.name }} -v || exit 1
timeout 120 ./target/release/wasmrun compile examples/${{ matrix.example.name }} -o /tmp/wasmrun_test_${{ matrix.example.name }} -v || exit 1
shell: bash

- name: Test ${{ matrix.example.name }} (Windows)
Expand All @@ -141,29 +168,32 @@ jobs:
& .\target\release\wasmrun.exe compile examples\${{ matrix.example.name }} -o $env:TEMP\wasmrun_test_${{ matrix.example.name }} -v
if ($LASTEXITCODE -ne 0) { exit 1 }
shell: powershell
timeout-minutes: 2
timeout-minutes: 5

- name: Verify output files exist (Linux)
if: runner.os == 'Linux'
run: |
if [ ! -f /tmp/wasmrun_test_${{ matrix.example.name }}/*.wasm ]; then
echo "Error: WASM file not found"
ls -la /tmp/wasmrun_test_${{ matrix.example.name }}/
OUTPUT_DIR="/tmp/wasmrun_test_${{ matrix.example.name }}"
WASM_COUNT=$(find "$OUTPUT_DIR" -name "*.wasm" 2>/dev/null | wc -l)
if [ "$WASM_COUNT" -eq 0 ]; then
echo "Error: No WASM file found in $OUTPUT_DIR"
ls -la "$OUTPUT_DIR/" 2>/dev/null || echo "Output directory does not exist"
exit 1
fi
echo "✓ Example ${{ matrix.example.name }} compiled successfully"
echo "✓ Example ${{ matrix.example.name }} compiled successfully ($WASM_COUNT wasm file(s))"
shell: bash

- name: Verify output files exist (Windows)
if: runner.os == 'Windows'
run: |
$wasmFiles = Get-ChildItem -Path "$env:TEMP\wasmrun_test_${{ matrix.example.name }}" -Filter "*.wasm"
$outputDir = "$env:TEMP\wasmrun_test_${{ matrix.example.name }}"
$wasmFiles = Get-ChildItem -Path $outputDir -Filter "*.wasm" -Recurse -ErrorAction SilentlyContinue
if ($wasmFiles.Count -eq 0) {
Write-Host "Error: WASM file not found"
Get-ChildItem -Path "$env:TEMP\wasmrun_test_${{ matrix.example.name }}"
Write-Host "Error: No WASM file found in $outputDir"
Get-ChildItem -Path $outputDir -ErrorAction SilentlyContinue
exit 1
}
Write-Host "✓ Example ${{ matrix.example.name }} compiled successfully"
Write-Host "✓ Example ${{ matrix.example.name }} compiled successfully ($($wasmFiles.Count) wasm file(s))"
shell: powershell

summary:
Expand Down
42 changes: 20 additions & 22 deletions src/compiler/detect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,17 @@ pub fn detect_project_language(project_path: &str) -> ProjectLanguage {
}
}

// asconfig.json is the definitive indicator of an AssemblyScript project
if path.join("asconfig.json").exists() {
debug_println!("Found asconfig.json - detected AssemblyScript project");
return ProjectLanguage::Asc;
}

if let Ok(package_json) = fs::read_to_string(path.join("package.json")) {
if package_json.contains("\"asc\"") {
if package_json.contains("assemblyscript") || package_json.contains("\"asc\"") {
debug_println!(
"Found assemblyscript in package.json - detected AssemblyScript project"
);
return ProjectLanguage::Asc;
}
}
Expand Down Expand Up @@ -148,17 +157,10 @@ pub fn detect_operating_system() -> OperatingSystem {
pub fn get_recommended_tools(language: &ProjectLanguage, os: &OperatingSystem) -> Vec<String> {
let recommended_tools = match (language, os) {
(ProjectLanguage::Rust, _) => {
vec![
"rustup".to_string(),
"cargo".to_string(),
"External Rust plugin (install with: wasmrun plugin install wasmrust)".to_string(),
]
vec!["cargo".to_string(), "wasm-bindgen".to_string()]
}
(ProjectLanguage::Go, _) => {
vec![
"External Go plugin (install with: wasmrun plugin install wasmgo)".to_string(),
"tinygo".to_string(),
]
vec!["tinygo".to_string()]
}
(ProjectLanguage::C, OperatingSystem::Windows) => {
vec![
Expand All @@ -175,13 +177,10 @@ pub fn get_recommended_tools(language: &ProjectLanguage, os: &OperatingSystem) -
]
}
(ProjectLanguage::Asc, _) => {
vec!["node.js".to_string(), "npm".to_string(), "asc".to_string()]
vec!["asc".to_string()]
}
(ProjectLanguage::Python, _) => {
vec![
"External Python plugin (install with: wasmrun plugin install waspy)".to_string(),
"python3".to_string(),
]
vec!["External Python plugin (install with: wasmrun plugin install waspy)".to_string()]
}
(ProjectLanguage::Unknown, _) => Vec::new(),
};
Expand Down Expand Up @@ -330,19 +329,18 @@ mod tests {

#[test]
fn test_get_recommended_tools_rust() {
// get_recommended_tools filters out already-installed tools, so the result
// depends on what's installed on the system — we just check it doesn't panic
let tools = get_recommended_tools(&ProjectLanguage::Rust, &OperatingSystem::Linux);
// Since tool installation depends on the system, we just check structure
assert!(tools
.iter()
.any(|t| t.contains("cargo") || t.contains("rustup") || t.contains("Rust")));
// All returned tool names should be non-empty strings
assert!(tools.iter().all(|t| !t.is_empty()));
}

#[test]
fn test_get_recommended_tools_go() {
let tools = get_recommended_tools(&ProjectLanguage::Go, &OperatingSystem::Linux);
assert!(tools
.iter()
.any(|t| t.contains("tinygo") || t.contains("Go")));
// All returned tool names should be non-empty strings
assert!(tools.iter().all(|t| !t.is_empty()));
}

#[test]
Expand Down
23 changes: 14 additions & 9 deletions src/plugin/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

use crate::compiler::builder::WasmBuilder;
use crate::error::Result;
use crate::plugin::languages::asc_plugin::AscPlugin;
use crate::plugin::languages::c_plugin::CPlugin;
use crate::plugin::languages::go_plugin::GoPlugin;
use crate::plugin::languages::rust_plugin::RustPlugin;
use crate::plugin::{Plugin, PluginCapabilities, PluginInfo, PluginType};
use std::sync::Arc;

Expand Down Expand Up @@ -157,10 +160,10 @@ impl WasmBuilder for BuiltinBuilderWrapper {

/// Load all built-in plugins into a vector
pub fn load_all_builtin_plugins(plugins: &mut Vec<Box<dyn Plugin>>) -> Result<()> {
// C plugin
let c_plugin = Arc::new(CPlugin::new());
plugins.push(Box::new(BuiltinPlugin::new(c_plugin)));

plugins.push(Box::new(BuiltinPlugin::new(Arc::new(CPlugin::new()))));
plugins.push(Box::new(BuiltinPlugin::new(Arc::new(AscPlugin::new()))));
plugins.push(Box::new(BuiltinPlugin::new(Arc::new(GoPlugin::new()))));
plugins.push(Box::new(BuiltinPlugin::new(Arc::new(RustPlugin::new()))));
Ok(())
}

Expand All @@ -173,7 +176,7 @@ pub fn get_builtin_plugin_info() -> Vec<PluginInfo> {
/// Check if a plugin name is a built-in plugin
#[allow(dead_code)] // TODO: Future plugin validation
pub fn is_builtin_plugin(name: &str) -> bool {
matches!(name, "c")
matches!(name, "c" | "asc" | "go" | "rust")
}

/// Get specific built-in plugin info by name
Expand Down Expand Up @@ -210,8 +213,10 @@ mod tests {

let plugin_names: Vec<&str> = plugins.iter().map(|p| p.info().name.as_str()).collect();

// Check that we have the expected builtin plugins
assert!(plugin_names.contains(&"c"));
assert!(plugin_names.contains(&"asc"));
assert!(plugin_names.contains(&"go"));
assert!(plugin_names.contains(&"rust"));
}

#[test]
Expand Down Expand Up @@ -317,10 +322,10 @@ mod tests {
#[test]
fn test_is_builtin_plugin() {
assert!(is_builtin_plugin("c"));
assert!(is_builtin_plugin("asc"));
assert!(is_builtin_plugin("go"));
assert!(is_builtin_plugin("rust"));

assert!(!is_builtin_plugin("asc"));
assert!(!is_builtin_plugin("rust"));
assert!(!is_builtin_plugin("go"));
assert!(!is_builtin_plugin("python"));
assert!(!is_builtin_plugin("nonexistent"));
assert!(!is_builtin_plugin(""));
Expand Down
Loading
Loading