Merge wasi-common into wasmtime

This commit merges [CraneStation/wasi-common] repo as a subdir of
this repo while preserving **all** of git history. There is an
initiative to pull `wasi-common` into [CraneStation/wasmtime], and
[CraneStation/wasmtime] becoming a monorepo. This came about for
several reasons with a common theme of convenience, namely,
having a monorepo:
1. cleans up the problem of dependencies (as we have seen first
   hand with dependabot enabled, it can cause some grief)
2. completely removes the problem of syncing the closely dependent
   repos (e.g., updating `wasi-common` with say a bugfix generally
   implies creating a "sync" commit for pulling in the changes into
   the "parent" repo, in this case, `wasmtime`)
3. mainly for the two reasons above, makes publishing to crates.io
   easier
4. hopefully streamlines the process of getting the community
   involved in contributing to `wasi-common` as now everything
   is one place

[CraneStation/wasi-common]: https://github.com/CraneStation/wasi-common
[CraneStation/wasmtime]: https://github.com/CraneStation/wasmtime
This commit is contained in:
Jakub Konka
2019-11-07 15:16:34 +01:00
120 changed files with 14853 additions and 5 deletions

219
wasi-common/build.rs Normal file
View File

@@ -0,0 +1,219 @@
//! Build program to generate a program which runs all the testsuites.
//!
//! By generating a separate `#[test]` test for each file, we allow cargo test
//! to automatically run the files in parallel.
//!
//! Idea adapted from: https://github.com/CraneStation/wasmtime/blob/master/build.rs
//! Thanks @sunfishcode
fn main() {
#[cfg(feature = "wasm_tests")]
wasm_tests::build_and_generate_tests();
}
#[cfg(feature = "wasm_tests")]
mod wasm_tests {
use std::env;
use std::fs::{read_dir, DirEntry, File};
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
pub(crate) fn build_and_generate_tests() {
// Validate if any of test sources are present and if they changed
// This should always work since there is no submodule to init anymore
let bin_tests = std::fs::read_dir("wasi-misc-tests/src/bin").unwrap();
for test in bin_tests {
if let Ok(test_file) = test {
let test_file_path = test_file
.path()
.into_os_string()
.into_string()
.expect("test file path");
println!("cargo:rerun-if-changed={}", test_file_path);
}
}
// Build tests to OUT_DIR (target/*/build/wasi-common-*/out/wasm32-wasi/release/*.wasm)
let out_dir = PathBuf::from(
env::var("OUT_DIR").expect("The OUT_DIR environment variable must be set"),
);
let mut out = File::create(out_dir.join("wasi_misc_tests.rs"))
.expect("error generating test source file");
build_tests("wasi-misc-tests", &out_dir).expect("building tests");
test_directory(&mut out, "wasi-misc-tests", &out_dir).expect("generating tests");
}
fn build_tests(testsuite: &str, out_dir: &Path) -> io::Result<()> {
let mut cmd = Command::new("cargo");
cmd.args(&[
"build",
"--release",
"--target=wasm32-wasi",
"--target-dir",
out_dir.to_str().unwrap(),
])
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.current_dir(testsuite);
let output = cmd.output()?;
let status = output.status;
if !status.success() {
panic!(
"Building tests failed: exit code: {}",
status.code().unwrap()
);
}
Ok(())
}
fn test_directory(out: &mut File, testsuite: &str, out_dir: &Path) -> io::Result<()> {
let mut dir_entries: Vec<_> = read_dir(out_dir.join("wasm32-wasi/release"))
.expect("reading testsuite directory")
.map(|r| r.expect("reading testsuite directory entry"))
.filter(|dir_entry| {
let p = dir_entry.path();
if let Some(ext) = p.extension() {
// Only look at wast files.
if ext == "wasm" {
// Ignore files starting with `.`, which could be editor temporary files
if let Some(stem) = p.file_stem() {
if let Some(stemstr) = stem.to_str() {
if !stemstr.starts_with('.') {
return true;
}
}
}
}
}
false
})
.collect();
dir_entries.sort_by_key(|dir| dir.path());
writeln!(
out,
"mod {} {{",
Path::new(testsuite)
.file_stem()
.expect("testsuite filename should have a stem")
.to_str()
.expect("testsuite filename should be representable as a string")
.replace("-", "_")
)?;
writeln!(out, " use super::{{runtime, utils, setup_log}};")?;
for dir_entry in dir_entries {
write_testsuite_tests(out, dir_entry, testsuite)?;
}
writeln!(out, "}}")?;
Ok(())
}
fn write_testsuite_tests(
out: &mut File,
dir_entry: DirEntry,
testsuite: &str,
) -> io::Result<()> {
let path = dir_entry.path();
let stemstr = path
.file_stem()
.expect("file_stem")
.to_str()
.expect("to_str");
writeln!(out, " #[test]")?;
if ignore(testsuite, stemstr) {
writeln!(out, " #[ignore]")?;
}
writeln!(
out,
" fn {}() -> Result<(), String> {{",
avoid_keywords(&stemstr.replace("-", "_"))
)?;
writeln!(out, " setup_log();")?;
write!(out, " let path = std::path::Path::new(\"")?;
// Write out the string with escape_debug to prevent special characters such
// as backslash from being reinterpreted.
for c in path.display().to_string().chars() {
write!(out, "{}", c.escape_debug())?;
}
writeln!(out, "\");")?;
writeln!(out, " let data = utils::read_wasm(path)?;")?;
writeln!(
out,
" let bin_name = utils::extract_exec_name_from_path(path)?;"
)?;
let workspace = if no_preopens(testsuite, stemstr) {
"None"
} else {
writeln!(
out,
" let workspace = utils::prepare_workspace(&bin_name)?;"
)?;
"Some(workspace.path())"
};
writeln!(
out,
" runtime::instantiate(&data, &bin_name, {})",
workspace
)?;
writeln!(out, " }}")?;
writeln!(out)?;
Ok(())
}
/// Rename tests which have the same name as Rust keywords.
fn avoid_keywords(name: &str) -> &str {
match name {
"if" => "if_",
"loop" => "loop_",
"type" => "type_",
"const" => "const_",
"return" => "return_",
other => other,
}
}
cfg_if::cfg_if! {
if #[cfg(not(windows))] {
/// Ignore tests that aren't supported yet.
fn ignore(_testsuite: &str, _name: &str) -> bool {
false
}
} else {
/// Ignore tests that aren't supported yet.
fn ignore(testsuite: &str, name: &str) -> bool {
if testsuite == "wasi-misc-tests" {
match name {
"readlink_no_buffer" => true,
"dangling_symlink" => true,
"symlink_loop" => true,
"truncation_rights" => true,
"path_rename_trailing_slashes" => true,
"fd_readdir" => true,
"poll_oneoff" => true,
_ => false,
}
} else {
unreachable!()
}
}
}
}
/// Mark tests which do not require preopens
fn no_preopens(testsuite: &str, name: &str) -> bool {
if testsuite == "wasi-misc-tests" {
match name {
"big_random_buf" => true,
"clock_time_get" => true,
"sched_yield" => true,
_ => false,
}
} else {
unreachable!()
}
}
}