Bye bye tokio

This commit is contained in:
Filip Tibell 2025-04-29 15:38:04 +02:00
parent 62910f02ab
commit 39f6319bdb
No known key found for this signature in database
14 changed files with 226 additions and 581 deletions

602
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -28,9 +28,9 @@ futures = { version = "0.3", default-features = false, features = ["std"] }
futures-lite = "2.6" futures-lite = "2.6"
futures-rustls = "0.26" futures-rustls = "0.26"
http-body-util = "0.1" http-body-util = "0.1"
hyper = { version = "1.6", features = ["http1", "client", "server"] } hyper = { version = "1.6", default-features = false, features = ["http1", "client", "server"] }
pin-project-lite = "0.2" pin-project-lite = "0.2"
rustls = "0.23" rustls = { version = "0.23", default-features = false, features = ["std", "tls12", "ring"] }
rustls-pki-types = "1.11" rustls-pki-types = "1.11"
url = "2.5" url = "2.5"
urlencoding = "2.1" urlencoding = "2.1"

View file

@ -26,7 +26,7 @@ std-luau = ["dep:lune-std", "lune-std/luau"]
std-net = ["dep:lune-std", "lune-std/net"] std-net = ["dep:lune-std", "lune-std/net"]
std-process = ["dep:lune-std", "lune-std/process"] std-process = ["dep:lune-std", "lune-std/process"]
std-regex = ["dep:lune-std", "lune-std/regex"] std-regex = ["dep:lune-std", "lune-std/regex"]
std-roblox = ["dep:lune-std", "lune-std/roblox", "dep:lune-roblox"] std-roblox = ["dep:lune-std", "lune-std/roblox"]
std-serde = ["dep:lune-std", "lune-std/serde"] std-serde = ["dep:lune-std", "lune-std/serde"]
std-stdio = ["dep:lune-std", "lune-std/stdio"] std-stdio = ["dep:lune-std", "lune-std/stdio"]
std-task = ["dep:lune-std", "lune-std/task"] std-task = ["dep:lune-std", "lune-std/task"]
@ -57,20 +57,20 @@ anyhow = "1.0"
console = "0.15" console = "0.15"
dialoguer = "0.11" dialoguer = "0.11"
directories = "6.0" directories = "6.0"
futures-util = "0.3"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
thiserror = "2.0" thiserror = "2.0"
async-io = "2.4"
async-fs = "2.1"
blocking = "1.6"
futures-lite = "2.6"
ureq = { version = "3.0", default-features = false, features = ["rustls", "gzip"] }
tracing = "0.1" tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing-subscriber = { version = "0.3", features = ["env-filter"] }
tokio = { version = "1", features = ["full"] }
reqwest = { version = "0.11", default-features = false, features = [
"rustls-tls",
] }
lune-std = { optional = true, version = "0.2.0", path = "../lune-std" } lune-std = { optional = true, version = "0.2.0", path = "../lune-std" }
lune-roblox = { optional = true, version = "0.2.0", path = "../lune-roblox" }
lune-utils = { version = "0.2.0", path = "../lune-utils" } lune-utils = { version = "0.2.0", path = "../lune-utils" }
### CLI ### CLI

View file

