Skip to content

Commit

Permalink
feat: finish templates
Browse files Browse the repository at this point in the history
  • Loading branch information
pxseu committed Jun 15, 2023
1 parent 56c1768 commit 9ff580b
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 43 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ update = []
ms = "0.1"
log = "0.4"
dirs = "5.0"
rand = "0.8"
regex = "1.6"
runas = "1.0"
anyhow = "1.0"
Expand Down
150 changes: 111 additions & 39 deletions src/commands/ignite/templates.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use anyhow::{anyhow, Result};
use clap::Parser;
use rand::Rng;
use regex::Regex;

use super::create::DeploymentConfig;
use crate::commands::containers::utils::create_containers;
use crate::commands::ignite::create::Options as CreateOptions;
use crate::commands::ignite::types::{Config, Deployment, Image, MapTo, PremadeInput, Volume};
use crate::commands::ignite::types::{
Autogen, Config, Deployment, Image, MapTo, PremadeInput, Volume,
};
use crate::commands::ignite::utils::{
create_deployment, format_premade, get_premade, update_deployment_config, WEB_IGNITE_URL,
};
Expand Down Expand Up @@ -48,32 +51,20 @@ pub async fn handle(options: Options, state: State) -> Result<()> {
&premades[selection]
};

let (mut deployment_config, container_options) = update_deployment_config(
&state.http,
CreateOptions {
config: options.config.clone(),
// temporary value that gets replaced after we get the name
image: Some("".to_string()),
},
options == Options::default(),
&Deployment {
config: Config {
entrypoint: premade.entrypoint.clone(),
env: premade.environment.clone().unwrap_or_default(),
volume: Some(Volume {
fs: premade.filesystem.clone().unwrap_or_default(),
mount_path: premade.mountpath.clone(),
size: "".to_string(),
}),
..Default::default()
},
let mut deployment = Deployment {
config: Config {
entrypoint: premade.entrypoint.clone(),
env: premade.environment.clone().unwrap_or_default(),
volume: Some(Volume {
fs: premade.filesystem.clone().unwrap_or_default(),
mount_path: premade.mountpath.clone(),
size: "".to_string(),
}),
..Default::default()
},
&Some(premade.name.clone()),
false,
&project,
)
.await?;

..Default::default()
};

if let Some(form) = &premade.form {
log::info!("This template requires some additional information");
Expand All @@ -85,29 +76,52 @@ pub async fn handle(options: Options, state: State) -> Result<()> {
autogen,
max_length,
validator,
required,
} => {
let mut input = dialoguer::Input::<String>::new();

if let Some(default) = default {
input.default(default.clone());
} else if let Some(autogen) = autogen {
input.default(match autogen {
Autogen::ProjectNamespace => project.namespace.clone(),

Autogen::SecureToken => {
// generate random bits securely
let mut rng = rand::thread_rng();

// generate a random string of 24 characters
std::iter::repeat(())
.map(|()| rng.sample(rand::distributions::Alphanumeric))
.take(24)
.map(|b| b as char)
.collect()
}
});
}

input.validate_with(|input: &String| -> Result<(), String> {
if let Some(max_length) = *max_length {
if input.len() > max_length {
return Err(format!(
"Input must be less than {max_length} characters",
));
}
if input.len() > *max_length {
return Err(
format!("Input must be less than {max_length} characters",),
);
}

if let Some(validator) = validator.clone() {
if Regex::new(&validator)
.map_err(|e| e.to_string())?
.is_match(input)
{
return Err(format!("Input must match regex `{validator}`",));
let validator = {
let valid = validator.split('/').into_iter().collect::<Vec<_>>();

if valid.len() == 3 {
valid[1]
} else {
return Err(format!("Invalid validator `{validator}`",));
}
};

if !Regex::new(validator)
.map_err(|e| e.to_string())?
.is_match(input)
{
return Err(format!("Input must match regex `{validator}`",));
}

Ok(())
Expand All @@ -119,20 +133,78 @@ pub async fn handle(options: Options, state: State) -> Result<()> {
input.with_prompt(&field.title);
}

input.interact()?
input.allow_empty(!required);

let value = input.interact()?;

if *required {
value
} else {
continue;
}
}

PremadeInput::Range {
default,
min,
max,
increment,
unit,
} => {
let items = std::iter::repeat(())
.enumerate()
.map(|(i, _)| format!("{}{}", min + (i as u64 * increment), unit))
.take(((max - min) / increment) as usize)
.collect::<Vec<_>>();

let mut input = dialoguer::Select::new();

input.default(
items
.iter()
.position(|i| i == &format!("{default}{unit}"))
.unwrap_or(0),
);

input.with_prompt(&field.title);

input.items(&items);

items[input.interact()?].clone()
}
};

for place in &field.map_to {
match place {
MapTo::Env { key } => {
deployment_config.env.insert(key.clone(), value.clone());
deployment.config.env.insert(key.clone(), value.clone());
}
MapTo::VolumeSize => {
deployment.config.volume = deployment.config.volume.take().map(|mut v| {
v.size = value.clone();
v
});
}
}
}
}
}

let (mut deployment_config, container_options) = update_deployment_config(
&state.http,
CreateOptions {
config: options.config.clone(),
// temporary value that gets replaced after we get the name
image: Some("".to_string()),
},
options == Options::default(),
&deployment,
&Some(premade.name.clone()),
false,
&project,
)
.await?;

// override the image with the premade image
deployment_config.image = Some(Image {
name: premade.image.clone(),
Expand Down
16 changes: 13 additions & 3 deletions src/commands/ignite/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -436,8 +436,17 @@ pub enum PremadeInput {
String {
default: Option<String>,
autogen: Option<Autogen>,
max_length: Option<usize>,
validator: Option<String>,
max_length: usize,
validator: String,
#[serde(default)]
required: bool,
},
Range {
default: u64,
min: u64,
max: u64,
increment: u64,
unit: String,
},
}

Expand All @@ -449,9 +458,10 @@ pub enum Autogen {
}

#[derive(Debug, Deserialize, Clone)]
#[serde(tag = "type", rename_all = "lowercase")]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum MapTo {
Env { key: String },
VolumeSize,
}

#[derive(Debug, Deserialize, Clone)]
Expand Down
1 change: 0 additions & 1 deletion src/commands/ignite/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,6 @@ async fn update_config_visual(
volume.size = dialoguer::Input::<String>::new()
.with_prompt("Volume size")
.default(volume.size)
.show_default(is_update)
.validate_with(|size: &String| -> Result<()> { parse_size(size).map(|_| ()) })
.interact_text()?;

Expand Down

0 comments on commit 9ff580b

Please sign in to comment.