diff --git a/Makefile.toml b/Makefile.toml new file mode 100644 index 0000000..9dff01a --- /dev/null +++ b/Makefile.toml @@ -0,0 +1,4 @@ +[tasks.codegen] +command = "cargo" +args = ["run", "-p", "ci", "--", "codegen"] +workspace = false diff --git a/ci/src/main.rs b/ci/src/main.rs index 96ffa0a..ea3818d 100644 --- a/ci/src/main.rs +++ b/ci/src/main.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use clap::ArgMatches; use dagger_sdk::{Container, HostDirectoryOpts, Query}; #[tokio::main] @@ -10,6 +11,7 @@ async fn main() -> eyre::Result<()> { .subcommand_required(true) .subcommand(clap::Command::new("pr")) .subcommand(clap::Command::new("release")) + .subcommand(clap::Command::new("codegen")) .get_matches(); let client = dagger_sdk::connect().await?; @@ -20,6 +22,7 @@ async fn main() -> eyre::Result<()> { return validate_pr(client, base).await; } Some(("release", subm)) => return release(client, subm).await, + Some(("codegen", subm)) => return run_codegen(client, subm).await, Some(_) => { panic!("invalid subcommand selected!") } @@ -29,6 +32,41 @@ async fn main() -> eyre::Result<()> { } } +async fn run_codegen(client: Arc, _subm: &ArgMatches) -> eyre::Result<()> { + let docker_cli = client + .container() + .from("docker:cli") + .file("/usr/local/bin/docker"); + let socket = client.host().unix_socket("/var/run/docker.sock"); + + let container = get_dependencies(client).await?; + + let generated_image = container + .with_exec(vec!["mkdir", "-p", "/mnt/output"]) + .with_mounted_file("/usr/bin/docker", docker_cli.id().await?) + .with_unix_socket("/var/run/docker.sock", socket.id().await?) + .with_exec(vec![ + "cargo", + "run", + "--", + "generate", + "--output", + "crates/dagger-sdk/gen.rs", + ]) + .with_exec(vec!["cargo", "fmt", "--all"]) + .with_exec(vec!["cargo", "fix", "--workspace", "--allow-dirty"]) + .with_exec(vec!["mv", "crates/dagger-sdk/gen.rs", "/mnt/output/gen.rs"]); + + let _ = generated_image.exit_code().await?; + + generated_image + .file("/mnt/output/gen.rs") + .export("crates/dagger-sdk/src/gen.rs") + .await?; + + Ok(()) +} + async fn release(client: Arc, _subm: &clap::ArgMatches) -> Result<(), color_eyre::Report> { let src_dir = client.host().directory_opts( ".", @@ -87,14 +125,14 @@ async fn get_dependencies(client: Arc) -> eyre::Result { ); let cache_cargo_index_dir = client.cache_volume("cargo_index"); - let cache_cargo_deps = client.cache_volume("cargo_deps"); + let _cache_cargo_deps = client.cache_volume("cargo_deps"); let cache_cargo_bin = client.cache_volume("cargo_bin_cache"); let minio_url = "https://github.com/mozilla/sccache/releases/download/v0.3.3/sccache-v0.3.3-x86_64-unknown-linux-musl.tar.gz"; let base_image = client .container() - .from("rust:latest") + .from("rustlang/rust:nightly") .with_workdir("app") .with_exec(vec!["apt-get", "update"]) .with_exec(vec!["apt-get", "install", "--yes", "libpq-dev", "wget"]) @@ -110,7 +148,7 @@ async fn get_dependencies(client: Arc) -> eyre::Result { "/usr/local/bin/sccache", ]) .with_exec(vec!["chmod", "+x", "/usr/local/bin/sccache"]) - .with_env_variable("RUSTC_WRAPPER", "/usr/local/bin/sccache") + //.with_env_variable("RUSTC_WRAPPER", "/usr/local/bin/sccache") .with_env_variable( "AWS_ACCESS_KEY_ID", std::env::var("AWS_ACCESS_KEY_ID").unwrap_or("".into()), @@ -152,8 +190,7 @@ async fn get_dependencies(client: Arc) -> eyre::Result { "--recipe-path", "recipe.json", ]) - .with_mounted_cache("/app/", cache_cargo_deps.id().await?) - .with_mounted_directory("/app/", src_dir.id().await?) + .with_directory("/app/", src_dir.id().await?) .with_exec(vec!["cargo", "build", "--all", "--release"]); return Ok(builder_start); diff --git a/crates/dagger-sdk/src/gen.rs b/crates/dagger-sdk/src/gen.rs index 21d2cac..7978207 100644 --- a/crates/dagger-sdk/src/gen.rs +++ b/crates/dagger-sdk/src/gen.rs @@ -25,6 +25,11 @@ pub struct BuildArg { pub name: String, pub value: String, } +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct PipelineLabel { + pub value: String, + pub name: String, +} #[derive(Debug, Clone)] pub struct CacheVolume { pub proc: Arc, @@ -97,8 +102,12 @@ pub struct ContainerExportOpts { } #[derive(Builder, Debug, PartialEq)] pub struct ContainerPipelineOpts<'a> { + /// Pipeline description. #[builder(setter(into, strip_option), default)] pub description: Option<&'a str>, + /// Pipeline labels. + #[builder(setter(into, strip_option), default)] + pub labels: Option>, } #[derive(Builder, Debug, PartialEq)] pub struct ContainerPublishOpts { @@ -138,6 +147,12 @@ pub struct ContainerWithExecOpts<'a> { /// The command being executed WILL BE GRANTED FULL ACCESS TO YOUR HOST FILESYSTEM. #[builder(setter(into, strip_option), default)] pub experimental_privileged_nesting: Option, + /// Execute the command with all root capabilities. This is similar to running a command + /// with "sudo" or executing `docker run` with the `--privileged` flag. Containerization + /// does not provide any security guarantees when using this option. It should only be used + /// when absolutely necessary and only with trusted commands. + #[builder(setter(into, strip_option), default)] + pub insecure_root_capabilities: Option, } #[derive(Builder, Debug, PartialEq)] pub struct ContainerWithExposedPortOpts<'a> { @@ -252,6 +267,7 @@ impl Container { /// Retrieves an endpoint that clients can use to reach this container. /// If no port is specified, the first exposed port is used. If none exist an error is returned. /// If a scheme is specified, a URL is returned. Otherwise, a host:port pair is returned. + /// Currently experimental; set _EXPERIMENTAL_DAGGER_SERVICES_DNS=0 to disable. /// /// # Arguments /// @@ -265,6 +281,7 @@ impl Container { /// Retrieves an endpoint that clients can use to reach this container. /// If no port is specified, the first exposed port is used. If none exist an error is returned. /// If a scheme is specified, a URL is returned. Otherwise, a host:port pair is returned. + /// Currently experimental; set _EXPERIMENTAL_DAGGER_SERVICES_DNS=0 to disable. /// /// # Arguments /// @@ -358,7 +375,7 @@ impl Container { }; } /// Exit code of the last executed command. Zero means success. - /// Null if no command has been executed. + /// Errors if no command has been executed. pub async fn exit_code(&self) -> eyre::Result { let query = self.selection.select("exitCode"); @@ -404,7 +421,8 @@ impl Container { query.execute(&graphql_client(&self.conn)).await } - /// Retrieves the list of exposed ports + /// Retrieves the list of exposed ports. + /// Currently experimental; set _EXPERIMENTAL_DAGGER_SERVICES_DNS=0 to disable. pub fn exposed_ports(&self) -> Vec { let query = self.selection.select("exposedPorts"); @@ -460,6 +478,7 @@ 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 { let query = self.selection.select("hostname"); @@ -505,6 +524,7 @@ impl Container { /// /// # Arguments /// + /// * `name` - Pipeline name. /// * `opt` - optional argument, see inner type for documentation, use _opts to use pub fn pipeline(&self, name: impl Into) -> Container { let mut query = self.selection.select("pipeline"); @@ -522,6 +542,7 @@ impl Container { /// /// # Arguments /// + /// * `name` - Pipeline name. /// * `opt` - optional argument, see inner type for documentation, use _opts to use pub fn pipeline_opts<'a>( &self, @@ -534,6 +555,9 @@ impl Container { if let Some(description) = opts.description { query = query.arg("description", description); } + if let Some(labels) = opts.labels { + query = query.arg("labels", labels); + } return Container { proc: self.proc.clone(), @@ -600,14 +624,14 @@ impl Container { }; } /// The error stream of the last executed command. - /// Null if no command has been executed. + /// Errors if no command has been executed. pub async fn stderr(&self) -> eyre::Result { let query = self.selection.select("stderr"); query.execute(&graphql_client(&self.conn)).await } /// The output stream of the last executed command. - /// Null if no command has been executed. + /// Errors if no command has been executed. pub async fn stdout(&self) -> eyre::Result { let query = self.selection.select("stdout"); @@ -796,6 +820,9 @@ impl Container { experimental_privileged_nesting, ); } + if let Some(insecure_root_capabilities) = opts.insecure_root_capabilities { + query = query.arg("insecureRootCapabilities", insecure_root_capabilities); + } return Container { proc: self.proc.clone(), @@ -807,6 +834,7 @@ impl Container { /// Exposed ports serve two purposes: /// - For health checks and introspection, when running services /// - For setting the EXPOSE OCI field when publishing the container + /// Currently experimental; set _EXPERIMENTAL_DAGGER_SERVICES_DNS=0 to disable. /// /// # Arguments /// @@ -828,6 +856,7 @@ impl Container { /// Exposed ports serve two purposes: /// - For health checks and introspection, when running services /// - For setting the EXPOSE OCI field when publishing the container + /// Currently experimental; set _EXPERIMENTAL_DAGGER_SERVICES_DNS=0 to disable. /// /// # Arguments /// @@ -1159,6 +1188,7 @@ impl Container { /// Establish a runtime dependency on a service. The service will be started automatically when needed and detached when it is no longer needed. /// The service will be reachable from the container via the provided hostname alias. /// The service dependency will also convey to any files or directories produced by the container. + /// Currently experimental; set _EXPERIMENTAL_DAGGER_SERVICES_DNS=0 to disable. /// /// # Arguments /// @@ -1247,6 +1277,7 @@ impl Container { }; } /// Unexpose a previously exposed port. + /// Currently experimental; set _EXPERIMENTAL_DAGGER_SERVICES_DNS=0 to disable. /// /// # Arguments /// @@ -1265,6 +1296,7 @@ impl Container { } /// Unexpose a previously exposed port. + /// Currently experimental; set _EXPERIMENTAL_DAGGER_SERVICES_DNS=0 to disable. /// /// # Arguments /// @@ -1391,8 +1423,12 @@ pub struct DirectoryEntriesOpts<'a> { } #[derive(Builder, Debug, PartialEq)] pub struct DirectoryPipelineOpts<'a> { + /// Pipeline description. #[builder(setter(into, strip_option), default)] pub description: Option<&'a str>, + /// Pipeline labels. + #[builder(setter(into, strip_option), default)] + pub labels: Option>, } #[derive(Builder, Debug, PartialEq)] pub struct DirectoryWithDirectoryOpts<'a> { @@ -1574,10 +1610,11 @@ impl Directory { conn: self.conn.clone(), }; } - /// Creates a named sub-pipeline. + /// Creates a named sub-pipeline /// /// # Arguments /// + /// * `name` - Pipeline name. /// * `opt` - optional argument, see inner type for documentation, use _opts to use pub fn pipeline(&self, name: impl Into) -> Directory { let mut query = self.selection.select("pipeline"); @@ -1591,10 +1628,11 @@ impl Directory { }; } - /// Creates a named sub-pipeline. + /// Creates a named sub-pipeline /// /// # Arguments /// + /// * `name` - Pipeline name. /// * `opt` - optional argument, see inner type for documentation, use _opts to use pub fn pipeline_opts<'a>( &self, @@ -1607,6 +1645,9 @@ impl Directory { if let Some(description) = opts.description { query = query.arg("description", description); } + if let Some(labels) = opts.labels { + query = query.arg("labels", labels); + } return Directory { proc: self.proc.clone(), @@ -2370,8 +2411,12 @@ pub struct QueryHttpOpts { } #[derive(Builder, Debug, PartialEq)] pub struct QueryPipelineOpts<'a> { + /// Pipeline description. #[builder(setter(into, strip_option), default)] pub description: Option<&'a str>, + /// Pipeline labels. + #[builder(setter(into, strip_option), default)] + pub labels: Option>, } #[derive(Builder, Debug, PartialEq)] pub struct QuerySocketOpts { @@ -2582,10 +2627,11 @@ impl Query { conn: self.conn.clone(), }; } - /// Creates a named sub-pipeline + /// Creates a named sub-pipeline. /// /// # Arguments /// + /// * `name` - Pipeline name. /// * `opt` - optional argument, see inner type for documentation, use _opts to use pub fn pipeline(&self, name: impl Into) -> Query { let mut query = self.selection.select("pipeline"); @@ -2599,10 +2645,11 @@ impl Query { }; } - /// Creates a named sub-pipeline + /// Creates a named sub-pipeline. /// /// # Arguments /// + /// * `name` - Pipeline name. /// * `opt` - optional argument, see inner type for documentation, use _opts to use pub fn pipeline_opts<'a>(&self, name: impl Into, opts: QueryPipelineOpts<'a>) -> Query { let mut query = self.selection.select("pipeline"); @@ -2611,6 +2658,9 @@ impl Query { if let Some(description) = opts.description { query = query.arg("description", description); } + if let Some(labels) = opts.labels { + query = query.arg("labels", labels); + } return Query { proc: self.proc.clone(), @@ -2714,12 +2764,12 @@ impl Socket { } #[derive(Serialize, Deserialize, Clone, PartialEq, Debug)] pub enum CacheSharingMode { + LOCKED, SHARED, PRIVATE, - LOCKED, } #[derive(Serialize, Deserialize, Clone, PartialEq, Debug)] pub enum NetworkProtocol { - UDP, TCP, + UDP, } diff --git a/crates/dagger-sdk/tests/mod.rs b/crates/dagger-sdk/tests/mod.rs index 16cf7bb..701e78d 100644 --- a/crates/dagger-sdk/tests/mod.rs +++ b/crates/dagger-sdk/tests/mod.rs @@ -1,4 +1,4 @@ -use dagger_sdk::{connect, ContainerExecOpts, ContainerExecOptsBuilder}; +use dagger_sdk::{connect, ContainerExecOptsBuilder}; use pretty_assertions::assert_eq; #[tokio::test]