Skip to content

Commit

Permalink
Merge pull request #5 from kate-goldenring/manifest-module
Browse files Browse the repository at this point in the history
Add `manifest` module and update `deploy.rs`
  • Loading branch information
kate-goldenring committed May 24, 2023
2 parents f3d42fd + 1e78c09 commit 95013c1
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 29 deletions.
59 changes: 30 additions & 29 deletions src/commands/deploy.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
use std::fs::File;
use std::io;
use std::io::{copy, Write};
use std::path::PathBuf;

use crate::{opts::*, parse_buildinfo};
use anyhow::ensure;
use anyhow::{anyhow, bail, Context, Result};
use bindle::Id;
Expand All @@ -16,7 +10,7 @@ use hippo_openapi::models::ChannelRevisionSelectionStrategy;
use rand::Rng;
use semver::BuildMetadata;
use sha2::{Digest, Sha256};
use spin_common::sloth;
use spin_common::{arg_parser::parse_kv, sloth};
use spin_http::routes::RoutePattern;
use spin_loader::bindle::BindleConnectionInfo;
use spin_loader::local::config::RawAppManifest;
Expand All @@ -26,11 +20,18 @@ use spin_manifest::{HttpTriggerConfiguration, TriggerConfig};
use spin_trigger_http::AppInfo;
use tokio::fs;
use tracing::instrument;

use std::fs::File;
use std::io;
use std::io::{copy, Write};
use std::path::PathBuf;
use url::Url;
use uuid::Uuid;

use crate::commands::login::LoginCommand;
use crate::commands::login::LoginConnection;
use crate::{opts::*, parse_buildinfo};

use super::login::LoginCommand;
use super::login::LoginConnection;

const SPIN_DEPLOY_CHANNEL_NAME: &str = "spin-deploy";
const SPIN_DEFAULT_KV_STORE: &str = "default";
Expand All @@ -40,14 +41,17 @@ const BINDLE_REGISTRY_URL_PATH: &str = "api/registry";
#[derive(Parser, Debug)]
#[clap(about = "Package and upload an application to the Fermyon Platform")]
pub struct DeployCommand {
/// Path to spin.toml
/// The application to deploy. This may be a manifest (spin.toml) file, or a
/// directory containing a spin.toml file.
/// If omitted, it defaults to "spin.toml".
#[clap(
name = APP_MANIFEST_FILE_OPT,
short = 'f',
long = "file",
default_value = "spin.toml"
long = "from",
alias = "file",
default_value = DEFAULT_MANIFEST_FILE
)]
pub app: PathBuf,
pub app_source: PathBuf,

/// Path to assemble the bindle before pushing (defaults to
/// a temporary directory)
Expand All @@ -70,7 +74,7 @@ pub struct DeployCommand {
#[clap(
name = BUILDINFO_OPT,
long = "buildinfo",
parse(try_from_str = parse_buildinfo)
parse(try_from_str = parse_buildinfo),
)]
pub buildinfo: Option<BuildMetadata>,

Expand All @@ -93,7 +97,8 @@ pub struct DeployCommand {
)]
pub deployment_env_id: Option<String>,

/// Pass a key/value (key=value) to all components of the application.
/// Set a key/value pair (key=value) in the deployed application's
/// default store. Any existing value will be overwritten.
/// Can be used multiple times.
#[clap(long = "key-value", parse(try_from_str = parse_kv))]
pub key_values: Vec<(String, String)>,
Expand Down Expand Up @@ -222,6 +227,10 @@ impl DeployCommand {
}
}

fn app(&self) -> anyhow::Result<PathBuf> {
crate::manifest::resolve_file_path(&self.app_source)
}

