From c5ac33755b6eaddb140c62c072a888596ab70314 Mon Sep 17 00:00:00 2001 From: itowlson Date: Tue, 12 Dec 2023 15:58:00 +1300 Subject: [PATCH] Fix double backslashes in printed Windows paths Signed-off-by: itowlson --- Cargo.lock | 1 + crates/build/src/lib.rs | 11 +++++-- crates/common/src/lib.rs | 1 + crates/common/src/paths.rs | 4 ++- crates/common/src/ui.rs | 10 ++++++ crates/doctor/src/lib.rs | 23 +++++++++---- crates/doctor/src/manifest.rs | 8 +++-- crates/doctor/src/manifest/upgrade.rs | 6 +++- crates/doctor/src/wasm/missing.rs | 6 +++- crates/llm-local/Cargo.toml | 1 + crates/llm-local/src/lib.rs | 11 +++++-- crates/loader/src/local.rs | 33 ++++++++++++------- crates/oci/src/auth.rs | 5 +-- crates/oci/src/client.rs | 11 +++++-- crates/oci/src/loader.rs | 16 ++++++--- crates/oci/src/utils.rs | 9 ++--- crates/trigger/src/loader.rs | 13 ++++---- crates/trigger/src/runtime_config.rs | 16 ++++++--- .../trigger/src/runtime_config/key_value.rs | 3 +- crates/trigger/src/runtime_config/sqlite.rs | 3 +- crates/trigger/src/stdio.rs | 7 ++-- src/commands/up.rs | 12 +++++-- src/commands/up/app_source.rs | 3 +- 23 files changed, 151 insertions(+), 62 deletions(-) create mode 100644 crates/common/src/ui.rs diff --git a/Cargo.lock b/Cargo.lock index 511133002..e081e5eed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5910,6 +5910,7 @@ dependencies = [ "rand 0.8.5", "safetensors", "serde", + "spin-common", "spin-core", "spin-llm", "spin-world", diff --git a/crates/build/src/lib.rs b/crates/build/src/lib.rs index 99c5ed9a9..202dafda6 100644 --- a/crates/build/src/lib.rs +++ b/crates/build/src/lib.rs @@ -6,7 +6,7 @@ mod manifest; use anyhow::{anyhow, bail, Context, Result}; use manifest::ComponentBuildInfo; -use spin_common::paths::parent_dir; +use spin_common::{paths::parent_dir, ui::quoted_path}; use std::{ collections::HashSet, path::{Path, PathBuf}, @@ -19,7 +19,12 @@ use crate::manifest::component_build_configs; pub async fn build(manifest_file: &Path, component_ids: &[String]) -> Result<()> { let components = component_build_configs(manifest_file) .await - .with_context(|| format!("Cannot read manifest file from {}", manifest_file.display()))?; + .with_context(|| { + format!( + "Cannot read manifest file from {}", + quoted_path(manifest_file) + ) + })?; let app_dir = parent_dir(manifest_file)?; let components_to_build = if component_ids.is_empty() { @@ -69,7 +74,7 @@ fn build_component(build_info: ComponentBuildInfo, app_dir: &Path) -> Result<()> ); let workdir = construct_workdir(app_dir, b.workdir.as_ref())?; if b.workdir.is_some() { - println!("Working directory: {:?}", workdir); + println!("Working directory: {}", quoted_path(&workdir)); } let exit_status = Exec::shell(&b.command) diff --git a/crates/common/src/lib.rs b/crates/common/src/lib.rs index fda38b623..f747d1544 100644 --- a/crates/common/src/lib.rs +++ b/crates/common/src/lib.rs @@ -13,4 +13,5 @@ pub mod data_dir; pub mod paths; pub mod sha256; pub mod sloth; +pub mod ui; pub mod url; diff --git a/crates/common/src/paths.rs b/crates/common/src/paths.rs index 93cc67e4c..cbe6f3920 100644 --- a/crates/common/src/paths.rs +++ b/crates/common/src/paths.rs @@ -3,6 +3,8 @@ use anyhow::{anyhow, Context, Result}; use std::path::{Path, PathBuf}; +use crate::ui::quoted_path; + /// The name given to the default manifest file. pub const DEFAULT_MANIFEST_FILE: &str = "spin.toml"; @@ -40,7 +42,7 @@ pub fn parent_dir(path: impl AsRef) -> Result { let path = path.as_ref(); let mut parent = path .parent() - .with_context(|| format!("No parent directory for path {path:?}"))?; + .with_context(|| format!("No parent directory for path {}", quoted_path(path)))?; if parent == Path::new("") { parent = Path::new("."); } diff --git a/crates/common/src/ui.rs b/crates/common/src/ui.rs new file mode 100644 index 000000000..a56022379 --- /dev/null +++ b/crates/common/src/ui.rs @@ -0,0 +1,10 @@ +//! Functions supporting common UI behaviour and standards + +use std::path::Path; + +/// Renders a Path with double quotes. This is the standard +/// for displaying paths in Spin. It is preferred to the Debug +/// format because the latter doubles up backlashes on Windows. +pub fn quoted_path(path: impl AsRef) -> impl std::fmt::Display { + format!("\"{}\"", path.as_ref().display()) +} diff --git a/crates/doctor/src/lib.rs b/crates/doctor/src/lib.rs index b006daee1..7fbd000e5 100644 --- a/crates/doctor/src/lib.rs +++ b/crates/doctor/src/lib.rs @@ -5,6 +5,7 @@ use std::{collections::VecDeque, fmt::Debug, fs, path::PathBuf}; use anyhow::{ensure, Context, Result}; use async_trait::async_trait; +use spin_common::ui::quoted_path; use toml_edit::Document; /// Diagnoses for app manifest format problems. @@ -88,15 +89,23 @@ impl PatientApp { let path = manifest_path.into(); ensure!( path.is_file(), - "No Spin app manifest file found at {path:?}" + "No Spin app manifest file found at {}", + quoted_path(&path), ); - let contents = fs::read_to_string(&path) - .with_context(|| format!("Couldn't read Spin app manifest file at {path:?}"))?; - - let manifest_doc: Document = contents - .parse() - .with_context(|| format!("Couldn't parse manifest file at {path:?} as valid TOML"))?; + let contents = fs::read_to_string(&path).with_context(|| { + format!( + "Couldn't read Spin app manifest file at {}", + quoted_path(&path) + ) + })?; + + let manifest_doc: Document = contents.parse().with_context(|| { + format!( + "Couldn't parse manifest file at {} as valid TOML", + quoted_path(&path) + ) + })?; Ok(Self { manifest_path: path, diff --git a/crates/doctor/src/manifest.rs b/crates/doctor/src/manifest.rs index 56ef77294..c61364fdf 100644 --- a/crates/doctor/src/manifest.rs +++ b/crates/doctor/src/manifest.rs @@ -2,6 +2,7 @@ use std::fs; use anyhow::{Context, Result}; use async_trait::async_trait; +use spin_common::ui::quoted_path; use toml_edit::Document; use crate::Treatment; @@ -37,8 +38,9 @@ impl Treatment for T { let after = after_doc.to_string(); let diff = similar::udiff::unified_diff(Default::default(), &before, &after, 1, None); Ok(format!( - "Apply the following diff to {:?}:\n{}", - patient.manifest_path, diff + "Apply the following diff to {}:\n{}", + quoted_path(&patient.manifest_path), + diff )) } @@ -47,6 +49,6 @@ impl Treatment for T { self.treat_manifest(doc).await?; let path = &patient.manifest_path; fs::write(path, doc.to_string()) - .with_context(|| format!("failed to write fixed manifest to {path:?}")) + .with_context(|| format!("failed to write fixed manifest to {}", quoted_path(path))) } } diff --git a/crates/doctor/src/manifest/upgrade.rs b/crates/doctor/src/manifest/upgrade.rs index 6da431084..30a6685bd 100644 --- a/crates/doctor/src/manifest/upgrade.rs +++ b/crates/doctor/src/manifest/upgrade.rs @@ -1,5 +1,6 @@ use anyhow::{anyhow, Context, Result}; use async_trait::async_trait; +use spin_common::ui::quoted_path; use spin_manifest::{compat::v1_to_v2_app, schema::v1::AppManifestV1, ManifestVersion}; use toml_edit::{de::from_document, ser::to_document, Item, Table}; @@ -97,7 +98,10 @@ impl Treatment for UpgradeDiagnosis { let v1_backup_path = patient.manifest_path.with_extension("toml.v1_backup"); std::fs::rename(&patient.manifest_path, &v1_backup_path) .context("failed to back up existing manifest")?; - println!("Version 1 manifest backed up to {v1_backup_path:?}."); + println!( + "Version 1 manifest backed up to {}.", + quoted_path(&v1_backup_path) + ); // Write new V2 manifest std::fs::write(&patient.manifest_path, v2_doc.to_string()) diff --git a/crates/doctor/src/wasm/missing.rs b/crates/doctor/src/wasm/missing.rs index 2af79a766..7759c7941 100644 --- a/crates/doctor/src/wasm/missing.rs +++ b/crates/doctor/src/wasm/missing.rs @@ -2,6 +2,7 @@ use std::process::Command; use anyhow::{ensure, Context, Result}; use async_trait::async_trait; +use spin_common::ui::quoted_path; use crate::{Diagnosis, PatientApp, Treatment}; @@ -52,7 +53,10 @@ impl Diagnosis for WasmMissing { let Some(rel_path) = self.0.source_path() else { unreachable!("unsupported source"); }; - format!("Component {id:?} source {rel_path:?} is missing") + format!( + "Component {id:?} source {} is missing", + quoted_path(rel_path) + ) } fn treatment(&self) -> Option<&dyn Treatment> { diff --git a/crates/llm-local/Cargo.toml b/crates/llm-local/Cargo.toml index 1fb4c6588..09d0b9485 100644 --- a/crates/llm-local/Cargo.toml +++ b/crates/llm-local/Cargo.toml @@ -18,6 +18,7 @@ num_cpus = "1" rand = "0.8.5" safetensors = "0.3.3" serde = { version = "1.0.150", features = ["derive"] } +spin-common = { path = "../common" } spin-core = { path = "../core" } spin-llm = { path = "../llm" } spin-world = { path = "../world" } diff --git a/crates/llm-local/src/lib.rs b/crates/llm-local/src/lib.rs index 60e1b7c02..120f9e4df 100644 --- a/crates/llm-local/src/lib.rs +++ b/crates/llm-local/src/lib.rs @@ -9,6 +9,7 @@ use llm::{ ModelArchitecture, ModelKVMemoryType, ModelParameters, }; use rand::SeedableRng; +use spin_common::ui::quoted_path; use spin_core::async_trait; use spin_llm::{LlmEngine, MODEL_ALL_MINILM_L6_V2}; use spin_world::v2::llm::{self as wasi_llm}; @@ -376,14 +377,18 @@ async fn generate_embeddings( } fn load_tokenizer(tokenizer_file: &Path) -> anyhow::Result { - let tokenizer = tokenizers::Tokenizer::from_file(tokenizer_file) - .map_err(|e| anyhow::anyhow!("Failed to read tokenizer file {tokenizer_file:?}: {e}"))?; + let tokenizer = tokenizers::Tokenizer::from_file(tokenizer_file).map_err(|e| { + anyhow::anyhow!( + "Failed to read tokenizer file {}: {e}", + quoted_path(tokenizer_file) + ) + })?; Ok(tokenizer) } fn load_model(model_file: &Path) -> anyhow::Result { let buffer = std::fs::read(model_file) - .with_context(|| format!("Failed to read model file {model_file:?}"))?; + .with_context(|| format!("Failed to read model file {}", quoted_path(model_file)))?; let weights = safetensors::SafeTensors::deserialize(&buffer)?; let vb = VarBuilder::from_safetensors(vec![weights], DType::F32, &candle::Device::Cpu); let model = BertModel::load(vb, &Config::default()).context("error loading bert model")?; diff --git a/crates/loader/src/local.rs b/crates/loader/src/local.rs index ddea5ab7a..f646f2218 100644 --- a/crates/loader/src/local.rs +++ b/crates/loader/src/local.rs @@ -3,7 +3,7 @@ use std::path::{Path, PathBuf}; use anyhow::{bail, ensure, Context, Result}; use futures::future::try_join_all; use reqwest::Url; -use spin_common::paths::parent_dir; +use spin_common::{paths::parent_dir, ui::quoted_path}; use spin_locked_app::{ locked::{ self, ContentPath, ContentRef, LockedApp, LockedComponent, LockedComponentSource, @@ -47,12 +47,16 @@ impl LocalLoader { pub async fn load_file(&self, path: impl AsRef) -> Result { // Parse manifest let path = path.as_ref(); - let manifest = spin_manifest::manifest_from_file(path) - .with_context(|| format!("Failed to read Spin app manifest from {path:?}"))?; + let manifest = spin_manifest::manifest_from_file(path).with_context(|| { + format!( + "Failed to read Spin app manifest from {}", + quoted_path(path) + ) + })?; let mut locked = self .load_manifest(manifest) .await - .with_context(|| format!("Failed to load Spin app from {path:?}"))?; + .with_context(|| format!("Failed to load Spin app from {}", quoted_path(path)))?; // Set origin metadata locked @@ -286,7 +290,7 @@ impl LocalLoader { let src_path = self.app_root.join(src); let meta = fs::metadata(&src_path) .await - .with_context(|| format!("invalid file mount source {src:?}"))?; + .with_context(|| format!("invalid file mount source {}", quoted_path(src)))?; if meta.is_dir() { // { source = "host/dir", destination = "guest/dir" } let pattern = src_path.join("**/*"); @@ -359,12 +363,19 @@ impl LocalLoader { let _loading_permit = self.file_loading_permits.acquire().await?; let dest_parent = parent_dir(dest)?; - fs::create_dir_all(&dest_parent) - .await - .with_context(|| format!("Failed to create parent directory {dest_parent:?}"))?; - fs::copy(src, dest) - .await - .with_context(|| format!("Failed to copy {src:?} to {dest:?}"))?; + fs::create_dir_all(&dest_parent).await.with_context(|| { + format!( + "Failed to create parent directory {}", + quoted_path(&dest_parent) + ) + })?; + fs::copy(src, dest).await.with_context(|| { + format!( + "Failed to copy {} to {}", + quoted_path(src), + quoted_path(dest) + ) + })?; tracing::debug!("Copied {src:?} to {dest:?}"); Ok(()) } diff --git a/crates/oci/src/auth.rs b/crates/oci/src/auth.rs index fdfe7092a..6a1a782eb 100644 --- a/crates/oci/src/auth.rs +++ b/crates/oci/src/auth.rs @@ -6,6 +6,7 @@ use std::{ use anyhow::{bail, Context, Result}; use oci_distribution::secrets::RegistryAuth; use serde::{Deserialize, Serialize}; +use spin_common::ui::quoted_path; #[derive(Serialize, Deserialize)] pub struct AuthConfig { @@ -84,7 +85,7 @@ impl AuthConfig { async fn load(p: &Path) -> Result { let contents = tokio::fs::read_to_string(&p).await?; serde_json::from_str(&contents) - .with_context(|| format!("cannot load authentication file {:?}", p)) + .with_context(|| format!("cannot load authentication file {}", quoted_path(p))) } async fn save(&self, p: &Path) -> Result<()> { @@ -95,6 +96,6 @@ impl AuthConfig { } tokio::fs::write(&p, &serde_json::to_vec_pretty(&self)?) .await - .with_context(|| format!("cannot save authentication file {:?}", p)) + .with_context(|| format!("cannot save authentication file {}", quoted_path(p))) } } diff --git a/crates/oci/src/client.rs b/crates/oci/src/client.rs index 8bdb58a43..2aad53fa3 100644 --- a/crates/oci/src/client.rs +++ b/crates/oci/src/client.rs @@ -12,6 +12,7 @@ use oci_distribution::{ }; use reqwest::Url; use spin_common::sha256; +use spin_common::ui::quoted_path; use spin_common::url::parse_file_url; use spin_loader::cache::Cache; use spin_loader::FilesMountStrategy; @@ -148,11 +149,17 @@ impl Client { if archive_layers { self.push_archive_layer(&source, &mut files, &mut layers) .await - .context(format!("cannot push archive layer for source {:?}", source))?; + .context(format!( + "cannot push archive layer for source {}", + quoted_path(&source) + ))?; } else { self.push_file_layers(&source, &mut files, &mut layers) .await - .context(format!("cannot push file layers for source {:?}", source))?; + .context(format!( + "cannot push file layers for source {}", + quoted_path(&source) + ))?; } } c.files = files; diff --git a/crates/oci/src/loader.rs b/crates/oci/src/loader.rs index 9b4b5a2c4..c5dd21e97 100644 --- a/crates/oci/src/loader.rs +++ b/crates/oci/src/loader.rs @@ -3,6 +3,7 @@ use std::path::{Path, PathBuf}; use anyhow::{anyhow, ensure, Context, Result}; use oci_distribution::Reference; use reqwest::Url; +use spin_common::ui::quoted_path; use spin_loader::cache::Cache; use spin_locked_app::locked::{ContentPath, ContentRef, LockedApp, LockedComponent}; @@ -46,9 +47,13 @@ impl OciLoader { ) -> std::result::Result { let locked_content = tokio::fs::read(&lockfile_path) .await - .with_context(|| format!("failed to read from {lockfile_path:?}"))?; - let mut locked_app = LockedApp::from_json(&locked_content) - .with_context(|| format!("failed to decode locked app from {lockfile_path:?}"))?; + .with_context(|| format!("failed to read from {}", quoted_path(&lockfile_path)))?; + let mut locked_app = LockedApp::from_json(&locked_content).with_context(|| { + format!( + "failed to decode locked app from {}", + quoted_path(&lockfile_path) + ) + })?; // Update origin metadata let resolved_reference = Reference::try_from(reference).context("invalid reference")?; @@ -108,7 +113,10 @@ impl OciLoader { tokio::fs::copy(&content_path, &mount_path) .await .with_context(|| { - format!("failed to copy {content_path:?}->{mount_path:?}") + format!( + "failed to copy {}->{mount_path:?}", + quoted_path(&content_path) + ) })?; } } diff --git a/crates/oci/src/utils.rs b/crates/oci/src/utils.rs index 832b8e105..a754e2c42 100644 --- a/crates/oci/src/utils.rs +++ b/crates/oci/src/utils.rs @@ -4,6 +4,7 @@ use anyhow::{Context, Result}; use async_compression::tokio::bufread::GzipDecoder; use async_compression::tokio::write::GzipEncoder; use async_tar::Archive; +use spin_common::ui::quoted_path; use std::path::{Path, PathBuf}; /// Create a compressed archive of source, returning its path in working_dir @@ -15,8 +16,8 @@ pub async fn archive(source: &Path, working_dir: &Path) -> Result { let tar_gz = tokio::fs::File::create(tar_gz_path.as_path()) .await .context(format!( - "Unable to create tar archive for source {:?}", - source + "Unable to create tar archive for source {}", + quoted_path(source) ))?; // Create encoder @@ -31,8 +32,8 @@ pub async fn archive(source: &Path, working_dir: &Path) -> Result { .append_dir_all(".", source) .await .context(format!( - "Unable to create tar archive for source {:?}", - source + "Unable to create tar archive for source {}", + quoted_path(source) ))?; // Finish writing the archive tar_builder.finish().await?; diff --git a/crates/trigger/src/loader.rs b/crates/trigger/src/loader.rs index eb8e652f9..0c25d72af 100644 --- a/crates/trigger/src/loader.rs +++ b/crates/trigger/src/loader.rs @@ -11,7 +11,7 @@ use spin_app::{ use spin_core::StoreBuilder; use tokio::fs; -use spin_common::url::parse_file_url; +use spin_common::{ui::quoted_path, url::parse_file_url}; pub struct TriggerLoader { working_dir: PathBuf, @@ -31,8 +31,8 @@ impl TriggerLoader { impl Loader for TriggerLoader { async fn load_app(&self, url: &str) -> Result { let path = parse_file_url(url)?; - let contents = - std::fs::read(&path).with_context(|| format!("failed to read manifest at {path:?}"))?; + let contents = std::fs::read(&path) + .with_context(|| format!("failed to read manifest at {}", quoted_path(&path)))?; let app = serde_json::from_slice(&contents).context("failed to parse app lock file JSON")?; Ok(app) @@ -57,7 +57,7 @@ impl Loader for TriggerLoader { })?; let component = spin_componentize::componentize_if_necessary(&bytes)?; spin_core::Component::new(engine, component.as_ref()) - .with_context(|| format!("loading module {path:?}")) + .with_context(|| format!("loading module {}", quoted_path(&path))) } async fn load_module( @@ -72,7 +72,7 @@ impl Loader for TriggerLoader { .context("LockedComponentSource missing source field")?; let path = parse_file_url(source)?; spin_core::Module::from_file(engine, &path) - .with_context(|| format!("loading module {path:?}")) + .with_context(|| format!("loading module {}", quoted_path(&path))) } async fn mount_files( @@ -89,7 +89,8 @@ impl Loader for TriggerLoader { let source_path = self.working_dir.join(parse_file_url(source_uri)?); ensure!( source_path.is_dir(), - "TriggerLoader only supports directory mounts; {source_path:?} is not a directory" + "TriggerLoader only supports directory mounts; {} is not a directory", + quoted_path(&source_path), ); let guest_path = content_dir.path.clone(); if self.allow_transient_write { diff --git a/crates/trigger/src/runtime_config.rs b/crates/trigger/src/runtime_config.rs index de0801d55..bb4176f10 100644 --- a/crates/trigger/src/runtime_config.rs +++ b/crates/trigger/src/runtime_config.rs @@ -12,6 +12,7 @@ use std::{ use anyhow::{Context, Result}; use serde::Deserialize; +use spin_common::ui::quoted_path; use spin_sqlite::Connection; use self::{ @@ -48,10 +49,12 @@ impl RuntimeConfig { /// later-loaded file take precedence over any earlier-loaded files. pub fn merge_config_file(&mut self, path: impl Into) -> Result<()> { let path = path.into(); - let bytes = fs::read(&path) - .with_context(|| format!("Failed to load runtime config file {path:?}"))?; - let mut opts: RuntimeConfigOpts = toml::from_slice(&bytes) - .with_context(|| format!("Failed to parse runtime config file {path:?}"))?; + let bytes = fs::read(&path).with_context(|| { + format!("Failed to load runtime config file {}", quoted_path(&path)) + })?; + let mut opts: RuntimeConfigOpts = toml::from_slice(&bytes).with_context(|| { + format!("Failed to parse runtime config file {}", quoted_path(&path)) + })?; opts.file_path = Some(path); self.files.push(opts); Ok(()) @@ -224,7 +227,10 @@ fn resolve_config_path(path: &Path, config_opts: &RuntimeConfigOpts) -> Result

file_path .parent() .with_context(|| { - format!("failed to get parent of runtime config file path {file_path:?}") + format!( + "failed to get parent of runtime config file path {}", + quoted_path(file_path) + ) })? .to_owned(), None => std::env::current_dir().context("failed to get current directory")?, diff --git a/crates/trigger/src/runtime_config/key_value.rs b/crates/trigger/src/runtime_config/key_value.rs index 40a92c1c9..1b0dcc1a1 100644 --- a/crates/trigger/src/runtime_config/key_value.rs +++ b/crates/trigger/src/runtime_config/key_value.rs @@ -3,6 +3,7 @@ use std::{collections::HashMap, fs, path::PathBuf, sync::Arc}; use crate::{runtime_config::RuntimeConfig, TriggerHooks}; use anyhow::{bail, Context, Result}; use serde::Deserialize; +use spin_common::ui::quoted_path; use spin_key_value::{ CachingStoreManager, DelegatingStoreManager, KeyValueComponent, StoreManager, KEY_VALUE_STORES_KEY, @@ -159,7 +160,7 @@ impl TriggerHooks for KeyValuePersistenceMessageHook { } KeyValueStoreOpts::Spin(store_opts) => { if let Some(path) = &store_opts.path { - println!("Storing default key-value data to {path:?}"); + println!("Storing default key-value data to {}", quoted_path(path)); } else { println!("Using in-memory default key-value store; data will not be saved!"); } diff --git a/crates/trigger/src/runtime_config/sqlite.rs b/crates/trigger/src/runtime_config/sqlite.rs index 2250ab769..8ae8974f7 100644 --- a/crates/trigger/src/runtime_config/sqlite.rs +++ b/crates/trigger/src/runtime_config/sqlite.rs @@ -2,6 +2,7 @@ use std::{collections::HashMap, path::PathBuf, sync::Arc}; use crate::{runtime_config::RuntimeConfig, TriggerHooks}; use anyhow::Context; +use spin_common::ui::quoted_path; use spin_sqlite::{Connection, ConnectionsStore, SqliteComponent, DATABASES_KEY}; use super::RuntimeConfigOpts; @@ -178,7 +179,7 @@ impl TriggerHooks for SqlitePersistenceMessageHook { match runtime_config.default_sqlite_opts() { SqliteDatabaseOpts::Spin(s) => { if let Some(path) = &s.path { - println!("Storing default SQLite data to {path:?}"); + println!("Storing default SQLite data to {}", quoted_path(path)); } else { println!("Using in-memory default SQLite database; data will not be saved!"); } diff --git a/crates/trigger/src/stdio.rs b/crates/trigger/src/stdio.rs index 667e42fed..b57814998 100644 --- a/crates/trigger/src/stdio.rs +++ b/crates/trigger/src/stdio.rs @@ -5,6 +5,7 @@ use std::{ }; use anyhow::{Context, Result}; +use spin_common::ui::quoted_path; use tokio::io::AsyncWrite; use crate::{runtime_config::RuntimeConfig, TriggerHooks}; @@ -61,7 +62,7 @@ impl StdioLoggingTriggerHooks { let log_path = log_dir.join(format!("{sanitized_component_id}_{log_suffix}.txt")); let follow = self.follow_components.should_follow(component_id); ComponentStdioWriter::new(&log_path, follow) - .with_context(|| format!("Failed to open log file {log_path:?}")) + .with_context(|| format!("Failed to open log file {}", quoted_path(&log_path))) } fn validate_follows(&self, app: &spin_app::App) -> anyhow::Result<()> { @@ -97,9 +98,9 @@ impl TriggerHooks for StdioLoggingTriggerHooks { if let Some(dir) = &self.log_dir { // Ensure log dir exists if set std::fs::create_dir_all(dir) - .with_context(|| format!("Failed to create log dir {dir:?}"))?; + .with_context(|| format!("Failed to create log dir {}", quoted_path(dir)))?; - println!("Logging component stdio to {:?}", dir.join("")) + println!("Logging component stdio to {}", quoted_path(dir.join(""))) } Ok(()) diff --git a/src/commands/up.rs b/src/commands/up.rs index a36e10d5a..046ac06b2 100644 --- a/src/commands/up.rs +++ b/src/commands/up.rs @@ -10,6 +10,7 @@ use anyhow::{anyhow, bail, Context, Result}; use clap::{CommandFactory, Parser}; use reqwest::Url; use spin_app::locked::LockedApp; +use spin_common::ui::quoted_path; use spin_loader::FilesMountStrategy; use spin_oci::OciLoader; use spin_trigger::cli::{SPIN_LOCAL_APP_DIR, SPIN_LOCKED_URL, SPIN_WORKING_DIR}; @@ -284,9 +285,9 @@ impl UpCommand { serde_json::to_vec_pretty(&locked_app).context("failed to serialize locked app")?; tokio::fs::write(&locked_path, locked_app_contents) .await - .with_context(|| format!("failed to write {:?}", locked_path))?; + .with_context(|| format!("failed to write {}", quoted_path(&locked_path)))?; let locked_url = Url::from_file_path(&locked_path) - .map_err(|_| anyhow!("cannot convert to file URL: {locked_path:?}"))? + .map_err(|_| anyhow!("cannot convert to file URL: {}", quoted_path(&locked_path)))? .to_string(); Ok(locked_url) @@ -336,7 +337,12 @@ impl UpCommand { }; spin_loader::from_file(&manifest_path, files_mount_strategy, None) .await - .with_context(|| format!("Failed to load manifest from {manifest_path:?}")) + .with_context(|| { + format!( + "Failed to load manifest from {}", + quoted_path(&manifest_path) + ) + }) } ResolvedAppSource::OciRegistry { locked_app } => Ok(locked_app), } diff --git a/src/commands/up/app_source.rs b/src/commands/up/app_source.rs index 60faf1185..3a6b7ae23 100644 --- a/src/commands/up/app_source.rs +++ b/src/commands/up/app_source.rs @@ -4,6 +4,7 @@ use std::{ }; use anyhow::ensure; +use spin_common::ui::quoted_path; use spin_locked_app::locked::LockedApp; use spin_manifest::schema::v2::AppManifest; @@ -60,7 +61,7 @@ impl AppSource { impl std::fmt::Display for AppSource { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::File(path) => write!(f, "local app {path:?}"), + Self::File(path) => write!(f, "local app {}", quoted_path(path)), Self::OciRegistry(reference) => write!(f, "remote app {reference:?}"), Self::Unresolvable(s) => write!(f, "unknown app source: {s:?}"), Self::None => write!(f, ""),