Skip to content
This repository was archived by the owner on Oct 31, 2023. It is now read-only.

feat(ux): flatten wash reg push/pull into wash push/pull #580

Merged
merged 1 commit into from
May 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ test: ## Run unit test suite

test-wash-ci:
@$(CARGO) nextest run --profile ci --workspace --bin wash
@$(CARGO) nextest run --profile ci -p wash-lib
@$(CARGO) nextest run --profile ci -p wash-lib --features=cli

test-watch: ## Run unit tests continously, can optionally specify a target test filter.
@$(CARGO) watch -- $(CARGO) nextest run $(TARGET)
Expand Down
97 changes: 97 additions & 0 deletions crates/wash-lib/src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::{
};

use anyhow::{anyhow, bail, Result};
use clap::{Parser, Subcommand};
use oci_distribution::manifest::OciImageManifest;
use oci_distribution::{
client::{Client, ClientConfig, ClientProtocol, Config, ImageLayer},
Expand Down Expand Up @@ -67,6 +68,102 @@ pub enum SupportedArtifacts {
Wasm,
}

#[derive(Parser, Debug, Clone)]
pub struct AuthOpts {
/// OCI username, if omitted anonymous authentication will be used
#[clap(
short = 'u',
long = "user",
env = "WASH_REG_USER",
hide_env_values = true
)]
pub user: Option<String>,

/// OCI password, if omitted anonymous authentication will be used
#[clap(
short = 'p',
long = "password",
env = "WASH_REG_PASSWORD",
hide_env_values = true
)]
pub password: Option<String>,

/// Allow insecure (HTTP) registry connections
#[clap(long = "insecure")]
pub insecure: bool,
}

#[derive(Debug, Clone, Subcommand)]
pub enum RegistryCommand {
/// Pull an artifact from an OCI compliant registry
#[clap(name = "pull")]
Pull(RegistryPullCommand),
/// Push an artifact to an OCI compliant registry
#[clap(name = "push")]
Push(RegistryPushCommand),
/// Ping (test url) to see if the OCI url has an artifact
#[clap(name = "ping")]
Ping(RegistryPingCommand),
}

#[derive(Parser, Debug, Clone)]
pub struct RegistryPullCommand {
/// URL of artifact
#[clap(name = "url")]
pub url: String,

/// File destination of artifact
#[clap(long = "destination")]
pub destination: Option<String>,

/// Digest to verify artifact against
#[clap(short = 'd', long = "digest")]
pub digest: Option<String>,

/// Allow latest artifact tags
#[clap(long = "allow-latest")]
pub allow_latest: bool,

#[clap(flatten)]
pub opts: AuthOpts,
}

#[derive(Parser, Debug, Clone)]
pub struct RegistryPushCommand {
/// URL to push artifact to
#[clap(name = "url")]
pub url: String,

/// Path to artifact to push
#[clap(name = "artifact")]
pub artifact: String,

/// Path to config file, if omitted will default to a blank configuration
#[clap(short = 'c', long = "config")]
pub config: Option<String>,

/// Allow latest artifact tags
#[clap(long = "allow-latest")]
pub allow_latest: bool,

/// Optional set of annotations to apply to the OCI artifact manifest
#[clap(short = 'a', long = "annotation", name = "annotations")]
pub annotations: Option<Vec<String>>,

#[clap(flatten)]
pub opts: AuthOpts,
}

#[derive(Parser, Debug, Clone)]
pub struct RegistryPingCommand {
/// URL of artifact
#[clap(name = "url")]
pub url: String,

#[clap(flatten)]
pub opts: AuthOpts,
}

// NOTE(thomastaylor312): In later refactors, we might want to consider making some sort of puller
// and pusher structs that can take optional implementations of a `Cache` trait that does all the
// cached file handling. But for now, this should be good enough
Expand Down
1 change: 1 addition & 0 deletions src/common/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub(crate) mod link_cmd;
pub(crate) mod registry_cmd;
pub(crate) mod start_cmd;
pub(crate) mod stop_cmd;
155 changes: 30 additions & 125 deletions src/reg.rs → src/common/registry_cmd.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::{collections::HashMap, path::PathBuf};

