Skip to content

Commit

Permalink
Enable running some commands from subdirectories
Browse files Browse the repository at this point in the history
Signed-off-by: itowlson <ivan.towlson@fermyon.com>
  • Loading branch information
itowlson committed Sep 19, 2024
1 parent 1e3d971 commit 7941f85
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 24 deletions.
37 changes: 37 additions & 0 deletions crates/common/src/paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@ use crate::ui::quoted_path;
/// The name given to the default manifest file.
pub const DEFAULT_MANIFEST_FILE: &str = "spin.toml";

/// Attempts to find a manifest. If a path is provided, that path is resolved
/// using `resolve_manifest_file_path`; otherwise, a directory search is carried out
/// using `search_upwards_for_manifest`. If a manifest is found, a boolean is
/// also returned indicating if it was the default: this can be used to
/// notify the user that a non-default manifest is being used.
pub fn find_manifest_file_path(provided_path: Option<impl AsRef<Path>>) -> Result<(PathBuf, bool)> {
match provided_path {
Some(provided_path) => resolve_manifest_file_path(provided_path).map(|p| (p, true)),
None => search_upwards_for_manifest()
.ok_or_else(|| anyhow!("\"{}\" not found", DEFAULT_MANIFEST_FILE)),
}
}

/// Resolves a manifest path provided by a user, which may be a file or
/// directory, to a path to a manifest file.
pub fn resolve_manifest_file_path(provided_path: impl AsRef<Path>) -> Result<PathBuf> {
Expand Down Expand Up @@ -36,6 +49,30 @@ pub fn resolve_manifest_file_path(provided_path: impl AsRef<Path>) -> Result<Pat
}
}

/// Starting from the current directory, searches upward through
/// the directory tree for a manifest (that is, a file with the default
/// manifest name `spin.toml`). If found, the path to the manifest
/// is returned, with a boolean flag indicating if the found path was
/// the default (i.e. `spin.toml` in the current directory).
/// If no matching file is found, the function returns None.
pub fn search_upwards_for_manifest() -> Option<(PathBuf, bool)> {
let mut inferred_dir = std::env::current_dir().unwrap();
let mut is_default = true;

loop {
let candidate = inferred_dir.join(DEFAULT_MANIFEST_FILE);

if candidate.is_file() {
return Some((candidate, is_default));
}

is_default = false;
let parent = inferred_dir.parent()?;

inferred_dir = parent.to_owned();
}
}

/// Resolves the parent directory of a path, returning an error if the path
/// has no parent. A path with a single component will return ".".
pub fn parent_dir(path: impl AsRef<Path>) -> Result<PathBuf> {
Expand Down
17 changes: 13 additions & 4 deletions src/commands/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ use std::{ffi::OsString, path::PathBuf};

use anyhow::Result;
use clap::Parser;
use spin_common::ui::quoted_path;

use crate::opts::{APP_MANIFEST_FILE_OPT, BUILD_UP_OPT, DEFAULT_MANIFEST_FILE};
use crate::opts::{APP_MANIFEST_FILE_OPT, BUILD_UP_OPT};

use super::up::UpCommand;

Expand All @@ -19,9 +20,8 @@ pub struct BuildCommand {
short = 'f',
long = "from",
alias = "file",
default_value = DEFAULT_MANIFEST_FILE
)]
pub app_source: PathBuf,
pub app_source: Option<PathBuf>,

