feat(sdk,core): Use async runtime instead of blocking.

Default to using async runtime instead of blocking. I.e.

```rust
fn main() -> eyre::Result<()> {
  // ...

  client.container().from("rust").publish("somewhere")?;

  // ...
}

// to

async fn main() -> eyre::Result<()> {
  // ...

  client.container().from("rust").publish("somewhere").await?;

  // ...
}
```
This commit is contained in:
Kasper Juul Hermansen 2023-02-19 21:37:54 +01:00 committed by Kasper Juul Hermansen
parent c35c104b49
commit 9be6f435d9
12 changed files with 778 additions and 395 deletions

View File

@ -10,6 +10,8 @@ use crate::functions::{
}; };
use crate::utility::OptionExt; use crate::utility::OptionExt;
use super::templates::object_tmpl::render_optional_field_args;
pub fn format_name(s: &str) -> String { pub fn format_name(s: &str) -> String {
s.to_case(Case::Pascal) s.to_case(Case::Pascal)
} }
@ -29,10 +31,33 @@ pub fn field_options_struct_name(field: &FullTypeFields) -> Option<String> {
} }
pub fn format_function(funcs: &CommonFunctions, field: &FullTypeFields) -> Option<rust::Tokens> { pub fn format_function(funcs: &CommonFunctions, field: &FullTypeFields) -> Option<rust::Tokens> {
let signature = quote! { let is_async = field.type_.pipe(|t| &t.type_ref).pipe(|t| {
pub fn $(field.name.pipe(|n | format_struct_name(n))) if type_ref_is_object(&t) || type_ref_is_list_of_objects(&t) {
return None;
} else {
return Some(quote! {
async
});
}; };
let args = format_function_args(funcs, field); });
let signature = quote! {
pub $(is_async) fn $(field.name.pipe(|n | format_struct_name(n)))
};
let lifecycle = format_optional_args(funcs, field)
.pipe(|(_, contains_lifecycle)| contains_lifecycle)
.and_then(|c| {
if *c {
Some(quote! {
<'a>
})
} else {
None
}
});
let args = format_function_args(funcs, field, lifecycle.as_ref());
let output_type = field let output_type = field
.type_ .type_
@ -52,7 +77,7 @@ pub fn format_function(funcs: &CommonFunctions, field: &FullTypeFields) -> Optio
$(render_execution(funcs, field)) $(render_execution(funcs, field))
} }
$(&signature)_opts( $(&signature)_opts$(lifecycle)(
$args $args
) -> $(output_type) { ) -> $(output_type) {
let mut query = self.selection.select($(quoted(field.name.as_ref()))); let mut query = self.selection.select($(quoted(field.name.as_ref())));
@ -235,13 +260,14 @@ fn render_execution(funcs: &CommonFunctions, field: &FullTypeFields) -> rust::To
let graphql_client = rust::import("crate::client", "graphql_client"); let graphql_client = rust::import("crate::client", "graphql_client");
quote! { quote! {
query.execute(&$graphql_client(&self.conn)) query.execute(&$graphql_client(&self.conn)).await
} }
} }
fn format_function_args( fn format_function_args(
funcs: &CommonFunctions, funcs: &CommonFunctions,
field: &FullTypeFields, field: &FullTypeFields,
lifecycle: Option<&rust::Tokens>,
) -> Option<(rust::Tokens, bool)> { ) -> Option<(rust::Tokens, bool)> {
if let Some(args) = field.args.as_ref() { if let Some(args) = field.args.as_ref() {
let args = args let args = args
@ -271,7 +297,7 @@ fn format_function_args(
Some(( Some((
quote! { quote! {
$(required_args) $(required_args)
opts: $(field_options_struct_name(field)) opts: $(field_options_struct_name(field))$(lifecycle)
}, },
true, true,
)) ))
@ -316,3 +342,19 @@ fn format_required_function_args(
None None
} }
} }
pub fn format_optional_args(
funcs: &CommonFunctions,
field: &FullTypeFields,
) -> Option<(rust::Tokens, bool)> {
field
.args
.pipe(|t| t.into_iter().flatten().collect::<Vec<_>>())
.map(|t| {
t.into_iter()
.filter(|t| type_ref_is_optional(&t.input_value.type_))
.collect::<Vec<_>>()
})
.pipe(|t| render_optional_field_args(funcs, t))
.flatten()
}

View File

@ -5,7 +5,8 @@ use itertools::Itertools;
use crate::functions::{type_ref_is_optional, CommonFunctions}; use crate::functions::{type_ref_is_optional, CommonFunctions};
use crate::rust::functions::{ use crate::rust::functions::{
field_options_struct_name, format_function, format_name, format_struct_name, field_options_struct_name, format_function, format_name, format_optional_args,
format_struct_name,
}; };
use crate::utility::OptionExt; use crate::utility::OptionExt;
@ -51,16 +52,7 @@ fn render_optional_args(
fn render_optional_arg(funcs: &CommonFunctions, field: &FullTypeFields) -> Option<rust::Tokens> { fn render_optional_arg(funcs: &CommonFunctions, field: &FullTypeFields) -> Option<rust::Tokens> {
let output_type = field_options_struct_name(field); let output_type = field_options_struct_name(field);
let fields = field let fields = format_optional_args(funcs, field);
.args
.pipe(|t| t.into_iter().flatten().collect::<Vec<_>>())
.map(|t| {
t.into_iter()
.filter(|t| type_ref_is_optional(&t.input_value.type_))
.collect::<Vec<_>>()
})
.pipe(|t| render_optional_field_args(funcs, t))
.flatten();
let builder = rust::import("derive_builder", "Builder"); let builder = rust::import("derive_builder", "Builder");
let _phantom_data = rust::import("std::marker", "PhantomData"); let _phantom_data = rust::import("std::marker", "PhantomData");
@ -79,7 +71,7 @@ fn render_optional_arg(funcs: &CommonFunctions, field: &FullTypeFields) -> Optio
} }
} }
fn render_optional_field_args( pub fn render_optional_field_args(
funcs: &CommonFunctions, funcs: &CommonFunctions,
args: &Vec<&FullTypeFieldsArgs>, args: &Vec<&FullTypeFieldsArgs>,
) -> Option<(rust::Tokens, bool)> { ) -> Option<(rust::Tokens, bool)> {

View File

@ -1,6 +1,7 @@
use dagger_sdk::HostDirectoryOpts; use dagger_sdk::HostDirectoryOpts;
fn main() -> eyre::Result<()> { #[tokio::main]
async fn main() -> eyre::Result<()> {
let client = dagger_sdk::connect()?; let client = dagger_sdk::connect()?;
let host_source_dir = client.host().directory_opts( let host_source_dir = client.host().directory_opts(
@ -14,7 +15,7 @@ fn main() -> eyre::Result<()> {
let source = client let source = client
.container() .container()
.from("node:16") .from("node:16")
.with_mounted_directory("/src", host_source_dir.id()?); .with_mounted_directory("/src", host_source_dir.id().await?);
let runner = source let runner = source
.with_workdir("/src") .with_workdir("/src")
@ -28,7 +29,7 @@ fn main() -> eyre::Result<()> {
let _ = build_dir.export("./build"); let _ = build_dir.export("./build");
let entries = build_dir.entries(); let entries = build_dir.entries().await;
println!("build dir contents: \n {:?}", entries); println!("build dir contents: \n {:?}", entries);

View File

@ -1,6 +1,7 @@
use rand::Rng; use rand::Rng;
fn main() -> eyre::Result<()> { #[tokio::main]
async fn main() -> eyre::Result<()> {
let client = dagger_sdk::connect()?; let client = dagger_sdk::connect()?;
let host_source_dir = client.host().directory_opts( let host_source_dir = client.host().directory_opts(
@ -10,12 +11,12 @@ fn main() -> eyre::Result<()> {
.build()?, .build()?,
); );
let node_cache = client.cache_volume("node").id()?; let node_cache = client.cache_volume("node").id().await?;
let source = client let source = client
.container() .container()
.from("node:16") .from("node:16")
.with_mounted_directory("/src", host_source_dir.id()?) .with_mounted_directory("/src", host_source_dir.id().await?)
.with_mounted_cache("/src/node_modules", node_cache); .with_mounted_cache("/src/node_modules", node_cache);
let runner = source let runner = source
@ -33,8 +34,8 @@ fn main() -> eyre::Result<()> {
let ref_ = client let ref_ = client
.container() .container()
.from("nginx") .from("nginx")
.with_directory("/usr/share/nginx/html", build_dir.id()?) .with_directory("/usr/share/nginx/html", build_dir.id().await?)
.publish(format!("ttl.sh/hello-dagger-rs-{}:1h", rng.gen::<u64>()))?; .publish(format!("ttl.sh/hello-dagger-rs-{}:1h", rng.gen::<u64>())).await?;
println!("published image to: {}", ref_); println!("published image to: {}", ref_);

View File

@ -1,6 +1,7 @@
use rand::Rng; use rand::Rng;
fn main() -> eyre::Result<()> { #[tokio::main]
async fn main() -> eyre::Result<()> {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let client = dagger_sdk::connect()?; let client = dagger_sdk::connect()?;
@ -11,8 +12,8 @@ fn main() -> eyre::Result<()> {
let ref_ = client let ref_ = client
.container() .container()
.build(context_dir.id()?) .build(context_dir.id().await?)
.publish(format!("ttl.sh/hello-dagger-rs-{}:1h", rng.gen::<u64>()))?; .publish(format!("ttl.sh/hello-dagger-rs-{}:1h", rng.gen::<u64>())).await?;
println!("published image to: {}", ref_); println!("published image to: {}", ref_);

View File

@ -1,11 +1,12 @@
fn main() -> eyre::Result<()> { #[tokio::main]
async fn main() -> eyre::Result<()> {
let client = dagger_sdk::connect()?; let client = dagger_sdk::connect()?;
let version = client let version = client
.container() .container()
.from("golang:1.19") .from("golang:1.19")
.with_exec(vec!["go", "version".into()]) .with_exec(vec!["go", "version"])
.stdout()?; .stdout().await?;
println!("Hello from Dagger and {}", version.trim()); println!("Hello from Dagger and {}", version.trim());

View File

@ -1,7 +1,8 @@
use dagger_sdk::HostDirectoryOpts; use dagger_sdk::HostDirectoryOpts;
use rand::Rng; use rand::Rng;
fn main() -> eyre::Result<()> { #[tokio::main]
async fn main() -> eyre::Result<()> {
let client = dagger_sdk::connect()?; let client = dagger_sdk::connect()?;
let host_source_dir = client.host().directory_opts( let host_source_dir = client.host().directory_opts(
@ -15,7 +16,7 @@ fn main() -> eyre::Result<()> {
let source = client let source = client
.container() .container()
.from("node:16") .from("node:16")
.with_mounted_directory("/src", host_source_dir.id()?); .with_mounted_directory("/src", host_source_dir.id().await?);
let runner = source let runner = source
.with_workdir("/src") .with_workdir("/src")
@ -32,8 +33,9 @@ fn main() -> eyre::Result<()> {
let ref_ = client let ref_ = client
.container() .container()
.from("nginx") .from("nginx")
.with_directory("/usr/share/nginx/html", build_dir.id()?) .with_directory("/usr/share/nginx/html", build_dir.id().await?)
.publish(format!("ttl.sh/hello-dagger-rs-{}:1h", rng.gen::<u64>()))?; .publish(format!("ttl.sh/hello-dagger-rs-{}:1h", rng.gen::<u64>()))
.await?;
println!("published image to: {}", ref_); println!("published image to: {}", ref_);

View File

@ -1,7 +1,8 @@
use dagger_sdk::HostDirectoryOpts; use dagger_sdk::HostDirectoryOpts;
use rand::Rng; use rand::Rng;
fn main() -> eyre::Result<()> { #[tokio::main]
async fn main() -> eyre::Result<()> {
let client = dagger_sdk::connect()?; let client = dagger_sdk::connect()?;
let output = "examples/publish-the-application/app/build"; let output = "examples/publish-the-application/app/build";
@ -16,7 +17,7 @@ fn main() -> eyre::Result<()> {
let source = client let source = client
.container() .container()
.from("node:16") .from("node:16")
.with_mounted_directory("/src", host_source_dir.id()?); .with_mounted_directory("/src", host_source_dir.id().await?);
let runner = source let runner = source
.with_workdir("/src") .with_workdir("/src")
@ -36,9 +37,9 @@ fn main() -> eyre::Result<()> {
.from("nginx") .from("nginx")
.with_directory( .with_directory(
"/usr/share/nginx/html", "/usr/share/nginx/html",
client.host().directory(output).id()?, client.host().directory(output).id().await?,
) )
.publish(format!("ttl.sh/hello-dagger-rs-{}:1h", rng.gen::<u64>()))?; .publish(format!("ttl.sh/hello-dagger-rs-{}:1h", rng.gen::<u64>())).await?;
println!("published image to: {}", ref_); println!("published image to: {}", ref_);

View File

@ -1,6 +1,7 @@
use dagger_sdk::HostDirectoryOpts; use dagger_sdk::HostDirectoryOpts;
fn main() -> eyre::Result<()> { #[tokio::main]
async fn main() -> eyre::Result<()> {
let client = dagger_sdk::connect()?; let client = dagger_sdk::connect()?;
let host_source_dir = client.host().directory_opts( let host_source_dir = client.host().directory_opts(
@ -14,7 +15,7 @@ fn main() -> eyre::Result<()> {
let source = client let source = client
.container() .container()
.from("node:16") .from("node:16")
.with_mounted_directory("/src", host_source_dir.id()?); .with_mounted_directory("/src", host_source_dir.id().await?);
let runner = source let runner = source
.with_workdir("/src") .with_workdir("/src")
@ -22,7 +23,7 @@ fn main() -> eyre::Result<()> {
let out = runner let out = runner
.with_exec(vec!["npm", "test", "--", "--watchAll=false"]) .with_exec(vec!["npm", "test", "--", "--watchAll=false"])
.stderr()?; .stderr().await?;
println!("{}", out); println!("{}", out);

File diff suppressed because it is too large Load Diff

View File

@ -93,18 +93,13 @@ impl Selection {
Ok(fields.join("{") + &"}".repeat(fields.len() - 1)) Ok(fields.join("{") + &"}".repeat(fields.len() - 1))
} }
pub fn execute<D>(&self, gql_client: &gql_client::Client) -> eyre::Result<D> pub async fn execute<D>(&self, gql_client: &gql_client::Client) -> eyre::Result<D>
where where
D: for<'de> Deserialize<'de>, D: for<'de> Deserialize<'de>,
{ {
let query = self.build()?; let query = self.build()?;
let basic = tokio::runtime::Builder::new_current_thread() let resp: Option<serde_json::Value> = match gql_client.query(&query).await {
.enable_all()
.build()
.unwrap();
let resp: Option<serde_json::Value> = match basic.block_on(gql_client.query(&query)) {
Ok(r) => r, Ok(r) => r,
Err(e) => eyre::bail!(e), Err(e) => eyre::bail!(e),
}; };

View File

@ -1,7 +1,7 @@
use dagger_sdk::{connect, ContainerExecOptsBuilder}; use dagger_sdk::{connect, ContainerExecOptsBuilder};
#[test] #[tokio::test]
fn test_example_container() { async fn test_example_container() {
let client = connect().unwrap(); let client = connect().unwrap();
let alpine = client.container().from("alpine:3.16.2"); let alpine = client.container().from("alpine:3.16.2");
@ -14,6 +14,7 @@ fn test_example_container() {
.unwrap(), .unwrap(),
) )
.stdout() .stdout()
.await
.unwrap(); .unwrap();
assert_eq!(out, "3.16.2\n".to_string()) assert_eq!(out, "3.16.2\n".to_string())