use anyhow::Result;
use clap::{Parser, Subcommand};
use log::warn;
use oci_distribution::{
client::{Client, ClientConfig, ClientProtocol},
Expand All @@ -11,128 +10,23 @@ use oci_distribution::{
use serde_json::json;
use tokio::fs::File;
use tokio::io::AsyncWriteExt;
use wash_lib::cli::{labels_vec_to_hashmap, CommandOutput, OutputKind};
use wash_lib::registry::{
pull_oci_artifact, push_oci_artifact, validate_artifact, OciPullOptions, OciPushOptions,
SupportedArtifacts,
};
use wash_lib::{
cli::{labels_vec_to_hashmap, CommandOutput, OutputKind},
registry::{RegistryCommand, RegistryPingCommand, RegistryPullCommand, RegistryPushCommand},
};

use crate::appearance::spinner::Spinner;

const PROVIDER_ARCHIVE_FILE_EXTENSION: &str = ".par.gz";
const WASM_FILE_EXTENSION: &str = ".wasm";

pub(crate) const SHOWER_EMOJI: &str = "\u{1F6BF}";
pub(crate) const PROVIDER_ARCHIVE_FILE_EXTENSION: &str = ".par.gz";
pub(crate) const WASM_FILE_EXTENSION: &str = ".wasm";

#[derive(Debug, Clone, Subcommand)]
pub(crate) enum RegCliCommand {
/// Pull an artifact from an OCI compliant registry
#[clap(name = "pull")]
Pull(PullCommand),
/// Push an artifact to an OCI compliant registry
#[clap(name = "push")]
Push(PushCommand),
/// Ping (test url) to see if the OCI url has an artifact
#[clap(name = "ping")]
Ping(PingCommand),
}

#[derive(Parser, Debug, Clone)]
pub(crate) struct PullCommand {
/// URL of artifact
#[clap(name = "url")]
pub(crate) url: String,

/// File destination of artifact
#[clap(long = "destination")]
pub(crate) destination: Option<String>,

/// Digest to verify artifact against
#[clap(short = 'd', long = "digest")]
pub(crate) digest: Option<String>,

/// Allow latest artifact tags
#[clap(long = "allow-latest")]
pub(crate) allow_latest: bool,

#[clap(flatten)]
pub(crate) opts: AuthOpts,
}

#[derive(Parser, Debug, Clone)]
pub(crate) struct PushCommand {
/// URL to push artifact to
#[clap(name = "url")]
pub(crate) url: String,

/// Path to artifact to push
#[clap(name = "artifact")]
pub(crate) artifact: String,

/// Path to config file, if omitted will default to a blank configuration
#[clap(short = 'c', long = "config")]
pub(crate) config: Option<String>,

/// Allow latest artifact tags
#[clap(long = "allow-latest")]
pub(crate) allow_latest: bool,

/// Optional set of annotations to apply to the OCI artifact manifest
#[clap(short = 'a', long = "annotation", name = "annotations")]
pub(crate) annotations: Option<Vec<String>>,

#[clap(flatten)]
pub(crate) opts: AuthOpts,
}

#[derive(Parser, Debug, Clone)]
pub(crate) struct PingCommand {
/// URL of artifact
#[clap(name = "url")]
pub(crate) url: String,

#[clap(flatten)]
pub(crate) opts: AuthOpts,
}

#[derive(Parser, Debug, Clone)]
pub(crate) struct AuthOpts {
/// OCI username, if omitted anonymous authentication will be used
#[clap(
short = 'u',
long = "user",
env = "WASH_REG_USER",
hide_env_values = true
)]
pub(crate) user: Option<String>,

/// OCI password, if omitted anonymous authentication will be used
#[clap(
short = 'p',
long = "password",
env = "WASH_REG_PASSWORD",
hide_env_values = true
)]
pub(crate) password: Option<String>,

/// Allow insecure (HTTP) registry connections
#[clap(long = "insecure")]
pub(crate) insecure: bool,
}