/// Component ID to build. This can be specified multiple times. The default is all components.
#[clap(short = 'c', long, multiple = true)]
Expand All @@ -37,7 +37,16 @@ pub struct BuildCommand {

impl BuildCommand {
pub async fn run(self) -> Result<()> {
let manifest_file = spin_common::paths::resolve_manifest_file_path(&self.app_source)?;
let (manifest_file, is_default) =
spin_common::paths::find_manifest_file_path(self.app_source.as_ref())?;
if !is_default {
terminal::einfo!(
"Using 'spin.toml' from parent directory:",
"{}",
quoted_path(&manifest_file)
);
}

spin_build::build(&manifest_file, &self.component_id).await?;

if self.up {
Expand Down
26 changes: 17 additions & 9 deletions src/commands/doctor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use clap::Parser;
use dialoguer::{console::Emoji, Confirm, Select};
use spin_doctor::{Diagnosis, DryRunNotSupported, PatientDiagnosis};

use crate::opts::{APP_MANIFEST_FILE_OPT, DEFAULT_MANIFEST_FILE};
use crate::opts::APP_MANIFEST_FILE_OPT;

#[derive(Parser, Debug)]
#[clap(about = "Detect and fix problems with Spin applications")]
Expand All @@ -18,21 +18,29 @@ pub struct DoctorCommand {
short = 'f',
long = "from",
alias = "file",
default_value = DEFAULT_MANIFEST_FILE
)]
pub app_source: PathBuf,
pub app_source: Option<PathBuf>,
}

impl DoctorCommand {
pub async fn run(self) -> Result<()> {
let manifest_file = spin_common::paths::resolve_manifest_file_path(&self.app_source)?;
let (manifest_file, is_default) =
spin_common::paths::find_manifest_file_path(self.app_source.as_ref())?;

println!("{icon}The Spin Doctor is in.", icon = Emoji("📟 ", ""));
println!(
"{icon}Checking {}...",
manifest_file.display(),
icon = Emoji("🩺 ", "")
);
if is_default {
println!(
"{icon}Checking {}...",
manifest_file.display(),
icon = Emoji("🩺 ", "")
);
} else {
println!(
"{icon}Checking file from parent directory {}...",
manifest_file.display(),
icon = Emoji("🩺 ", "")
);
}

let mut checkup = spin_doctor::Checkup::new(manifest_file)?;
let mut has_problems = false;
Expand Down
16 changes: 12 additions & 4 deletions src/commands/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::opts::*;
use anyhow::{Context, Result};
use clap::{Parser, Subcommand};
use indicatif::{ProgressBar, ProgressStyle};
use spin_common::arg_parser::parse_kv;
use spin_common::{arg_parser::parse_kv, ui::quoted_path};
use spin_oci::{client::InferPredefinedAnnotations, Client};
use std::{io::Read, path::PathBuf, time::Duration};

Expand Down Expand Up @@ -37,9 +37,8 @@ pub struct Push {
short = 'f',
long = "from",
alias = "file",
default_value = DEFAULT_MANIFEST_FILE
)]
pub app_source: PathBuf,
pub app_source: Option<PathBuf>,

/// Ignore server certificate errors
#[clap(
Expand Down Expand Up @@ -71,7 +70,16 @@ pub struct Push {

impl Push {
pub async fn run(self) -> Result<()> {
let app_file = spin_common::paths::resolve_manifest_file_path(&self.app_source)?;
let (app_file, is_default) =
spin_common::paths::find_manifest_file_path(self.app_source.as_ref())?;
if !is_default {
terminal::einfo!(
"Using 'spin.toml' from parent directory:",
"{}",
quoted_path(&app_file)
);
}

if self.build {
spin_build::build(&app_file, &[]).await?;
}
Expand Down
14 changes: 13 additions & 1 deletion src/commands/up.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,19 @@ impl UpCommand {
);
AppSource::Unresolvable(msg)
} else {
AppSource::None
match spin_common::paths::search_upwards_for_manifest() {
Some((manifest_path, is_default)) => {
if !is_default {
terminal::einfo!(
"Using 'spin.toml' from parent directory:",
"{}",
quoted_path(&manifest_path)
);
}
AppSource::File(manifest_path)
}
None => AppSource::None,
}
}
}

Expand Down
18 changes: 12 additions & 6 deletions src/commands/watch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@ use anyhow::{Context, Result};
use clap::Parser;
use itertools::Itertools;
use path_absolutize::Absolutize;
use spin_common::paths::parent_dir;
use spin_common::{paths::parent_dir, ui::quoted_path};
use uuid::Uuid;
use watchexec::Watchexec;

use crate::opts::{
APP_MANIFEST_FILE_OPT, DEFAULT_MANIFEST_FILE, WATCH_CLEAR_OPT, WATCH_DEBOUNCE_OPT,
WATCH_SKIP_BUILD_OPT,
APP_MANIFEST_FILE_OPT, WATCH_CLEAR_OPT, WATCH_DEBOUNCE_OPT, WATCH_SKIP_BUILD_OPT,
};

mod buildifier;
Expand All @@ -41,9 +40,8 @@ pub struct WatchCommand {
short = 'f',
long = "from",
alias = "file",
default_value = DEFAULT_MANIFEST_FILE
)]
pub app_source: PathBuf,
pub app_source: Option<PathBuf>,

/// Clear the screen before each run.
#[clap(
Expand Down Expand Up @@ -93,7 +91,15 @@ impl WatchCommand {
// has just done so. Subsequent asset changes _do_ clear the screen.

let spin_bin = std::env::current_exe()?;
let manifest_file = spin_common::paths::resolve_manifest_file_path(&self.app_source)?;
let (manifest_file, is_default) =
spin_common::paths::find_manifest_file_path(self.app_source.as_ref())?;
if !is_default {
terminal::einfo!(
"Using 'spin.toml' from parent directory:",
"{}",
quoted_path(&manifest_file)
);
}
let manifest_file = manifest_file.absolutize()?.to_path_buf(); // or watchexec misses files in subdirectories
let manifest_dir = parent_dir(&manifest_file)?;

Expand Down

0 comments on commit 7941f85

Please sign in to comment.