@ -3,7 +3,8 @@ use std::{
path::PathBuf, path::PathBuf,
}; };
use tokio::{fs, task}; use async_fs as fs;
use blocking::unblock;
use crate::standalone::metadata::CURRENT_EXE; use crate::standalone::metadata::CURRENT_EXE;
@ -44,25 +45,30 @@ pub async fn get_or_download_base_executable(target: BuildTarget) -> BuildResult
// Try to request to download the zip file from the target url, // Try to request to download the zip file from the target url,
// making sure transient errors are handled gracefully and // making sure transient errors are handled gracefully and
// with a different error message than "not found" // with a different error message than "not found"
let response = reqwest::get(release_url).await?; let (res_status, res_body) = unblock(move || {
if !response.status().is_success() { let mut res = ureq::get(release_url).call()?;
if response.status().as_u16() == 404 { let body = res.body_mut().read_to_vec()?;
Ok::<_, BuildError>((res.status(), body))
})
.await?;
if !res_status.is_success() {
if res_status.as_u16() == 404 {
return Err(BuildError::ReleaseTargetNotFound(target)); return Err(BuildError::ReleaseTargetNotFound(target));
} }
return Err(BuildError::Download( return Err(BuildError::Download(ureq::Error::StatusCode(
response.error_for_status().unwrap_err(), res_status.as_u16(),
)); )));
} }
// Receive the full zip file // Start reading the zip file
let zip_bytes = response.bytes().await?.to_vec(); let zip_file = Cursor::new(res_body);
let zip_file = Cursor::new(zip_bytes);
// Look for and extract the binary file from the zip file // Look for and extract the binary file from the zip file
// NOTE: We use spawn_blocking here since reading a zip // NOTE: We use spawn_blocking here since reading a zip
// archive is a somewhat slow / blocking operation // archive is a somewhat slow / blocking operation
let binary_file_name = format!("lune{}", target.exe_suffix()); let binary_file_name = format!("lune{}", target.exe_suffix());
let binary_file_handle = task::spawn_blocking(move || { let binary_file_handle = unblock(move || {
let mut archive = zip::ZipArchive::new(zip_file)?; let mut archive = zip::ZipArchive::new(zip_file)?;
let mut binary = Vec::new(); let mut binary = Vec::new();
@ -73,7 +79,7 @@ pub async fn get_or_download_base_executable(target: BuildTarget) -> BuildResult
Ok::<_, BuildError>(binary) Ok::<_, BuildError>(binary)
}); });
let binary_file_contents = binary_file_handle.await??; let binary_file_contents = binary_file_handle.await?;
// Finally, write the extracted binary to the cache // Finally, write the extracted binary to the cache
if !CACHE_DIR.exists() { if !CACHE_DIR.exists() {

View file

@ -1,7 +1,8 @@
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use anyhow::Result; use anyhow::Result;
use tokio::{fs, io::AsyncWriteExt}; use async_fs as fs;
use futures_lite::prelude::*;
/** /**
Removes the source file extension from the given path, if it has one. Removes the source file extension from the given path, if it has one.
@ -32,6 +33,7 @@ pub async fn write_executable_file_to(
#[cfg(unix)] #[cfg(unix)]
{ {
use fs::unix::OpenOptionsExt;
options.mode(0o755); // Read & execute for all, write for owner options.mode(0o755); // Read & execute for all, write for owner
} }

View file

@ -1,9 +1,9 @@
use std::{path::PathBuf, process::ExitCode}; use std::{path::PathBuf, process::ExitCode};
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
use async_fs as fs;
use clap::Parser; use clap::Parser;
use console::style; use console::style;
use tokio::fs;
use crate::standalone::metadata::Metadata; use crate::standalone::metadata::Metadata;

View file

@ -12,11 +12,9 @@ pub enum BuildError {
#[error("failed to find lune binary '{0}' in downloaded zip file")] #[error("failed to find lune binary '{0}' in downloaded zip file")]
ZippedBinaryNotFound(String), ZippedBinaryNotFound(String),
#[error("failed to download lune binary: {0}")] #[error("failed to download lune binary: {0}")]
Download(#[from] reqwest::Error), Download(#[from] ureq::Error),
#[error("failed to unzip lune binary: {0}")] #[error("failed to unzip lune binary: {0}")]
Unzip(#[from] zip::result::ZipError), Unzip(#[from] zip::result::ZipError),
#[error("panicked while unzipping lune binary: {0}")]
UnzipJoin(#[from] tokio::task::JoinError),
#[error("io error: {0}")] #[error("io error: {0}")]
IoError(#[from] std::io::Error), IoError(#[from] std::io::Error),
} }

View file

@ -1,6 +1,7 @@
use std::{path::PathBuf, process::ExitCode}; use std::{path::PathBuf, process::ExitCode};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use async_fs as fs;
use clap::Parser; use clap::Parser;
use directories::UserDirs; use directories::UserDirs;
use rustyline::{error::ReadlineError, DefaultEditor}; use rustyline::{error::ReadlineError, DefaultEditor};
@ -28,7 +29,7 @@ impl ReplCommand {
.home_dir() .home_dir()
.join(".lune_history"); .join(".lune_history");
if !history_file_path.exists() { if !history_file_path.exists() {
tokio::fs::write(history_file_path, &[]).await?; fs::write(history_file_path, &[]).await?;
} }
let mut repl = DefaultEditor::new()?; let mut repl = DefaultEditor::new()?;

View file

@ -1,11 +1,10 @@
use std::{env, process::ExitCode}; use std::{env, io::stdin, process::ExitCode};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use async_fs::read as read_to_vec;
use blocking::Unblock;
use clap::Parser; use clap::Parser;
use tokio::{ use futures_lite::prelude::*;
fs::read as read_to_vec,
io::{stdin, AsyncReadExt as _},
};
use lune::Runtime; use lune::Runtime;
@ -27,7 +26,7 @@ impl RunCommand {
// (dash) as the script name to run to the cli // (dash) as the script name to run to the cli
let (script_display_name, script_contents) = if &self.script_path == "-" { let (script_display_name, script_contents) = if &self.script_path == "-" {
let mut stdin_contents = Vec::new(); let mut stdin_contents = Vec::new();
stdin() Unblock::new(stdin())
.read_to_end(&mut stdin_contents) .read_to_end(&mut stdin_contents)
.await .await
.context("Failed to read script contents from stdin")?; .context("Failed to read script contents from stdin")?;

View file

@ -1,11 +1,10 @@
use std::{borrow::BorrowMut, env::current_dir, io::ErrorKind, path::PathBuf, process::ExitCode}; use std::{borrow::BorrowMut, env::current_dir, io::ErrorKind, path::PathBuf, process::ExitCode};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use async_fs as fs;
use clap::Parser; use clap::Parser;
use directories::UserDirs; use directories::UserDirs;
use futures_util::future::try_join_all;
use thiserror::Error; use thiserror::Error;
use tokio::fs;
// TODO: Use a library that supports json with comments since VSCode settings may contain comments // TODO: Use a library that supports json with comments since VSCode settings may contain comments
use serde_json::Value as JsonValue; use serde_json::Value as JsonValue;
@ -157,16 +156,12 @@ async fn generate_typedef_files_from_definitions() -> Result<String> {
files_to_write.push((name, path, builtin.typedefs())); files_to_write.push((name, path, builtin.typedefs()));
} }
// Write all dirs and files only when we know generation was successful // Write all dirs and files
let futs_dirs = dirs_to_write for dir in dirs_to_write {
.drain(..) fs::create_dir_all(dir).await?;
.map(fs::create_dir_all) }
.collect::<Vec<_>>(); for (_name, path, contents) in files_to_write {
let futs_files = files_to_write fs::write(path, contents).await?;
.iter() }
.map(|(_, path, contents)| fs::write(path, contents))
.collect::<Vec<_>>();
try_join_all(futs_dirs).await?;
try_join_all(futs_files).await?;
Ok(version_string.to_string()) Ok(version_string.to_string())
} }

View file

@ -1,11 +1,14 @@
#![allow(clippy::match_same_arms)] #![allow(clippy::match_same_arms)]
use std::{cmp::Ordering, ffi::OsStr, fmt::Write as _, path::PathBuf, sync::LazyLock}; use std::{
cmp::Ordering, ffi::OsStr, fmt::Write as _, io::ErrorKind, path::PathBuf, sync::LazyLock,
};
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use async_fs as fs;
use console::Style; use console::Style;
use directories::UserDirs; use directories::UserDirs;
use tokio::{fs, io}; use futures_lite::prelude::*;
use super::files::{discover_script_path, parse_lune_description_from_file}; use super::files::{discover_script_path, parse_lune_description_from_file};
@ -25,7 +28,7 @@ pub async fn find_lune_scripts(in_home_dir: bool) -> Result<Vec<(String, String)
match lune_dir { match lune_dir {
Ok(mut dir) => { Ok(mut dir) => {
let mut files = Vec::new(); let mut files = Vec::new();
while let Some(entry) = dir.next_entry().await? { while let Some(entry) = dir.try_next().await? {
let meta = entry.metadata().await?; let meta = entry.metadata().await?;
if meta.is_file() { if meta.is_file() {
let contents = fs::read(entry.path()).await?; let contents = fs::read(entry.path()).await?;
@ -77,7 +80,7 @@ pub async fn find_lune_scripts(in_home_dir: bool) -> Result<Vec<(String, String)
.collect(); .collect();
Ok(parsed) Ok(parsed)
} }
Err(e) if matches!(e.kind(), io::ErrorKind::NotFound) => { Err(e) if matches!(e.kind(), ErrorKind::NotFound) => {
bail!("No lune directory was found.") bail!("No lune directory was found.")
} }
Err(e) => { Err(e) => {

View file

@ -9,8 +9,7 @@ pub(crate) mod standalone;
use lune_utils::fmt::Label; use lune_utils::fmt::Label;
#[tokio::main(flavor = "multi_thread")] fn main() -> ExitCode {
async fn main() -> ExitCode {
tracing_subscriber::fmt() tracing_subscriber::fmt()
.compact() .compact()
.with_env_filter(tracing_subscriber::filter::EnvFilter::from_default_env()) .with_env_filter(tracing_subscriber::filter::EnvFilter::from_default_env())
@ -20,24 +19,26 @@ async fn main() -> ExitCode {
.with_writer(stderr) .with_writer(stderr)
.init(); .init();
if let Some(bin) = standalone::check().await { async_io::block_on(async {
return standalone::run(bin).await.unwrap(); if let Some(bin) = standalone::check().await {
} return standalone::run(bin).await.unwrap();
}
#[cfg(feature = "cli")] #[cfg(feature = "cli")]
{ {
match cli::Cli::new().run().await { match cli::Cli::new().run().await {
Ok(code) => code, Ok(code) => code,
Err(err) => { Err(err) => {
eprintln!("{}\n{err:?}", Label::Error); eprintln!("{}\n{err:?}", Label::Error);
ExitCode::FAILURE ExitCode::FAILURE
}
} }
} }
}
#[cfg(not(feature = "cli"))] #[cfg(not(feature = "cli"))]
{ {
eprintln!("{}\nCLI feature is disabled", Label::Error); eprintln!("{}\nCLI feature is disabled", Label::Error);
ExitCode::FAILURE ExitCode::FAILURE
} }
})
} }

View file

@ -1,8 +1,8 @@
use std::{env, path::PathBuf, sync::LazyLock}; use std::{env, path::PathBuf, sync::LazyLock};
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use async_fs as fs;
use mlua::Compiler as LuaCompiler; use mlua::Compiler as LuaCompiler;
use tokio::fs;
pub static CURRENT_EXE: LazyLock<PathBuf> = pub static CURRENT_EXE: LazyLock<PathBuf> =
LazyLock::new(|| env::current_exe().expect("failed to get current exe")); LazyLock::new(|| env::current_exe().expect("failed to get current exe"));

View file

@ -3,9 +3,9 @@ use std::path::PathBuf;
use std::process::ExitCode; use std::process::ExitCode;
use anyhow::Result; use anyhow::Result;
use async_fs::read_to_string;
use console::set_colors_enabled; use console::set_colors_enabled;
use console::set_colors_enabled_stderr; use console::set_colors_enabled_stderr;
use tokio::fs::read_to_string;
use lune_utils::path::clean_path_and_make_absolute; use lune_utils::path::clean_path_and_make_absolute;
@ -15,37 +15,39 @@ const ARGS: &[&str] = &["Foo", "Bar"];
macro_rules! create_tests { macro_rules! create_tests {
($($name:ident: $value:expr,)*) => { $( ($($name:ident: $value:expr,)*) => { $(
#[tokio::test(flavor = "multi_thread")] #[test]
async fn $name() -> Result<ExitCode> { fn $name() -> Result<ExitCode> {
// We need to change the current directory to the workspace root since async_io::block_on(async {
// we are in a sub-crate and tests would run relative to the sub-crate // We need to change the current directory to the workspace root since
let workspace_dir_str = format!("{}/../../", env!("CARGO_MANIFEST_DIR")); // we are in a sub-crate and tests would run relative to the sub-crate
let workspace_dir = clean_path_and_make_absolute(PathBuf::from(workspace_dir_str)); let workspace_dir_str = format!("{}/../../", env!("CARGO_MANIFEST_DIR"));
set_current_dir(&workspace_dir)?; let workspace_dir = clean_path_and_make_absolute(PathBuf::from(workspace_dir_str));
set_current_dir(&workspace_dir)?;
// Disable styling for stdout and stderr since // Disable styling for stdout and stderr since
// some tests rely on output not being styled // some tests rely on output not being styled
set_colors_enabled(false); set_colors_enabled(false);
set_colors_enabled_stderr(false); set_colors_enabled_stderr(false);
// The rest of the test logic can continue as normal // The rest of the test logic can continue as normal
let full_name = format!("{}/tests/{}.luau", workspace_dir.display(), $value); let full_name = format!("{}/tests/{}.luau", workspace_dir.display(), $value);
let script = read_to_string(&full_name).await?; let script = read_to_string(&full_name).await?;
let mut lune = Runtime::new()? let mut lune = Runtime::new()?
.with_jit(true) .with_jit(true)
.with_args( .with_args(
ARGS ARGS
.clone() .clone()
.iter() .iter()
.map(ToString::to_string) .map(ToString::to_string)
.collect::<Vec<_>>() .collect::<Vec<_>>()
); );
let script_name = full_name let script_name = full_name
.trim_end_matches(".luau") .trim_end_matches(".luau")
.trim_end_matches(".lua") .trim_end_matches(".lua")
.to_string(); .to_string();
let script_values = lune.run(&script_name, &script).await?; let script_values = lune.run(&script_name, &script).await?;
Ok(ExitCode::from(script_values.status())) Ok(ExitCode::from(script_values.status()))
})
} }
)* } )* }
} }