pub(crate) async fn handle_command(
command: RegCliCommand,
output_kind: OutputKind,
) -> Result<CommandOutput> {
match command {
RegCliCommand::Pull(cmd) => handle_pull(cmd, output_kind).await,
RegCliCommand::Push(cmd) => handle_push(cmd, output_kind).await,
RegCliCommand::Ping(cmd) => handle_ping(cmd).await,
}
}

pub(crate) async fn handle_pull(
cmd: PullCommand,
pub(crate) async fn registry_pull(
cmd: RegistryPullCommand,
output_kind: OutputKind,
) -> Result<CommandOutput> {
let artifact_url = cmd.url.to_ascii_lowercase();
Expand Down Expand Up @@ -165,7 +59,7 @@ pub(crate) async fn handle_pull(
))
}

pub(crate) async fn handle_ping(cmd: PingCommand) -> Result<CommandOutput> {
pub(crate) async fn registry_ping(cmd: RegistryPingCommand) -> Result<CommandOutput> {
let image: Reference = cmd.url.parse()?;
let mut client = Client::new(ClientConfig {
protocol: if cmd.opts.insecure {
Expand Down Expand Up @@ -212,8 +106,8 @@ pub(crate) async fn write_artifact(
Ok(outfile)
}

pub(crate) async fn handle_push(
cmd: PushCommand,
pub(crate) async fn registry_push(
cmd: RegistryPushCommand,
output_kind: OutputKind,
) -> Result<CommandOutput> {
let artifact_url = cmd.url.to_ascii_lowercase();
Expand Down Expand Up @@ -250,9 +144,20 @@ pub(crate) async fn handle_push(
))
}

pub(crate) async fn handle_command(
command: RegistryCommand,
output_kind: OutputKind,
) -> Result<CommandOutput> {
match command {
RegistryCommand::Pull(cmd) => registry_pull(cmd, output_kind).await,
RegistryCommand::Push(cmd) => registry_push(cmd, output_kind).await,
RegistryCommand::Ping(cmd) => registry_ping(cmd).await,
}
}

#[cfg(test)]
mod tests {
use super::{PullCommand, PushCommand, RegCliCommand};
use crate::common::registry_cmd::{RegistryCommand, RegistryPullCommand, RegistryPushCommand};
use clap::Parser;

const ECHO_WASM: &str = "wasmcloud.azurecr.io/echo:0.2.0";
Expand All @@ -261,7 +166,7 @@ mod tests {
#[derive(Debug, Parser)]
struct Cmd {
#[clap(subcommand)]
reg: RegCliCommand,
reg: RegistryCommand,
}

#[test]
Expand Down Expand Up @@ -291,14 +196,14 @@ mod tests {
])
.unwrap();
match pull_basic.reg {
RegCliCommand::Pull(PullCommand { url, .. }) => {
RegistryCommand::Pull(RegistryPullCommand { url, .. }) => {
assert_eq!(url, ECHO_WASM);
}
_ => panic!("`reg pull` constructed incorrect command"),
};

match pull_all_flags.reg {
RegCliCommand::Pull(PullCommand {
RegistryCommand::Pull(RegistryPullCommand {
url,
allow_latest,
opts,
Expand All @@ -312,7 +217,7 @@ mod tests {
};

match pull_all_options.reg {
RegCliCommand::Pull(PullCommand {
RegistryCommand::Pull(RegistryPullCommand {
url,
destination,
digest,
Expand Down Expand Up @@ -351,7 +256,7 @@ mod tests {
])
.unwrap();
match push_basic.reg {
RegCliCommand::Push(PushCommand {
RegistryCommand::Push(RegistryPushCommand {
url,
artifact,
opts,
Expand All @@ -376,7 +281,7 @@ mod tests {
])
.unwrap();
match push_all_flags.reg {
RegCliCommand::Push(PushCommand {
RegistryCommand::Push(RegistryPushCommand {
url,
artifact,
opts,
Expand Down Expand Up @@ -409,7 +314,7 @@ mod tests {
])
.unwrap();
match push_all_options.reg {
RegCliCommand::Push(PushCommand {
RegistryCommand::Push(RegistryPushCommand {
url,
artifact,
opts,
Expand Down
Loading