// TODO: unify with login
fn config_file_path(&self) -> Result<PathBuf> {
let root = dirs::config_dir()
Expand All @@ -240,7 +249,7 @@ impl DeployCommand {
}

async fn deploy_hippo(self, login_connection: LoginConnection) -> Result<()> {
let cfg_any = spin_loader::local::raw_manifest_from_file(&self.app).await?;
let cfg_any = spin_loader::local::raw_manifest_from_file(&self.app()?).await?;
let cfg = cfg_any.into_v1();

ensure!(!cfg.components.is_empty(), "No components in spin.toml!");
Expand Down Expand Up @@ -368,7 +377,7 @@ impl DeployCommand {

let client = CloudClient::new(connection_config.clone());

let cfg_any = spin_loader::local::raw_manifest_from_file(&self.app).await?;
let cfg_any = spin_loader::local::raw_manifest_from_file(&self.app()?).await?;
let cfg = cfg_any.into_v1();

validate_cloud_app(&cfg)?;
Expand Down Expand Up @@ -507,8 +516,9 @@ impl DeployCommand {
}

async fn compute_buildinfo(&self, cfg: &RawAppManifest) -> Result<BuildMetadata> {
let app_file = self.app()?;
let mut sha256 = Sha256::new();
let app_folder = parent_dir(&self.app)?;
let app_folder = parent_dir(&app_file)?;

for x in cfg.components.iter() {
match &x.source {
Expand All @@ -532,7 +542,7 @@ impl DeployCommand {
}
}

let mut r = File::open(&self.app)?;
let mut r = File::open(&app_file)?;
copy(&mut r, &mut sha256)?;

let mut final_digest = format!("q{:x}", sha256.finalize());
Expand Down Expand Up @@ -674,7 +684,7 @@ impl DeployCommand {
Some(path) => path.as_path(),
};

let bindle_id = spin_bindle::prepare_bindle(&self.app, buildinfo, dest_dir)
let bindle_id = spin_bindle::prepare_bindle(&self.app()?, buildinfo, dest_dir)
.await
.map_err(crate::wrap_prepare_bindle_error)?;

Expand Down Expand Up @@ -872,12 +882,3 @@ fn has_expired(login_connection: &LoginConnection) -> Result<bool> {
None => Ok(false),
}
}

// Parse the key/values passed in as `key=value` pairs.
fn parse_kv(s: &str) -> Result<(String, String)> {
let parts: Vec<_> = s.splitn(2, '=').collect();
if parts.len() != 2 {
bail!("Key/Values must be of the form `key=value`");
}
Ok((parts[0].to_owned(), parts[1].to_owned()))
}
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod commands;
mod manifest;
mod opts;
use anyhow::{anyhow, Error, Result};
use clap::{Parser, Subcommand};
Expand Down
32 changes: 32 additions & 0 deletions src/manifest.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use anyhow::anyhow;
use std::path::{Path, PathBuf};

use crate::opts::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(crate) fn resolve_file_path(provided_path: impl AsRef<Path>) -> anyhow::Result<PathBuf> {
let path = provided_path.as_ref();

if path.is_file() {
Ok(path.to_owned())
} else if path.is_dir() {
let file_path = path.join(DEFAULT_MANIFEST_FILE);
if file_path.is_file() {
Ok(file_path)
} else {
Err(anyhow!(
"Directory {} does not contain a file named 'spin.toml'",
path.display()
))
}
} else {
let pd = path.display();
let err = match path.try_exists() {
Err(e) => anyhow!("Error accessing path {pd}: {e:#}"),
Ok(false) => anyhow!("No such file or directory '{pd}'"),
Ok(true) => anyhow!("Path {pd} is neither a file nor a directory"),
};
Err(err)
}
}
1 change: 1 addition & 0 deletions src/opts.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub const DEFAULT_MANIFEST_FILE: &str = "spin.toml";
pub const APP_MANIFEST_FILE_OPT: &str = "APP_MANIFEST_FILE";
pub const BINDLE_SERVER_URL_OPT: &str = "BINDLE_SERVER_URL";
pub const BINDLE_URL_ENV: &str = "BINDLE_URL";
Expand Down

0 comments on commit 95013c1

Please sign in to comment.