diff --git a/crates/bin/ampctl/src/cmd/dataset/deploy.rs b/crates/bin/ampctl/src/cmd/dataset/deploy.rs index 8542ca8f4..b3665434a 100644 --- a/crates/bin/ampctl/src/cmd/dataset/deploy.rs +++ b/crates/bin/ampctl/src/cmd/dataset/deploy.rs @@ -66,23 +66,6 @@ pub struct Args { pub worker_id: Option, } -/// Result of a dataset deployment operation. -#[derive(serde::Serialize)] -struct DeployResult { - job_id: JobId, -} - -impl std::fmt::Display for DeployResult { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - writeln!( - f, - "{} Dataset deployed successfully", - console::style("✓").green().bold() - )?; - writeln!(f, "{} Job ID: {}", console::style("→").cyan(), self.job_id) - } -} - /// Deploy a dataset to start syncing blockchain data. /// /// Schedules a deployment job via the admin API and returns the job ID. @@ -137,6 +120,23 @@ async fn deploy_dataset( Ok(job_id) } +/// Result of a dataset deployment operation. +#[derive(serde::Serialize)] +struct DeployResult { + job_id: JobId, +} + +impl std::fmt::Display for DeployResult { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + writeln!( + f, + "{} Dataset deployed successfully", + console::style("✓").green().bold() + )?; + writeln!(f, "{} Job ID: {}", console::style("→").cyan(), self.job_id) + } +} + /// Errors for dataset deployment operations. #[derive(Debug, thiserror::Error)] pub enum Error { diff --git a/crates/bin/ampctl/src/cmd/dataset/inspect.rs b/crates/bin/ampctl/src/cmd/dataset/inspect.rs index ffa96a362..0b4d8dc36 100644 --- a/crates/bin/ampctl/src/cmd/dataset/inspect.rs +++ b/crates/bin/ampctl/src/cmd/dataset/inspect.rs @@ -26,24 +26,6 @@ pub struct Args { pub reference: Reference, } -/// Result of a dataset inspect operation. -#[derive(serde::Serialize)] -struct InspectResult { - #[serde(flatten)] - dataset: client::datasets::DatasetInfo, -} - -impl std::fmt::Display for InspectResult { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - writeln!(f, "Namespace: {}", self.dataset.namespace)?; - writeln!(f, "Name: {}", self.dataset.name)?; - writeln!(f, "Revision: {}", self.dataset.revision)?; - writeln!(f, "Kind: {}", self.dataset.kind)?; - writeln!(f, "Manifest Hash: {}", self.dataset.manifest_hash)?; - Ok(()) - } -} - /// Inspect dataset details by retrieving them from the admin API. /// /// Retrieves dataset information and displays it based on the output format. @@ -85,6 +67,24 @@ async fn get_dataset( } } +/// Result of a dataset inspect operation. +#[derive(serde::Serialize)] +struct InspectResult { + #[serde(flatten)] + dataset: client::datasets::DatasetInfo, +} + +impl std::fmt::Display for InspectResult { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + writeln!(f, "Namespace: {}", self.dataset.namespace)?; + writeln!(f, "Name: {}", self.dataset.name)?; + writeln!(f, "Revision: {}", self.dataset.revision)?; + writeln!(f, "Kind: {}", self.dataset.kind)?; + writeln!(f, "Manifest Hash: {}", self.dataset.manifest_hash)?; + Ok(()) + } +} + /// Errors for dataset inspect operations. #[derive(Debug, thiserror::Error)] pub enum Error { diff --git a/crates/bin/ampctl/src/cmd/dataset/list.rs b/crates/bin/ampctl/src/cmd/dataset/list.rs index c4901d27b..5a9c8d380 100644 --- a/crates/bin/ampctl/src/cmd/dataset/list.rs +++ b/crates/bin/ampctl/src/cmd/dataset/list.rs @@ -21,35 +21,6 @@ pub struct Args { pub global: GlobalArgs, } -/// Result of a dataset list operation. -#[derive(serde::Serialize)] -struct ListResult { - datasets: Vec, -} - -impl std::fmt::Display for ListResult { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - if self.datasets.is_empty() { - writeln!(f, "No datasets found") - } else { - writeln!(f, "Datasets:")?; - for dataset in &self.datasets { - let versions_str = if dataset.versions.is_empty() { - "no versions".to_string() - } else { - format!("{} version(s)", dataset.versions.len()) - }; - writeln!( - f, - " {}/{} - {}", - dataset.namespace, dataset.name, versions_str - )?; - } - Ok(()) - } - } -} - /// List all datasets by retrieving them from the admin API. /// /// Retrieves all datasets and displays them based on the output format. @@ -85,6 +56,35 @@ async fn get_datasets(global: &GlobalArgs) -> Result, +} + +impl std::fmt::Display for ListResult { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if self.datasets.is_empty() { + writeln!(f, "No datasets found") + } else { + writeln!(f, "Datasets:")?; + for dataset in &self.datasets { + let versions_str = if dataset.versions.is_empty() { + "no versions".to_string() + } else { + format!("{} version(s)", dataset.versions.len()) + }; + writeln!( + f, + " {}/{} - {}", + dataset.namespace, dataset.name, versions_str + )?; + } + Ok(()) + } + } +} + /// Errors for datasets listing operations. #[derive(Debug, thiserror::Error)] pub enum Error { diff --git a/crates/bin/ampctl/src/cmd/dataset/manifest.rs b/crates/bin/ampctl/src/cmd/dataset/manifest.rs index 470a96d3c..801980b50 100644 --- a/crates/bin/ampctl/src/cmd/dataset/manifest.rs +++ b/crates/bin/ampctl/src/cmd/dataset/manifest.rs @@ -26,21 +26,6 @@ pub struct Args { pub reference: Reference, } -/// Result wrapper for manifest inspect output. -#[derive(serde::Serialize)] -struct InspectResult { - #[serde(flatten)] - data: serde_json::Value, -} - -impl std::fmt::Display for InspectResult { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - // For manifest inspect, output pretty JSON as manifests are complex nested structures - let json = serde_json::to_string_pretty(&self.data).map_err(|_| std::fmt::Error)?; - write!(f, "{}", json) - } -} - /// Retrieve dataset manifest by fetching it from the admin API. /// /// Retrieves the manifest JSON and displays it based on the output format. @@ -86,6 +71,21 @@ async fn get_manifest( } } +/// Result wrapper for manifest inspect output. +#[derive(serde::Serialize)] +struct InspectResult { + #[serde(flatten)] + data: serde_json::Value, +} + +impl std::fmt::Display for InspectResult { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + // For manifest inspect, output pretty JSON as manifests are complex nested structures + let json = serde_json::to_string_pretty(&self.data).map_err(|_| std::fmt::Error)?; + write!(f, "{}", json) + } +} + /// Errors for dataset manifest operations. #[derive(Debug, thiserror::Error)] pub enum Error { diff --git a/crates/bin/ampctl/src/cmd/dataset/restore.rs b/crates/bin/ampctl/src/cmd/dataset/restore.rs index a7c43eb28..8bc202935 100644 --- a/crates/bin/ampctl/src/cmd/dataset/restore.rs +++ b/crates/bin/ampctl/src/cmd/dataset/restore.rs @@ -42,7 +42,59 @@ pub struct Args { pub location_id: Option, } -/// Result of a dataset restore operation (all tables). +/// Restore dataset physical tables from object storage. +/// +/// Re-indexes physical table metadata from storage into the database. +/// Optionally targets a single table with `--table`, and can activate +/// a specific revision with `--location-id`. +/// +/// # Errors +/// +/// Returns [`Error`] for invalid paths/URLs, API errors (400/404/500), or network failures. +#[tracing::instrument(skip_all, fields(admin_url = %global.admin_url, %dataset_ref))] +pub async fn run( + Args { + global, + dataset_ref, + table, + location_id, + }: Args, +) -> Result<(), Error> { + let client = global.build_client().map_err(Error::ClientBuild)?; + + if let Some(table_name) = table { + tracing::debug!(%dataset_ref, %table_name, ?location_id, "restoring single table"); + + client + .datasets() + .restore_table(&dataset_ref, &table_name, location_id) + .await + .map_err(Error::RestoreTable)?; + + let result = RestoreTableResult { + table: table_name, + location_id, + }; + global.print(&result).map_err(Error::JsonSerialization)?; + } else { + tracing::debug!(%dataset_ref, "restoring dataset"); + + let response = client + .datasets() + .restore(&dataset_ref) + .await + .map_err(Error::Restore)?; + + let result = RestoreResult { + tables: response.tables, + }; + global.print(&result).map_err(Error::JsonSerialization)?; + } + + Ok(()) +} + +/// Result of a dataset restore operation. #[derive(serde::Serialize)] struct RestoreResult { tables: Vec, @@ -105,58 +157,6 @@ impl std::fmt::Display for RestoreTableResult { } } -/// Restore dataset physical tables from object storage. -/// -/// Re-indexes physical table metadata from storage into the database. -/// Optionally targets a single table with `--table`, and can activate -/// a specific revision with `--location-id`. -/// -/// # Errors -/// -/// Returns [`Error`] for invalid paths/URLs, API errors (400/404/500), or network failures. -#[tracing::instrument(skip_all, fields(admin_url = %global.admin_url, %dataset_ref))] -pub async fn run( - Args { - global, - dataset_ref, - table, - location_id, - }: Args, -) -> Result<(), Error> { - let client = global.build_client().map_err(Error::ClientBuild)?; - - if let Some(table_name) = table { - tracing::debug!(%dataset_ref, %table_name, ?location_id, "restoring single table"); - - client - .datasets() - .restore_table(&dataset_ref, &table_name, location_id) - .await - .map_err(Error::RestoreTable)?; - - let result = RestoreTableResult { - table: table_name, - location_id, - }; - global.print(&result).map_err(Error::JsonSerialization)?; - } else { - tracing::debug!(%dataset_ref, "restoring dataset"); - - let response = client - .datasets() - .restore(&dataset_ref) - .await - .map_err(Error::Restore)?; - - let result = RestoreResult { - tables: response.tables, - }; - global.print(&result).map_err(Error::JsonSerialization)?; - } - - Ok(()) -} - /// Errors for dataset restore operations. #[derive(Debug, thiserror::Error)] pub enum Error { diff --git a/crates/bin/ampctl/src/cmd/dataset/versions.rs b/crates/bin/ampctl/src/cmd/dataset/versions.rs index 833884b93..beaf45850 100644 --- a/crates/bin/ampctl/src/cmd/dataset/versions.rs +++ b/crates/bin/ampctl/src/cmd/dataset/versions.rs @@ -25,39 +25,6 @@ pub struct Args { pub fqn: FullyQualifiedName, } -/// Result wrapper for versions list output. -#[derive(serde::Serialize)] -struct ListResult { - #[serde(flatten)] - data: client::datasets::VersionsResponse, -} - -impl std::fmt::Display for ListResult { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - writeln!(f, "Dataset: {}/{}", self.data.namespace, self.data.name)?; - writeln!(f)?; - - if let Some(latest) = &self.data.special_tags.latest { - writeln!(f, "Latest version: {}", latest)?; - } - if let Some(dev) = &self.data.special_tags.dev { - writeln!(f, "Dev hash: {}", dev)?; - } - - if self.data.versions.is_empty() { - writeln!(f, "\nNo versions found")?; - } else { - writeln!(f, "\nVersions:")?; - for version in &self.data.versions { - writeln!(f, " {} ({})", version.version, version.manifest_hash)?; - writeln!(f, " Created: {}", version.created_at)?; - writeln!(f, " Updated: {}", version.updated_at)?; - } - } - Ok(()) - } -} - /// List all versions of a dataset by retrieving them from the admin API. /// /// Retrieves version information and displays it based on the output format. @@ -96,6 +63,39 @@ async fn get_versions( Ok(versions_response) } +/// Result wrapper for versions list output. +#[derive(serde::Serialize)] +struct ListResult { + #[serde(flatten)] + data: client::datasets::VersionsResponse, +} + +impl std::fmt::Display for ListResult { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + writeln!(f, "Dataset: {}/{}", self.data.namespace, self.data.name)?; + writeln!(f)?; + + if let Some(latest) = &self.data.special_tags.latest { + writeln!(f, "Latest version: {}", latest)?; + } + if let Some(dev) = &self.data.special_tags.dev { + writeln!(f, "Dev hash: {}", dev)?; + } + + if self.data.versions.is_empty() { + writeln!(f, "\nNo versions found")?; + } else { + writeln!(f, "\nVersions:")?; + for version in &self.data.versions { + writeln!(f, " {} ({})", version.version, version.manifest_hash)?; + writeln!(f, " Created: {}", version.created_at)?; + writeln!(f, " Updated: {}", version.updated_at)?; + } + } + Ok(()) + } +} + /// Errors for dataset versions listing operations. #[derive(Debug, thiserror::Error)] pub enum Error { diff --git a/crates/bin/ampctl/src/cmd/job/inspect.rs b/crates/bin/ampctl/src/cmd/job/inspect.rs index 5e833af49..80eeba358 100644 --- a/crates/bin/ampctl/src/cmd/job/inspect.rs +++ b/crates/bin/ampctl/src/cmd/job/inspect.rs @@ -25,28 +25,6 @@ pub struct Args { pub id: JobId, } -/// Result wrapper for job inspect output. -#[derive(serde::Serialize)] -struct InspectResult { - #[serde(flatten)] - data: client::jobs::JobInfo, -} - -impl std::fmt::Display for InspectResult { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - writeln!(f, "Job ID: {}", self.data.id)?; - writeln!(f, "Status: {}", self.data.status)?; - writeln!(f, "Worker: {}", self.data.node_id)?; - writeln!(f, "Created: {}", self.data.created_at)?; - writeln!(f, "Updated: {}", self.data.updated_at)?; - writeln!(f)?; - writeln!(f, "Descriptor:")?; - let descriptor_json = - serde_json::to_string_pretty(&self.data.descriptor).map_err(|_| std::fmt::Error)?; - write!(f, "{}", descriptor_json) - } -} - /// Inspect job details by retrieving them from the admin API. /// /// Retrieves job information and displays it based on the output format. @@ -83,6 +61,28 @@ async fn get_job(global: &GlobalArgs, id: JobId) -> Result std::fmt::Result { + writeln!(f, "Job ID: {}", self.data.id)?; + writeln!(f, "Status: {}", self.data.status)?; + writeln!(f, "Worker: {}", self.data.node_id)?; + writeln!(f, "Created: {}", self.data.created_at)?; + writeln!(f, "Updated: {}", self.data.updated_at)?; + writeln!(f)?; + writeln!(f, "Descriptor:")?; + let descriptor_json = + serde_json::to_string_pretty(&self.data.descriptor).map_err(|_| std::fmt::Error)?; + write!(f, "{}", descriptor_json) + } +} + /// Errors for job inspect operations. #[derive(Debug, thiserror::Error)] pub enum Error { diff --git a/crates/bin/ampctl/src/cmd/job/list.rs b/crates/bin/ampctl/src/cmd/job/list.rs index 239cc9ec9..0171f8bee 100644 --- a/crates/bin/ampctl/src/cmd/job/list.rs +++ b/crates/bin/ampctl/src/cmd/job/list.rs @@ -37,52 +37,6 @@ pub struct Args { pub status: String, } -/// Result wrapper for jobs list output. -#[derive(serde::Serialize)] -struct ListResult { - #[serde(flatten)] - data: crate::client::jobs::JobsResponse, -} - -impl std::fmt::Display for ListResult { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - if self.data.jobs.is_empty() { - writeln!(f, "No jobs found") - } else { - writeln!(f, "Jobs:")?; - for job in &self.data.jobs { - writeln!(f, " {} - {} ({})", job.id, job.status, job.node_id)?; - if let Some(descriptor) = show_dataset_descriptor(&job.descriptor) { - writeln!(f, " Descriptor: {descriptor}")?; - } - } - - if let Some(next_cursor) = &self.data.next_cursor { - writeln!(f, "\nNext cursor: {}", next_cursor)?; - } - Ok(()) - } - } -} - -fn show_dataset_descriptor(descriptor: &serde_json::Value) -> Option { - let descriptor: JobDescriptor = serde_json::from_value(descriptor.clone()).ok()?; - match descriptor { - JobDescriptor::MaterializeRaw(desc) => Some(format!( - "materialize-raw {}/{dataset_name}@{hash}", - desc.dataset_namespace, - dataset_name = desc.dataset_name, - hash = &desc.manifest_hash.as_str()[..7], - )), - JobDescriptor::MaterializeDerived(desc) => Some(format!( - "materialize-derived {}/{dataset_name}@{hash}", - desc.dataset_namespace, - dataset_name = desc.dataset_name, - hash = &desc.manifest_hash.as_str()[..7], - )), - } -} - /// List all jobs by retrieving them from the admin API. /// /// Retrieves all jobs with pagination and displays them based on the output format. @@ -134,6 +88,52 @@ async fn get_jobs( Ok(jobs_response) } +/// Result wrapper for jobs list output. +#[derive(serde::Serialize)] +struct ListResult { + #[serde(flatten)] + data: crate::client::jobs::JobsResponse, +} + +impl std::fmt::Display for ListResult { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if self.data.jobs.is_empty() { + writeln!(f, "No jobs found") + } else { + writeln!(f, "Jobs:")?; + for job in &self.data.jobs { + writeln!(f, " {} - {} ({})", job.id, job.status, job.node_id)?; + if let Some(descriptor) = show_dataset_descriptor(&job.descriptor) { + writeln!(f, " Descriptor: {descriptor}")?; + } + } + + if let Some(next_cursor) = &self.data.next_cursor { + writeln!(f, "\nNext cursor: {}", next_cursor)?; + } + Ok(()) + } + } +} + +fn show_dataset_descriptor(descriptor: &serde_json::Value) -> Option { + let descriptor: JobDescriptor = serde_json::from_value(descriptor.clone()).ok()?; + match descriptor { + JobDescriptor::MaterializeRaw(desc) => Some(format!( + "materialize-raw {}/{dataset_name}@{hash}", + desc.dataset_namespace, + dataset_name = desc.dataset_name, + hash = &desc.manifest_hash.as_str()[..7], + )), + JobDescriptor::MaterializeDerived(desc) => Some(format!( + "materialize-derived {}/{dataset_name}@{hash}", + desc.dataset_namespace, + dataset_name = desc.dataset_name, + hash = &desc.manifest_hash.as_str()[..7], + )), + } +} + /// Errors for jobs listing operations. #[derive(Debug, thiserror::Error)] pub enum Error { diff --git a/crates/bin/ampctl/src/cmd/job/progress.rs b/crates/bin/ampctl/src/cmd/job/progress.rs index 503188d5e..3f6ab83e9 100644 --- a/crates/bin/ampctl/src/cmd/job/progress.rs +++ b/crates/bin/ampctl/src/cmd/job/progress.rs @@ -62,38 +62,6 @@ async fn get_progress(global: &GlobalArgs, id: JobId) -> Result String { format!("{} B", bytes) } } + +/// Errors for job progress operations. +#[derive(Debug, thiserror::Error)] +pub enum Error { + /// Failed to build admin API client + /// + /// This occurs when the client configuration is invalid or the admin URL + /// is malformed. + #[error("failed to build admin API client")] + ClientBuild(#[source] crate::args::BuildClientError), + + /// Client error from the API + /// + /// This wraps errors returned by the admin API client, including network + /// failures, invalid responses, and server errors. + #[error("client error")] + ClientError(#[source] crate::client::jobs::GetProgressError), + + /// Job not found in the system + /// + /// The specified job ID does not exist in the metadata database. + /// Verify the job ID is correct using `ampctl job list`. + #[error("job not found: {id}")] + JobNotFound { id: JobId }, + + /// Failed to format output as JSON + /// + /// This occurs when serializing the progress result to JSON fails, + /// which is unexpected for well-formed data structures. + #[error("failed to format output")] + JsonFormattingError(#[source] serde_json::Error), +} diff --git a/crates/bin/ampctl/src/cmd/job/prune.rs b/crates/bin/ampctl/src/cmd/job/prune.rs index f300ef186..60a54d079 100644 --- a/crates/bin/ampctl/src/cmd/job/prune.rs +++ b/crates/bin/ampctl/src/cmd/job/prune.rs @@ -34,22 +34,6 @@ pub struct Args { pub status: Option, } -/// Result of a job pruning operation. -#[derive(serde::Serialize)] -struct PruneResult { - status_filter: Option, -} - -impl std::fmt::Display for PruneResult { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - let message = match &self.status_filter { - None => "Terminal jobs pruned".to_string(), - Some(filter) => format!("Jobs with status \"{}\" pruned", filter), - }; - writeln!(f, "{} {}", console::style("✓").green().bold(), message) - } -} - /// Prune jobs via the admin API. /// /// Deletes jobs in bulk, optionally filtered by status. @@ -88,6 +72,22 @@ async fn prune_jobs( Ok(()) } +/// Result of a job pruning operation. +#[derive(serde::Serialize)] +struct PruneResult { + status_filter: Option, +} + +impl std::fmt::Display for PruneResult { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let message = match &self.status_filter { + None => "Terminal jobs pruned".to_string(), + Some(filter) => format!("Jobs with status \"{}\" pruned", filter), + }; + writeln!(f, "{} {}", console::style("✓").green().bold(), message) + } +} + /// Errors for job pruning operations. #[derive(Debug, thiserror::Error)] pub enum Error { diff --git a/crates/bin/ampctl/src/cmd/job/rm.rs b/crates/bin/ampctl/src/cmd/job/rm.rs index 67ea045b4..8504891b3 100644 --- a/crates/bin/ampctl/src/cmd/job/rm.rs +++ b/crates/bin/ampctl/src/cmd/job/rm.rs @@ -27,23 +27,6 @@ pub struct Args { pub id: JobId, } -/// Result of a job removal operation. -#[derive(serde::Serialize)] -struct RemoveResult { - job_id: JobId, -} - -impl std::fmt::Display for RemoveResult { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - writeln!( - f, - "{} Job {} removed", - console::style("✓").green().bold(), - self.job_id - ) - } -} - /// Remove a job by deleting it via the admin API. /// /// # Errors @@ -65,6 +48,23 @@ pub async fn run(Args { global, id }: Args) -> Result<(), Error> { Ok(()) } +/// Result of a job removal operation. +#[derive(serde::Serialize)] +struct RemoveResult { + job_id: JobId, +} + +impl std::fmt::Display for RemoveResult { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + writeln!( + f, + "{} Job {} removed", + console::style("✓").green().bold(), + self.job_id + ) + } +} + /// Errors for job rm operations. #[derive(Debug, thiserror::Error)] pub enum Error { diff --git a/crates/bin/ampctl/src/cmd/job/stop.rs b/crates/bin/ampctl/src/cmd/job/stop.rs index 5fce06bb0..8e09f81d5 100644 --- a/crates/bin/ampctl/src/cmd/job/stop.rs +++ b/crates/bin/ampctl/src/cmd/job/stop.rs @@ -25,23 +25,6 @@ pub struct Args { pub id: JobId, } -/// Result of a job stop operation. -#[derive(serde::Serialize)] -struct StopResult { - job_id: JobId, -} - -impl std::fmt::Display for StopResult { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - writeln!( - f, - "{} Job {} stop requested", - console::style("✓").green().bold(), - self.job_id - ) - } -} - /// Stop a job by requesting it to stop via the admin API. /// /// # Errors @@ -66,6 +49,23 @@ pub async fn run(Args { global, id }: Args) -> Result<(), Error> { Ok(()) } +/// Result of a job stop operation. +#[derive(serde::Serialize)] +struct StopResult { + job_id: JobId, +} + +impl std::fmt::Display for StopResult { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + writeln!( + f, + "{} Job {} stop requested", + console::style("✓").green().bold(), + self.job_id + ) + } +} + /// Errors for job stop operations. #[derive(Debug, thiserror::Error)] pub enum Error { diff --git a/crates/bin/ampctl/src/cmd/manifest/inspect.rs b/crates/bin/ampctl/src/cmd/manifest/inspect.rs index aaa55daa3..df6c8444a 100644 --- a/crates/bin/ampctl/src/cmd/manifest/inspect.rs +++ b/crates/bin/ampctl/src/cmd/manifest/inspect.rs @@ -25,21 +25,6 @@ pub struct Args { pub hash: Hash, } -/// Result wrapper for manifest inspect output. -#[derive(serde::Serialize)] -struct InspectResult { - #[serde(flatten)] - data: serde_json::Value, -} - -impl std::fmt::Display for InspectResult { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - // For manifest inspect, output pretty JSON as manifests are complex nested structures - let json = serde_json::to_string_pretty(&self.data).map_err(|_| std::fmt::Error)?; - write!(f, "{}", json) - } -} - /// Inspect a manifest by retrieving it from content-addressable storage via the admin API. /// /// Retrieves manifest content and displays it based on the output format. @@ -87,6 +72,21 @@ async fn get_manifest_value(global: &GlobalArgs, hash: &Hash) -> Result std::fmt::Result { + // For manifest inspect, output pretty JSON as manifests are complex nested structures + let json = serde_json::to_string_pretty(&self.data).map_err(|_| std::fmt::Error)?; + write!(f, "{}", json) + } +} + /// Errors for manifest inspection operations. #[derive(Debug, thiserror::Error)] pub enum Error { diff --git a/crates/bin/ampctl/src/cmd/manifest/list.rs b/crates/bin/ampctl/src/cmd/manifest/list.rs index 23b58b852..257e50132 100644 --- a/crates/bin/ampctl/src/cmd/manifest/list.rs +++ b/crates/bin/ampctl/src/cmd/manifest/list.rs @@ -21,31 +21,6 @@ pub struct Args { pub global: GlobalArgs, } -/// Result wrapper for manifests list output. -#[derive(serde::Serialize)] -struct ListResult { - manifests: Vec, -} - -impl std::fmt::Display for ListResult { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - if self.manifests.is_empty() { - writeln!(f, "No manifests found") - } else { - writeln!(f, "Manifests:")?; - for manifest in &self.manifests { - let dataset_text = if manifest.dataset_count == 1 { - "1 dataset" - } else { - &format!("{} datasets", manifest.dataset_count) - }; - writeln!(f, " {} - {}", manifest.hash, dataset_text)?; - } - Ok(()) - } - } -} - /// List all manifests by retrieving them from the admin API. /// /// Retrieves all manifests and displays them based on the output format. @@ -81,6 +56,31 @@ async fn get_manifests(global: &GlobalArgs) -> Result, +} + +impl std::fmt::Display for ListResult { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if self.manifests.is_empty() { + writeln!(f, "No manifests found") + } else { + writeln!(f, "Manifests:")?; + for manifest in &self.manifests { + let dataset_text = if manifest.dataset_count == 1 { + "1 dataset" + } else { + &format!("{} datasets", manifest.dataset_count) + }; + writeln!(f, " {} - {}", manifest.hash, dataset_text)?; + } + Ok(()) + } + } +} + /// Errors for manifests listing operations. #[derive(Debug, thiserror::Error)] pub enum Error { diff --git a/crates/bin/ampctl/src/cmd/manifest/prune.rs b/crates/bin/ampctl/src/cmd/manifest/prune.rs index ecb8f5166..9b8ca4f25 100644 --- a/crates/bin/ampctl/src/cmd/manifest/prune.rs +++ b/crates/bin/ampctl/src/cmd/manifest/prune.rs @@ -22,23 +22,6 @@ pub struct Args { pub global: GlobalArgs, } -/// Result of a manifest pruning operation. -#[derive(serde::Serialize)] -struct PruneResult { - deleted_count: usize, -} - -impl std::fmt::Display for PruneResult { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - writeln!( - f, - "{} Pruned {} orphaned manifest(s)", - console::style("✓").green().bold(), - self.deleted_count - ) - } -} - /// Prune all orphaned manifests via the admin API. /// /// Deletes all manifests that are not linked to any datasets. @@ -80,6 +63,23 @@ async fn prune_manifests(global: &GlobalArgs) -> Result { Ok(response.deleted_count) } +/// Result of a manifest pruning operation. +#[derive(serde::Serialize)] +struct PruneResult { + deleted_count: usize, +} + +impl std::fmt::Display for PruneResult { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + writeln!( + f, + "{} Pruned {} orphaned manifest(s)", + console::style("✓").green().bold(), + self.deleted_count + ) + } +} + /// Errors for manifest pruning operations. #[derive(Debug, thiserror::Error)] pub enum Error { diff --git a/crates/bin/ampctl/src/cmd/manifest/register.rs b/crates/bin/ampctl/src/cmd/manifest/register.rs index 1da8a927e..54a564f56 100644 --- a/crates/bin/ampctl/src/cmd/manifest/register.rs +++ b/crates/bin/ampctl/src/cmd/manifest/register.rs @@ -39,28 +39,6 @@ pub struct Args { pub manifest_file: ManifestFilePath, } -/// Result of a manifest registration operation. -#[derive(serde::Serialize)] -struct RegisterResult { - hash: String, -} - -impl std::fmt::Display for RegisterResult { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - writeln!( - f, - "{} Manifest registered successfully", - console::style("✓").green().bold() - )?; - writeln!( - f, - "{} Manifest hash: {}", - console::style("→").cyan(), - self.hash - ) - } -} - /// Register a manifest with content-addressable storage via the admin API. /// /// Loads manifest content from storage and POSTs to `/manifests` endpoint. @@ -146,6 +124,28 @@ pub async fn register_manifest(global: &GlobalArgs, manifest_str: &str) -> Resul .map_err(Error::RegisterError) } +/// Result of a manifest registration operation. +#[derive(serde::Serialize)] +struct RegisterResult { + hash: String, +} + +impl std::fmt::Display for RegisterResult { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + writeln!( + f, + "{} Manifest registered successfully", + console::style("✓").green().bold() + )?; + writeln!( + f, + "{} Manifest hash: {}", + console::style("→").cyan(), + self.hash + ) + } +} + /// Errors for manifest registration operations. #[derive(Debug, thiserror::Error)] pub enum Error { diff --git a/crates/bin/ampctl/src/cmd/manifest/remove.rs b/crates/bin/ampctl/src/cmd/manifest/remove.rs index f9cc50ab6..6fe254dec 100644 --- a/crates/bin/ampctl/src/cmd/manifest/remove.rs +++ b/crates/bin/ampctl/src/cmd/manifest/remove.rs @@ -27,22 +27,6 @@ pub struct Args { pub hash: Hash, } -/// Result of a manifest removal operation. -#[derive(serde::Serialize)] -struct RemoveResult { - hash: String, -} - -impl std::fmt::Display for RemoveResult { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - writeln!( - f, - "{} Manifest deleted successfully", - console::style("✓").green().bold() - ) - } -} - /// Remove a manifest from content-addressable storage via the admin API. /// /// Deletes the manifest if it is not linked to any datasets. @@ -112,6 +96,22 @@ async fn delete_manifest(global: &GlobalArgs, hash: &Hash) -> Result<(), Error> }) } +/// Result of a manifest removal operation. +#[derive(serde::Serialize)] +struct RemoveResult { + hash: String, +} + +impl std::fmt::Display for RemoveResult { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + writeln!( + f, + "{} Manifest deleted successfully", + console::style("✓").green().bold() + ) + } +} + /// Errors for manifest removal operations. #[derive(Debug, thiserror::Error)] pub enum Error { diff --git a/crates/bin/ampctl/src/cmd/provider/inspect.rs b/crates/bin/ampctl/src/cmd/provider/inspect.rs index 0ee2e62cb..1dffeeaac 100644 --- a/crates/bin/ampctl/src/cmd/provider/inspect.rs +++ b/crates/bin/ampctl/src/cmd/provider/inspect.rs @@ -23,21 +23,6 @@ pub struct Args { pub name: String, } -/// Result wrapper for provider inspect output. -#[derive(serde::Serialize)] -struct InspectResult { - #[serde(flatten)] - data: serde_json::Value, -} - -impl std::fmt::Display for InspectResult { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - // For provider inspect, output pretty JSON as provider configs are complex nested structures - let json = serde_json::to_string_pretty(&self.data).map_err(|_| std::fmt::Error)?; - write!(f, "{}", json) - } -} - /// Inspect a provider by retrieving it from the admin API. /// /// Retrieves provider configuration and displays it based on the output format. @@ -83,6 +68,21 @@ async fn get_provider_value(global: &GlobalArgs, name: &str) -> Result std::fmt::Result { + // For provider inspect, output pretty JSON as provider configs are complex nested structures + let json = serde_json::to_string_pretty(&self.data).map_err(|_| std::fmt::Error)?; + write!(f, "{}", json) + } +} + /// Errors for provider inspection operations. #[derive(Debug, thiserror::Error)] pub enum Error { diff --git a/crates/bin/ampctl/src/cmd/provider/list.rs b/crates/bin/ampctl/src/cmd/provider/list.rs index 1a947462f..86f1bd744 100644 --- a/crates/bin/ampctl/src/cmd/provider/list.rs +++ b/crates/bin/ampctl/src/cmd/provider/list.rs @@ -21,26 +21,6 @@ pub struct Args { pub global: GlobalArgs, } -/// Result wrapper for providers list output. -#[derive(serde::Serialize)] -struct ListResult { - providers: Vec, -} - -impl std::fmt::Display for ListResult { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - if self.providers.is_empty() { - writeln!(f, "No providers found") - } else { - writeln!(f, "Providers:")?; - for provider in &self.providers { - writeln!(f, " {} ({})", provider.name, provider.kind)?; - } - Ok(()) - } - } -} - /// List all providers by retrieving them from the admin API. /// /// Retrieves all provider configurations and displays them based on the output format. @@ -74,6 +54,26 @@ async fn get_providers(global: &GlobalArgs) -> Result, +} + +impl std::fmt::Display for ListResult { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if self.providers.is_empty() { + writeln!(f, "No providers found") + } else { + writeln!(f, "Providers:")?; + for provider in &self.providers { + writeln!(f, " {} ({})", provider.name, provider.kind)?; + } + Ok(()) + } + } +} + /// Errors for provider listing operations. #[derive(Debug, thiserror::Error)] pub enum Error { diff --git a/crates/bin/ampctl/src/cmd/provider/register.rs b/crates/bin/ampctl/src/cmd/provider/register.rs index b84367cd9..8cbaa4f62 100644 --- a/crates/bin/ampctl/src/cmd/provider/register.rs +++ b/crates/bin/ampctl/src/cmd/provider/register.rs @@ -45,22 +45,6 @@ pub struct Args { pub provider_file: ProviderFilePath, } -/// Result of a provider registration operation. -#[derive(serde::Serialize)] -struct RegisterResult { - name: String, -} - -impl std::fmt::Display for RegisterResult { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - writeln!( - f, - "{} Provider registered successfully", - console::style("✓").green().bold() - ) - } -} - /// Register a provider configuration via the admin API. /// /// Loads provider TOML content from storage, converts to JSON, and POSTs to `/providers` endpoint. @@ -172,6 +156,22 @@ async fn register_provider( Ok(()) } +/// Result of a provider registration operation. +#[derive(serde::Serialize)] +struct RegisterResult { + name: String, +} + +impl std::fmt::Display for RegisterResult { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + writeln!( + f, + "{} Provider registered successfully", + console::style("✓").green().bold() + ) + } +} + /// Errors for provider registration operations. #[derive(Debug, thiserror::Error)] pub enum Error { diff --git a/crates/bin/ampctl/src/cmd/provider/remove.rs b/crates/bin/ampctl/src/cmd/provider/remove.rs index 82f398109..1ba8e4c0c 100644 --- a/crates/bin/ampctl/src/cmd/provider/remove.rs +++ b/crates/bin/ampctl/src/cmd/provider/remove.rs @@ -25,22 +25,6 @@ pub struct Args { pub name: String, } -/// Result of a provider removal operation. -#[derive(serde::Serialize)] -struct RemoveResult { - name: String, -} - -impl std::fmt::Display for RemoveResult { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - writeln!( - f, - "{} Provider deleted successfully", - console::style("✓").green().bold() - ) - } -} - /// Remove a provider from the admin API. /// /// Deletes the provider configuration if it exists. @@ -88,6 +72,22 @@ async fn delete_provider(global: &GlobalArgs, name: &str) -> Result<(), Error> { }) } +/// Result of a provider removal operation. +#[derive(serde::Serialize)] +struct RemoveResult { + name: String, +} + +impl std::fmt::Display for RemoveResult { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + writeln!( + f, + "{} Provider deleted successfully", + console::style("✓").green().bold() + ) + } +} + /// Errors for provider removal operations. #[derive(Debug, thiserror::Error)] pub enum Error { diff --git a/crates/bin/ampctl/src/cmd/table/list.rs b/crates/bin/ampctl/src/cmd/table/list.rs index cd616802b..143d688e0 100644 --- a/crates/bin/ampctl/src/cmd/table/list.rs +++ b/crates/bin/ampctl/src/cmd/table/list.rs @@ -31,36 +31,6 @@ pub struct Args { pub limit: Option, } -/// Result of a table list operation. -#[derive(serde::Serialize)] -struct ListResult { - revisions: Vec, -} - -impl std::fmt::Display for ListResult { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - if self.revisions.is_empty() { - writeln!(f, "No revisions found") - } else { - writeln!(f, "Revisions ({}):", self.revisions.len())?; - for rev in &self.revisions { - let meta = &rev.metadata; - let active_str = if rev.active { - console::style("active").green().to_string() - } else { - console::style("inactive").red().to_string() - }; - writeln!( - f, - " {} - {}/{} {} [{}]", - rev.id, meta.dataset_namespace, meta.dataset_name, meta.table_name, active_str, - )?; - } - Ok(()) - } - } -} - /// List all table revisions by retrieving them from the admin API. /// /// Retrieves table revisions with optional filtering and displays them based on @@ -113,6 +83,36 @@ async fn get_revisions( Ok(revisions) } +/// Result of a table list operation. +#[derive(serde::Serialize)] +struct ListResult { + revisions: Vec, +} + +impl std::fmt::Display for ListResult { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + if self.revisions.is_empty() { + writeln!(f, "No revisions found") + } else { + writeln!(f, "Revisions ({}):", self.revisions.len())?; + for rev in &self.revisions { + let meta = &rev.metadata; + let active_str = if rev.active { + console::style("active").green().to_string() + } else { + console::style("inactive").red().to_string() + }; + writeln!( + f, + " {} - {}/{} {} [{}]", + rev.id, meta.dataset_namespace, meta.dataset_name, meta.table_name, active_str, + )?; + } + Ok(()) + } + } +} + /// Errors for table revision listing operations. #[derive(Debug, thiserror::Error)] pub enum Error { diff --git a/crates/bin/ampctl/src/cmd/worker/inspect.rs b/crates/bin/ampctl/src/cmd/worker/inspect.rs index 353235bfa..2036c5568 100644 --- a/crates/bin/ampctl/src/cmd/worker/inspect.rs +++ b/crates/bin/ampctl/src/cmd/worker/inspect.rs @@ -26,29 +26,6 @@ pub struct Args { pub node_id: NodeId, } -/// Result wrapper for worker inspect output. -#[derive(serde::Serialize)] -struct InspectResult { - #[serde(flatten)] - data: client::workers::WorkerDetailResponse, -} - -impl std::fmt::Display for InspectResult { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - writeln!(f, "Node ID: {}", self.data.node_id)?; - writeln!(f, "Created: {}", self.data.created_at)?; - writeln!(f, "Registered: {}", self.data.registered_at)?; - writeln!(f, "Heartbeat: {}", self.data.heartbeat_at)?; - writeln!(f)?; - writeln!(f, "Worker Info:")?; - writeln!(f, " Version: {}", self.data.info.version)?; - writeln!(f, " Commit: {}", self.data.info.commit_sha)?; - writeln!(f, " Commit Timestamp: {}", self.data.info.commit_timestamp)?; - writeln!(f, " Build Date: {}", self.data.info.build_date)?; - Ok(()) - } -} - /// Inspect worker details by retrieving them from the admin API. /// /// Retrieves worker information and displays it based on the output format. @@ -90,6 +67,29 @@ async fn get_worker( } } +/// Result wrapper for worker inspect output. +#[derive(serde::Serialize)] +struct InspectResult { + #[serde(flatten)] + data: client::workers::WorkerDetailResponse, +} + +impl std::fmt::Display for InspectResult { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + writeln!(f, "Node ID: {}", self.data.node_id)?; + writeln!(f, "Created: {}", self.data.created_at)?; + writeln!(f, "Registered: {}", self.data.registered_at)?; + writeln!(f, "Heartbeat: {}", self.data.heartbeat_at)?; + writeln!(f)?; + writeln!(f, "Worker Info:")?; + writeln!(f, " Version: {}", self.data.info.version)?; + writeln!(f, " Commit: {}", self.data.info.commit_sha)?; + writeln!(f, " Commit Timestamp: {}", self.data.info.commit_timestamp)?; + writeln!(f, " Build Date: {}", self.data.info.build_date)?; + Ok(()) + } +} + /// Errors for worker inspect operations. #[derive(Debug, thiserror::Error)] pub enum Error { diff --git a/crates/bin/ampctl/src/cmd/worker/list.rs b/crates/bin/ampctl/src/cmd/worker/list.rs index e1578aa93..bf1dbf8c8 100644 --- a/crates/bin/ampctl/src/cmd/worker/list.rs +++ b/crates/bin/ampctl/src/cmd/worker/list.rs @@ -21,31 +21,6 @@ pub struct Args { pub global: GlobalArgs, } -/// Result wrapper for workers list output. -#[derive(serde::Serialize)] -struct ListResult { - #[serde(flatten)] - data: client::workers::WorkersResponse, -} - -impl std::fmt::Display for ListResult { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - if self.data.workers.is_empty() { - writeln!(f, "No workers found") - } else { - writeln!(f, "Workers:")?; - for worker in &self.data.workers { - writeln!( - f, - " {} (last heartbeat: {})", - worker.node_id, worker.heartbeat_at - )?; - } - Ok(()) - } - } -} - /// List all workers by retrieving them from the admin API. /// /// Retrieves all workers and displays them based on the output format. @@ -81,6 +56,31 @@ async fn get_workers(global: &GlobalArgs) -> Result std::fmt::Result { + if self.data.workers.is_empty() { + writeln!(f, "No workers found") + } else { + writeln!(f, "Workers:")?; + for worker in &self.data.workers { + writeln!( + f, + " {} (last heartbeat: {})", + worker.node_id, worker.heartbeat_at + )?; + } + Ok(()) + } + } +} + /// Errors for workers listing operations. #[derive(Debug, thiserror::Error)] pub enum Error {