Compare commits

...

6 Commits

Author SHA1 Message Date
107d3ca0bf 🚀 chore(README.md): check off introducing thiserror for better errors in plan for next release
The plan for the next release has been updated to reflect that the [thiserror](https://docs.rs/thiserror/latest/thiserror/) library has been introduced to improve error handling.
2023-04-30 13:12:23 +02:00
3a9abb97c2 Add thiserror instead of exposing eyre anonymous errors
The change here is to make it easier for the consumer to debug the api.
Such that they can `match` on individual errors instead of having to
parse text.

eyre is convenient, but mostly from a consumers perspective
2023-04-30 13:12:23 +02:00
66ab2f552c
🚀 chore(Cargo.toml): add thiserror crate to dependencies
The thiserror crate has been added to the dependencies in the Cargo.toml file. This crate is used to derive custom error types with automatic source location.
2023-04-30 11:41:12 +02:00
b72920e235
chore(README.md): mark dagger run compatibility and upstream update tasks as completed 2023-04-30 11:39:08 +02:00
c8bdf42e86
refactor(dagger-codegen): remove unnecessary mutability from field variable in for loop 2023-04-30 11:37:55 +02:00
40ece05140
Release dagger-core v0.2.11, dagger-sdk v0.2.22 2023-04-30 10:56:53 +02:00
18 changed files with 228 additions and 83 deletions

6
Cargo.lock generated
View File

@ -317,7 +317,7 @@ dependencies = [
[[package]]
name = "dagger-core"
version = "0.2.10"
version = "0.2.11"
dependencies = [
"async-trait",
"base64",
@ -334,6 +334,7 @@ dependencies = [
"sha2",
"tar",
"tempfile",
"thiserror",
"tokio",
"tracing",
"tracing-subscriber",
@ -341,7 +342,7 @@ dependencies = [
[[package]]
name = "dagger-sdk"
version = "0.2.21"
version = "0.2.22"
dependencies = [
"dagger-core",
"derive_builder",
@ -352,6 +353,7 @@ dependencies = [
"rand",
"serde",
"serde_json",
"thiserror",
"tokio",
"tracing",
"tracing-subscriber",

View File

@ -23,3 +23,4 @@ tracing-subscriber = { version = "0.3.16", features = [
"tracing-log",
"tracing",
] }
thiserror = "1.0.40"

View File

@ -4,14 +4,14 @@ A dagger sdk written in rust for rust.
## Plan for next release
- [ ] Introduce [thiserror](https://docs.rs/thiserror/latest/thiserror/) for
- [x] Introduce [thiserror](https://docs.rs/thiserror/latest/thiserror/) for
better errors
- [ ] Add compatibility with `dagger run`
- [x] Add compatibility with `dagger run`
- [ ] Add open telemetry tracing to the sdk
- [ ] Remove `id().await?` from passing to other dagger graphs, this should make
the design much cleaner
- [ ] Start MkBook on how to actually use the sdk
- [ ] Update to newest upstream release
- [x] Update to newest upstream release
- [ ] Fix bugs
- [x] Run in conjunction with golang and other sdks
- [ ] Stabilize the initial `Arc<Query>` model into something more extensible

View File

@ -8,6 +8,6 @@ edition = "2021"
[dependencies]
clap = "4.1.6"
color-eyre = "0.6.2"
dagger-sdk = { path = "../crates/dagger-sdk/", version = "^0.2.21" }
dagger-sdk = { path = "../crates/dagger-sdk/", version = "^0.2.22" }
eyre = "0.6.8"
tokio = { version = "1.25.0", features = ["full"] }

View File

@ -13,7 +13,7 @@ use self::generator::DynGenerator;
fn set_schema_parents(mut schema: Schema) -> Schema {
for t in schema.types.as_mut().into_iter().flatten().flatten() {
let t_parent = t.full_type.clone();
for mut field in t.full_type.fields.as_mut().into_iter().flatten() {
for field in t.full_type.fields.as_mut().into_iter().flatten() {
field.parent_type = Some(t_parent.clone());
}
}

View File

@ -235,8 +235,10 @@ fn render_output_type(funcs: &CommonFunctions, type_ref: &TypeRef) -> rust::Toke
};
}
let dagger_error = rust::import("crate::errors", "DaggerError");
quote! {
eyre::Result<$output_type>
Result<$output_type, $dagger_error>
}
}

View File

@ -5,6 +5,33 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## v0.2.11 (2023-04-29)
### New Features
- <csr-id-2a29a66217fa4d6c530ea1ce670c8836383e7051/> dagger-run support
- <csr-id-eb7470c604169d1a15976078c0889d5cc7011257/> update to dagger-5.1
### Commit Statistics
<csr-read-only-do-not-edit/>
- 2 commits contributed to the release.
- 4 days passed between releases.
- 2 commits were understood as [conventional](https://www.conventionalcommits.org).
- 0 issues like '(#ID)' were seen in commit messages
### Commit Details
<csr-read-only-do-not-edit/>
<details><summary>view details</summary>
* **Uncategorized**
- dagger-run support ([`2a29a66`](https://github.com/kjuulh/dagger-sdk/commit/2a29a66217fa4d6c530ea1ce670c8836383e7051))
- update to dagger-5.1 ([`eb7470c`](https://github.com/kjuulh/dagger-sdk/commit/eb7470c604169d1a15976078c0889d5cc7011257))
</details>
## v0.2.10 (2023-04-25)
### Bug Fixes
@ -15,7 +42,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
<csr-read-only-do-not-edit/>
- 1 commit contributed to the release.
- 2 commits contributed to the release.
- 21 days passed between releases.
- 1 commit was understood as [conventional](https://www.conventionalcommits.org).
- 0 issues like '(#ID)' were seen in commit messages
@ -27,6 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
<details><summary>view details</summary>
* **Uncategorized**
- Release dagger-core v0.2.10 ([`8011c42`](https://github.com/kjuulh/dagger-sdk/commit/8011c42dc077d101b1bccaf231fac17636dd249d))
- delete other files/folder in downloads: #57 ([`9d3c21d`](https://github.com/kjuulh/dagger-sdk/commit/9d3c21d16b4a64eb7a7b1888365a4c4ea56d7225))
</details>

View File

@ -1,6 +1,6 @@
[package]
name = "dagger-core"
version = "0.2.10"
version = "0.2.11"
edition = "2021"
readme = "README.md"
license-file = "LICENSE.MIT"
@ -16,6 +16,7 @@ serde_json = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
thiserror.workspace = true
base64 = "0.21.0"
dirs = "4.0.0"

View File

@ -15,7 +15,7 @@ pub struct GraphQLError {
#[derive(Deserialize, Debug, Clone)]
#[allow(dead_code)]
pub struct GraphQLErrorMessage {
message: String,
pub message: String,
locations: Option<Vec<GraphQLErrorLocation>>,
extensions: Option<HashMap<String, String>>,
path: Option<Vec<GraphQLErrorPathParam>>,

View File

@ -4,13 +4,14 @@ use std::sync::Arc;
use async_trait::async_trait;
use base64::engine::general_purpose;
use base64::Engine;
use thiserror::Error;
use crate::connect_params::ConnectParams;
use crate::gql_client::{ClientConfig, GQLClient};
#[async_trait]
pub trait GraphQLClient {
async fn query(&self, query: &str) -> eyre::Result<Option<serde_json::Value>>;
async fn query(&self, query: &str) -> Result<Option<serde_json::Value>, GraphQLError>;
}
pub type DynGraphQLClient = Arc<dyn GraphQLClient + Send + Sync>;
@ -40,13 +41,50 @@ impl DefaultGraphQLClient {
#[async_trait]
impl GraphQLClient for DefaultGraphQLClient {
async fn query(&self, query: &str) -> eyre::Result<Option<serde_json::Value>> {
let res: Option<serde_json::Value> = self
.client
.query(&query)
.await
.map_err(|r| eyre::anyhow!(r.to_string()))?;
async fn query(&self, query: &str) -> Result<Option<serde_json::Value>, GraphQLError> {
let res: Option<serde_json::Value> =
self.client.query(&query).await.map_err(map_graphql_error)?;
return Ok(res);
}
}
fn map_graphql_error(gql_error: crate::gql_client::GraphQLError) -> GraphQLError {
let message = gql_error.message().to_string();
let json = gql_error.json();
if let Some(json) = json {
if !json.is_empty() {
return GraphQLError::DomainError {
message,
fields: GraphqlErrorMessages(json.into_iter().map(|e| e.message).collect()),
};
}
}
GraphQLError::HttpError(message)
}
#[derive(Error, Debug)]
pub enum GraphQLError {
#[error("http error: {0}")]
HttpError(String),
#[error("domain error:\n{message}\n{fields}")]
DomainError {
message: String,
fields: GraphqlErrorMessages,
},
}
#[derive(Debug, Clone)]
pub struct GraphqlErrorMessages(Vec<String>);
impl std::fmt::Display for GraphqlErrorMessages {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for error in self.0.iter() {
f.write_fmt(format_args!("{error}\n"))?;
}
Ok(())
}
}

View File

@ -6,8 +6,37 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## v0.2.22 (2023-04-29)
### New Features
- <csr-id-2a29a66217fa4d6c530ea1ce670c8836383e7051/> dagger-run support
- <csr-id-eb7470c604169d1a15976078c0889d5cc7011257/> update to dagger-5.1
### Commit Statistics
<csr-read-only-do-not-edit/>
- 2 commits contributed to the release.
- 4 days passed between releases.
- 2 commits were understood as [conventional](https://www.conventionalcommits.org).
- 0 issues like '(#ID)' were seen in commit messages
### Commit Details
<csr-read-only-do-not-edit/>
<details><summary>view details</summary>
* **Uncategorized**
- dagger-run support ([`2a29a66`](https://github.com/kjuulh/dagger-sdk/commit/2a29a66217fa4d6c530ea1ce670c8836383e7051))
- update to dagger-5.1 ([`eb7470c`](https://github.com/kjuulh/dagger-sdk/commit/eb7470c604169d1a15976078c0889d5cc7011257))
</details>
## v0.2.21 (2023-04-25)
<csr-id-09881ee39bdfb9201d104e4679a51c3b76b5fe27/>
### Chore
- <csr-id-09881ee39bdfb9201d104e4679a51c3b76b5fe27/> add new dagger-core-version
@ -16,7 +45,7 @@ and this project adheres to
<csr-read-only-do-not-edit/>
- 1 commit contributed to the release.
- 2 commits contributed to the release.
- 21 days passed between releases.
- 1 commit was understood as [conventional](https://www.conventionalcommits.org).
- 0 issues like '(#ID)' were seen in commit messages
@ -28,6 +57,7 @@ and this project adheres to
<details><summary>view details</summary>
* **Uncategorized**
- Release dagger-sdk v0.2.21 ([`6937ef0`](https://github.com/kjuulh/dagger-sdk/commit/6937ef0ace797315013513aa7e2af39a9206a738))
- add new dagger-core-version ([`09881ee`](https://github.com/kjuulh/dagger-sdk/commit/09881ee39bdfb9201d104e4679a51c3b76b5fe27))
</details>

View File

@ -1,6 +1,6 @@
[package]
name = "dagger-sdk"
version = "0.2.21"
version = "0.2.22"
edition = "2021"
readme = "README.md"
license-file = "LICENSE.MIT"
@ -11,7 +11,7 @@ publish = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
dagger-core = { workspace = true, version = "0.2.10" }
dagger-core = { workspace = true, version = "^0.2.11" }
eyre = { workspace = true }
tokio = { workspace = true }
@ -19,6 +19,7 @@ serde = { workspace = true }
serde_json = { workspace = true }
tracing.workspace = true
tracing-subscriber.workspace = true
thiserror.workspace = true
futures = "0.3.28"
derive_builder = "0.12.0"

View File

@ -5,20 +5,24 @@ use dagger_core::graphql_client::DefaultGraphQLClient;
use dagger_core::config::Config;
use dagger_core::engine::Engine as DaggerEngine;
use crate::errors::ConnectError;
use crate::gen::Query;
use crate::logging::StdLogger;
use crate::querybuilder::query;
pub type DaggerConn = Arc<Query>;
pub async fn connect() -> eyre::Result<DaggerConn> {
pub async fn connect() -> Result<DaggerConn, ConnectError> {
let cfg = Config::new(None, None, None, None, Some(Arc::new(StdLogger::default())));
connect_opts(cfg).await
}
pub async fn connect_opts(cfg: Config) -> eyre::Result<DaggerConn> {
let (conn, proc) = DaggerEngine::new().start(&cfg).await?;
pub async fn connect_opts(cfg: Config) -> Result<DaggerConn, ConnectError> {
let (conn, proc) = DaggerEngine::new()
.start(&cfg)
.await
.map_err(ConnectError::FailedToConnect)?;
Ok(Arc::new(Query {
proc: proc.map(|p| Arc::new(p)),

View File

@ -0,0 +1,27 @@
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ConnectError {
#[error("failed to connect to dagger engine")]
FailedToConnect(#[source] eyre::Error),
}
#[derive(Error, Debug)]
pub enum DaggerError {
#[error("failed to build dagger internal graph")]
Build(#[source] eyre::Error),
#[error("failed to parse input type")]
Serialize(#[source] eyre::Error),
#[error("failed to query dagger engine: {0}")]
Query(#[source] dagger_core::graphql_client::GraphQLError),
#[error("failed to unpack response")]
Unpack(#[source] DaggerUnpackError),
}
#[derive(Error, Debug)]
pub enum DaggerUnpackError {
#[error("Too many nested objects inside graphql response")]
TooManyNestedObjects,
#[error("failed to deserialize response")]
Deserialize(#[source] serde_json::Error),
}

View File

@ -1,3 +1,4 @@
use crate::errors::DaggerError;
use crate::querybuilder::Selection;
use dagger_core::graphql_client::DynGraphQLClient;
use derive_builder::Builder;
@ -121,7 +122,7 @@ pub struct CacheVolume {
}
impl CacheVolume {
pub async fn id(&self) -> eyre::Result<CacheId> {
pub async fn id(&self) -> Result<CacheId, DaggerError> {
let query = self.selection.select("id");
query.execute(self.graphql_client.clone()).await
@ -397,7 +398,7 @@ impl Container {
};
}
/// Retrieves default arguments for future commands.
pub async fn default_args(&self) -> eyre::Result<Vec<String>> {
pub async fn default_args(&self) -> Result<Vec<String>, DaggerError> {
let query = self.selection.select("defaultArgs");
query.execute(self.graphql_client.clone()).await
@ -427,7 +428,7 @@ impl Container {
/// # Arguments
///
/// * `opt` - optional argument, see inner type for documentation, use <func>_opts to use
pub async fn endpoint(&self) -> eyre::Result<String> {
pub async fn endpoint(&self) -> Result<String, DaggerError> {
let query = self.selection.select("endpoint");
query.execute(self.graphql_client.clone()).await
@ -441,7 +442,10 @@ impl Container {
/// # Arguments
///
/// * `opt` - optional argument, see inner type for documentation, use <func>_opts to use
pub async fn endpoint_opts<'a>(&self, opts: ContainerEndpointOpts<'a>) -> eyre::Result<String> {
pub async fn endpoint_opts<'a>(
&self,
opts: ContainerEndpointOpts<'a>,
) -> Result<String, DaggerError> {
let mut query = self.selection.select("endpoint");
if let Some(port) = opts.port {
@ -454,7 +458,7 @@ impl Container {
query.execute(self.graphql_client.clone()).await
}
/// Retrieves entrypoint to be prepended to the arguments of all commands.
pub async fn entrypoint(&self) -> eyre::Result<Vec<String>> {
pub async fn entrypoint(&self) -> Result<Vec<String>, DaggerError> {
let query = self.selection.select("entrypoint");
query.execute(self.graphql_client.clone()).await
@ -464,7 +468,7 @@ impl Container {
/// # Arguments
///
/// * `name` - The name of the environment variable to retrieve (e.g., "PATH").
pub async fn env_variable(&self, name: impl Into<String>) -> eyre::Result<String> {
pub async fn env_variable(&self, name: impl Into<String>) -> Result<String, DaggerError> {
let mut query = self.selection.select("envVariable");
query = query.arg("name", name.into());
@ -531,7 +535,7 @@ impl Container {
}
/// Exit code of the last executed command. Zero means success.
/// Will execute default command if none is set, or error if there's no default.
pub async fn exit_code(&self) -> eyre::Result<isize> {
pub async fn exit_code(&self) -> Result<isize, DaggerError> {
let query = self.selection.select("exitCode");
query.execute(self.graphql_client.clone()).await
@ -545,7 +549,7 @@ impl Container {
/// * `path` - Host's destination path (e.g., "./tarball").
/// Path can be relative to the engine's workdir or absolute.
/// * `opt` - optional argument, see inner type for documentation, use <func>_opts to use
pub async fn export(&self, path: impl Into<String>) -> eyre::Result<bool> {
pub async fn export(&self, path: impl Into<String>) -> Result<bool, DaggerError> {
let mut query = self.selection.select("export");
query = query.arg("path", path.into());
@ -566,7 +570,7 @@ impl Container {
&self,
path: impl Into<String>,
opts: ContainerExportOpts,
) -> eyre::Result<bool> {
) -> Result<bool, DaggerError> {
let mut query = self.selection.select("export");
query = query.arg("path", path.into());
@ -634,19 +638,19 @@ impl Container {
}
/// Retrieves a hostname which can be used by clients to reach this container.
/// Currently experimental; set _EXPERIMENTAL_DAGGER_SERVICES_DNS=0 to disable.
pub async fn hostname(&self) -> eyre::Result<String> {
pub async fn hostname(&self) -> Result<String, DaggerError> {
let query = self.selection.select("hostname");
query.execute(self.graphql_client.clone()).await
}
/// A unique identifier for this container.
pub async fn id(&self) -> eyre::Result<ContainerId> {
pub async fn id(&self) -> Result<ContainerId, DaggerError> {
let query = self.selection.select("id");
query.execute(self.graphql_client.clone()).await
}
/// The unique image reference which can only be retrieved immediately after the 'Container.From' call.
pub async fn image_ref(&self) -> eyre::Result<String> {
pub async fn image_ref(&self) -> Result<String, DaggerError> {
let query = self.selection.select("imageRef");
query.execute(self.graphql_client.clone()).await
@ -694,7 +698,7 @@ impl Container {
};
}
/// Retrieves the value of the specified label.
pub async fn label(&self, name: impl Into<String>) -> eyre::Result<String> {
pub async fn label(&self, name: impl Into<String>) -> Result<String, DaggerError> {
let mut query = self.selection.select("label");
query = query.arg("name", name.into());
@ -712,7 +716,7 @@ impl Container {
}];
}
/// Retrieves the list of paths where a directory is mounted.
pub async fn mounts(&self) -> eyre::Result<Vec<String>> {
pub async fn mounts(&self) -> Result<Vec<String>, DaggerError> {
let query = self.selection.select("mounts");
query.execute(self.graphql_client.clone()).await
@ -763,7 +767,7 @@ impl Container {
};
}
/// The platform this container executes and publishes as.
pub async fn platform(&self) -> eyre::Result<Platform> {
pub async fn platform(&self) -> Result<Platform, DaggerError> {
let query = self.selection.select("platform");
query.execute(self.graphql_client.clone()).await
@ -778,7 +782,7 @@ impl Container {
///
/// Formatted as [host]/[user]/[repo]:[tag] (e.g. "docker.io/dagger/dagger:main").
/// * `opt` - optional argument, see inner type for documentation, use <func>_opts to use
pub async fn publish(&self, address: impl Into<String>) -> eyre::Result<String> {
pub async fn publish(&self, address: impl Into<String>) -> Result<String, DaggerError> {
let mut query = self.selection.select("publish");
query = query.arg("address", address.into());
@ -800,7 +804,7 @@ impl Container {
&self,
address: impl Into<String>,
opts: ContainerPublishOpts,
) -> eyre::Result<String> {
) -> Result<String, DaggerError> {
let mut query = self.selection.select("publish");
query = query.arg("address", address.into());
@ -822,20 +826,20 @@ impl Container {
}
/// The error stream of the last executed command.
/// Will execute default command if none is set, or error if there's no default.
pub async fn stderr(&self) -> eyre::Result<String> {
pub async fn stderr(&self) -> Result<String, DaggerError> {
let query = self.selection.select("stderr");
query.execute(self.graphql_client.clone()).await
}
/// The output stream of the last executed command.
/// Will execute default command if none is set, or error if there's no default.
pub async fn stdout(&self) -> eyre::Result<String> {
pub async fn stdout(&self) -> Result<String, DaggerError> {
let query = self.selection.select("stdout");
query.execute(self.graphql_client.clone()).await
}
/// Retrieves the user to be set for all commands.
pub async fn user(&self) -> eyre::Result<String> {
pub async fn user(&self) -> Result<String, DaggerError> {
let query = self.selection.select("user");
query.execute(self.graphql_client.clone()).await
@ -1720,7 +1724,7 @@ impl Container {
};
}
/// Retrieves the working directory for all commands.
pub async fn workdir(&self) -> eyre::Result<String> {
pub async fn workdir(&self) -> Result<String, DaggerError> {
let query = self.selection.select("workdir");
query.execute(self.graphql_client.clone()).await
@ -1882,7 +1886,7 @@ impl Directory {
/// # Arguments
///
/// * `opt` - optional argument, see inner type for documentation, use <func>_opts to use
pub async fn entries(&self) -> eyre::Result<Vec<String>> {
pub async fn entries(&self) -> Result<Vec<String>, DaggerError> {
let query = self.selection.select("entries");
query.execute(self.graphql_client.clone()).await
@ -1896,7 +1900,7 @@ impl Directory {
pub async fn entries_opts<'a>(
&self,
opts: DirectoryEntriesOpts<'a>,
) -> eyre::Result<Vec<String>> {
) -> Result<Vec<String>, DaggerError> {
let mut query = self.selection.select("entries");
if let Some(path) = opts.path {
@ -1910,7 +1914,7 @@ impl Directory {
/// # Arguments
///
/// * `path` - Location of the copied directory (e.g., "logs/").
pub async fn export(&self, path: impl Into<String>) -> eyre::Result<bool> {
pub async fn export(&self, path: impl Into<String>) -> Result<bool, DaggerError> {
let mut query = self.selection.select("export");
query = query.arg("path", path.into());
@ -1934,7 +1938,7 @@ impl Directory {
};
}
/// The content-addressed identifier of the directory.
pub async fn id(&self) -> eyre::Result<DirectoryId> {
pub async fn id(&self) -> Result<DirectoryId, DaggerError> {
let query = self.selection.select("id");
query.execute(self.graphql_client.clone()).await
@ -2242,13 +2246,13 @@ pub struct EnvVariable {
impl EnvVariable {
/// The environment variable name.
pub async fn name(&self) -> eyre::Result<String> {
pub async fn name(&self) -> Result<String, DaggerError> {
let query = self.selection.select("name");
query.execute(self.graphql_client.clone()).await
}
/// The environment variable value.
pub async fn value(&self) -> eyre::Result<String> {
pub async fn value(&self) -> Result<String, DaggerError> {
let query = self.selection.select("value");
query.execute(self.graphql_client.clone()).await
@ -2263,7 +2267,7 @@ pub struct File {
impl File {
/// Retrieves the contents of the file.
pub async fn contents(&self) -> eyre::Result<String> {
pub async fn contents(&self) -> Result<String, DaggerError> {
let query = self.selection.select("contents");
query.execute(self.graphql_client.clone()).await
@ -2273,7 +2277,7 @@ impl File {
/// # Arguments
///
/// * `path` - Location of the written directory (e.g., "output.txt").
pub async fn export(&self, path: impl Into<String>) -> eyre::Result<bool> {
pub async fn export(&self, path: impl Into<String>) -> Result<bool, DaggerError> {
let mut query = self.selection.select("export");
query = query.arg("path", path.into());
@ -2281,7 +2285,7 @@ impl File {
query.execute(self.graphql_client.clone()).await
}
/// Retrieves the content-addressed identifier of the file.
pub async fn id(&self) -> eyre::Result<FileId> {
pub async fn id(&self) -> Result<FileId, DaggerError> {
let query = self.selection.select("id");
query.execute(self.graphql_client.clone()).await
@ -2297,7 +2301,7 @@ impl File {
};
}
/// Gets the size of the file, in bytes.
pub async fn size(&self) -> eyre::Result<isize> {
pub async fn size(&self) -> Result<isize, DaggerError> {
let query = self.selection.select("size");
query.execute(self.graphql_client.clone()).await
@ -2338,7 +2342,7 @@ pub struct GitRefTreeOpts<'a> {
impl GitRef {
/// The digest of the current value of this ref.
pub async fn digest(&self) -> eyre::Result<String> {
pub async fn digest(&self) -> Result<String, DaggerError> {
let query = self.selection.select("digest");
query.execute(self.graphql_client.clone()).await
@ -2405,7 +2409,7 @@ impl GitRepository {
};
}
/// Lists of branches on the repository.
pub async fn branches(&self) -> eyre::Result<Vec<String>> {
pub async fn branches(&self) -> Result<Vec<String>, DaggerError> {
let query = self.selection.select("branches");
query.execute(self.graphql_client.clone()).await
@ -2443,7 +2447,7 @@ impl GitRepository {
};
}
/// Lists of tags on the repository.
pub async fn tags(&self) -> eyre::Result<Vec<String>> {
pub async fn tags(&self) -> Result<Vec<String>, DaggerError> {
let query = self.selection.select("tags");
query.execute(self.graphql_client.clone()).await
@ -2609,7 +2613,7 @@ impl HostVariable {
};
}
/// The value of this variable.
pub async fn value(&self) -> eyre::Result<String> {
pub async fn value(&self) -> Result<String, DaggerError> {
let query = self.selection.select("value");
query.execute(self.graphql_client.clone()).await
@ -2624,13 +2628,13 @@ pub struct Label {
impl Label {
/// The label name.
pub async fn name(&self) -> eyre::Result<String> {
pub async fn name(&self) -> Result<String, DaggerError> {
let query = self.selection.select("name");
query.execute(self.graphql_client.clone()).await
}
/// The label value.
pub async fn value(&self) -> eyre::Result<String> {
pub async fn value(&self) -> Result<String, DaggerError> {
let query = self.selection.select("value");
query.execute(self.graphql_client.clone()).await
@ -2645,19 +2649,19 @@ pub struct Port {
impl Port {
/// The port description.
pub async fn description(&self) -> eyre::Result<String> {
pub async fn description(&self) -> Result<String, DaggerError> {
let query = self.selection.select("description");
query.execute(self.graphql_client.clone()).await
}
/// The port number.
pub async fn port(&self) -> eyre::Result<isize> {
pub async fn port(&self) -> Result<isize, DaggerError> {
let query = self.selection.select("port");
query.execute(self.graphql_client.clone()).await
}
/// The transport layer network protocol.
pub async fn protocol(&self) -> eyre::Result<NetworkProtocol> {
pub async fn protocol(&self) -> Result<NetworkProtocol, DaggerError> {
let query = self.selection.select("protocol");
query.execute(self.graphql_client.clone()).await
@ -2692,25 +2696,25 @@ impl Project {
};
}
/// install the project's schema
pub async fn install(&self) -> eyre::Result<bool> {
pub async fn install(&self) -> Result<bool, DaggerError> {
let query = self.selection.select("install");
query.execute(self.graphql_client.clone()).await
}
/// name of the project
pub async fn name(&self) -> eyre::Result<String> {
pub async fn name(&self) -> Result<String, DaggerError> {
let query = self.selection.select("name");
query.execute(self.graphql_client.clone()).await
}
/// schema provided by the project
pub async fn schema(&self) -> eyre::Result<String> {
pub async fn schema(&self) -> Result<String, DaggerError> {
let query = self.selection.select("schema");
query.execute(self.graphql_client.clone()).await
}
/// sdk used to generate code for and/or execute this project
pub async fn sdk(&self) -> eyre::Result<String> {
pub async fn sdk(&self) -> Result<String, DaggerError> {
let query = self.selection.select("sdk");
query.execute(self.graphql_client.clone()).await
@ -2825,7 +2829,7 @@ impl Query {
};
}
/// The default platform of the builder.
pub async fn default_platform(&self) -> eyre::Result<Platform> {
pub async fn default_platform(&self) -> Result<Platform, DaggerError> {
let query = self.selection.select("defaultPlatform");
query.execute(self.graphql_client.clone()).await
@ -3094,13 +3098,13 @@ pub struct Secret {
impl Secret {
/// The identifier for this secret.
pub async fn id(&self) -> eyre::Result<SecretId> {
pub async fn id(&self) -> Result<SecretId, DaggerError> {
let query = self.selection.select("id");
query.execute(self.graphql_client.clone()).await
}
/// The value of this secret.
pub async fn plaintext(&self) -> eyre::Result<String> {
pub async fn plaintext(&self) -> Result<String, DaggerError> {
let query = self.selection.select("plaintext");
query.execute(self.graphql_client.clone()).await
@ -3115,7 +3119,7 @@ pub struct Socket {
impl Socket {
/// The content-addressed identifier of the socket.
pub async fn id(&self) -> eyre::Result<SocketId> {
pub async fn id(&self) -> Result<SocketId, DaggerError> {
let query = self.selection.select("id");
query.execute(self.graphql_client.clone()).await

View File

@ -1,6 +1,7 @@
#![deny(warnings)]
mod client;
pub mod errors;
mod gen;
pub mod logging;
mod querybuilder;

View File

@ -1,9 +1,10 @@
use std::{collections::HashMap, ops::Add, sync::Arc};
use dagger_core::graphql_client::DynGraphQLClient;
use eyre::Context;
use serde::{Deserialize, Serialize};
use crate::errors::{DaggerError, DaggerUnpackError};
pub fn query() -> Selection {
Selection::default()
}
@ -92,7 +93,7 @@ impl Selection {
s
}
pub fn build(&self) -> eyre::Result<String> {
pub fn build(&self) -> Result<String, DaggerError> {
let mut fields = vec!["query".to_string()];
for sel in self.path() {
@ -117,7 +118,7 @@ impl Selection {
Ok(fields.join("{") + &"}".repeat(fields.len() - 1))
}
pub async fn execute<D>(&self, gql_client: DynGraphQLClient) -> eyre::Result<D>
pub async fn execute<D>(&self, gql_client: DynGraphQLClient) -> Result<D, DaggerError>
where
D: for<'de> Deserialize<'de>,
{
@ -127,7 +128,7 @@ impl Selection {
let resp: Option<serde_json::Value> = match gql_client.query(&query).await {
Ok(r) => r,
Err(e) => eyre::bail!(e),
Err(e) => return Err(DaggerError::Query(e)),
};
let resp: Option<D> = self.unpack_resp(resp)?;
@ -151,7 +152,10 @@ impl Selection {
selections
}
pub(crate) fn unpack_resp<D>(&self, resp: Option<serde_json::Value>) -> eyre::Result<Option<D>>
pub(crate) fn unpack_resp<D>(
&self,
resp: Option<serde_json::Value>,
) -> Result<Option<D>, DaggerError>
where
D: for<'de> Deserialize<'de>,
{
@ -161,21 +165,23 @@ impl Selection {
}
}
fn unpack_resp_value<D>(&self, r: serde_json::Value) -> eyre::Result<D>
fn unpack_resp_value<D>(&self, r: serde_json::Value) -> Result<D, DaggerError>
where
D: for<'de> Deserialize<'de>,
{
if let Some(o) = r.as_object() {
let keys = o.keys();
if keys.len() != 1 {
eyre::bail!("too many nested objects inside graphql response")
return Err(DaggerError::Unpack(DaggerUnpackError::TooManyNestedObjects));
}
let first = keys.into_iter().next().unwrap();
return self.unpack_resp_value(o.get(first).unwrap().clone());
}
serde_json::from_value::<D>(r).context("could not deserialize response")
serde_json::from_value::<D>(r)
.map_err(DaggerUnpackError::Deserialize)
.map_err(DaggerError::Unpack)
}
}

View File

@ -111,9 +111,9 @@ async fn test_err_message() {
assert_eq!(alpine.is_err(), true);
let err = alpine.expect_err("Tests expect err");
let error_msg = r#"
GQLClient Error: Look at json field for more details
Message: pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed
let error_msg = r#"failed to query dagger engine: domain error:
Look at json field for more details
pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed
"#;
assert_eq!(err.to_string().as_str(), error_msg);