mirror of
https://codeberg.org/icewind/haze.git
synced 2026-06-04 01:24:09 +02:00
better command parsing
This commit is contained in:
parent
6041587c05
commit
30a002ef71
5 changed files with 205 additions and 136 deletions
177
src/args.rs
177
src/args.rs
|
|
@ -1,44 +1,115 @@
|
||||||
|
use crate::cloud::CloudOptions;
|
||||||
use color_eyre::{Report, Result};
|
use color_eyre::{Report, Result};
|
||||||
|
use parse_display::Display;
|
||||||
|
use std::fmt::Display;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub struct HazeArgs {
|
pub enum HazeArgs {
|
||||||
pub id: Option<String>,
|
List {
|
||||||
pub command: HazeCommand,
|
filter: Option<String>,
|
||||||
pub options: Vec<String>,
|
},
|
||||||
|
Start {
|
||||||
|
options: CloudOptions,
|
||||||
|
},
|
||||||
|
Stop {
|
||||||
|
filter: Option<String>,
|
||||||
|
},
|
||||||
|
Test {
|
||||||
|
options: CloudOptions,
|
||||||
|
path: Option<String>,
|
||||||
|
},
|
||||||
|
Exec {
|
||||||
|
filter: Option<String>,
|
||||||
|
command: Vec<String>,
|
||||||
|
},
|
||||||
|
Occ {
|
||||||
|
filter: Option<String>,
|
||||||
|
command: Vec<String>,
|
||||||
|
},
|
||||||
|
Db {
|
||||||
|
filter: Option<String>,
|
||||||
|
},
|
||||||
|
Clean,
|
||||||
|
Logs {
|
||||||
|
filter: Option<String>,
|
||||||
|
},
|
||||||
|
Open {
|
||||||
|
filter: Option<String>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HazeArgs {
|
impl HazeArgs {
|
||||||
pub fn parse<I, S>(mut args: I) -> Result<HazeArgs>
|
pub fn parse<I, S>(mut args: I) -> Result<HazeArgs>
|
||||||
where
|
where
|
||||||
S: AsRef<str> + ToString,
|
S: AsRef<str> + Into<String> + Display,
|
||||||
I: Iterator<Item = S>,
|
I: Iterator<Item = S>,
|
||||||
{
|
{
|
||||||
let _bin = args.next().unwrap();
|
let _bin = args.next();
|
||||||
let (id, command) = match args.next() {
|
let command_or_filter = match args.next() {
|
||||||
Some(sub_or_id) => {
|
Some(s) => s,
|
||||||
if let Ok(command) = sub_or_id.as_ref().parse() {
|
None => return Ok(HazeArgs::List { filter: None }),
|
||||||
(None, command)
|
|
||||||
} else {
|
|
||||||
if let Some(sub) = args.next() {
|
|
||||||
(Some(sub_or_id.to_string()), sub.as_ref().parse()?)
|
|
||||||
} else {
|
|
||||||
(Some(sub_or_id.to_string()), HazeCommand::List)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => (None, HazeCommand::List),
|
|
||||||
};
|
};
|
||||||
let options = args.map(|s| s.to_string()).collect();
|
let (cmd, filter) = match HazeCommand::from_str(command_or_filter.as_ref()) {
|
||||||
Ok(HazeArgs {
|
Ok(cmd) => (cmd, None),
|
||||||
id,
|
Err(_) => {
|
||||||
command,
|
let cmd = match args.next() {
|
||||||
options,
|
Some(cmd) => HazeCommand::from_str(cmd.as_ref())?,
|
||||||
|
None => {
|
||||||
|
return Ok(HazeArgs::List {
|
||||||
|
filter: Some(command_or_filter.into()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
if !cmd.allows_filter() {
|
||||||
|
return Err(Report::msg(format!(
|
||||||
|
"{} doesn't allow specifying a filter",
|
||||||
|
cmd
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
(cmd, Some(command_or_filter.into()))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match cmd {
|
||||||
|
HazeCommand::List => Ok(HazeArgs::List {
|
||||||
|
filter: filter.or_else(|| args.next().map(S::into)),
|
||||||
|
}),
|
||||||
|
HazeCommand::Start => {
|
||||||
|
let mut args = args.peekable();
|
||||||
|
let options = CloudOptions::parse(&mut args)?;
|
||||||
|
if let Some(leftover) = args.next() {
|
||||||
|
return Err(Report::msg(format!("unrecognized option {}", leftover)));
|
||||||
|
}
|
||||||
|
Ok(HazeArgs::Start { options })
|
||||||
|
}
|
||||||
|
HazeCommand::Stop => Ok(HazeArgs::Stop { filter }),
|
||||||
|
HazeCommand::Test => {
|
||||||
|
let mut args = args.peekable();
|
||||||
|
let options = CloudOptions::parse(&mut args)?;
|
||||||
|
let path = args.next().map(S::into);
|
||||||
|
if let Some(leftover) = args.next() {
|
||||||
|
return Err(Report::msg(format!("unrecognized option {}", leftover)));
|
||||||
|
}
|
||||||
|
Ok(HazeArgs::Test { options, path })
|
||||||
|
}
|
||||||
|
HazeCommand::Exec => Ok(HazeArgs::Exec {
|
||||||
|
filter,
|
||||||
|
command: args.map(S::into).collect(),
|
||||||
|
}),
|
||||||
|
HazeCommand::Occ => Ok(HazeArgs::Occ {
|
||||||
|
filter,
|
||||||
|
command: args.map(S::into).collect(),
|
||||||
|
}),
|
||||||
|
HazeCommand::Db => Ok(HazeArgs::Db { filter }),
|
||||||
|
HazeCommand::Clean => Ok(HazeArgs::Clean),
|
||||||
|
HazeCommand::Logs => Ok(HazeArgs::Logs { filter }),
|
||||||
|
HazeCommand::Open => Ok(HazeArgs::Open { filter }),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Display)]
|
||||||
pub enum HazeCommand {
|
pub enum HazeCommand {
|
||||||
List,
|
List,
|
||||||
Start,
|
Start,
|
||||||
|
|
@ -72,54 +143,60 @@ impl FromStr for HazeCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl HazeCommand {
|
||||||
|
pub fn allows_filter(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
HazeCommand::List => true,
|
||||||
|
HazeCommand::Start => false,
|
||||||
|
HazeCommand::Stop => true,
|
||||||
|
HazeCommand::Test => false,
|
||||||
|
HazeCommand::Exec => true,
|
||||||
|
HazeCommand::Occ => true,
|
||||||
|
HazeCommand::Db => true,
|
||||||
|
HazeCommand::Clean => false,
|
||||||
|
HazeCommand::Logs => true,
|
||||||
|
HazeCommand::Open => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_arg_parse() {
|
fn test_arg_parse() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
HazeArgs::parse(vec!["haze"].into_iter()).unwrap(),
|
HazeArgs::parse(vec!["haze"].into_iter()).unwrap(),
|
||||||
HazeArgs {
|
HazeArgs::List { filter: None }
|
||||||
id: None,
|
|
||||||
command: HazeCommand::List,
|
|
||||||
options: Vec::new(),
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
HazeArgs::parse(vec!["haze", "test"].into_iter()).unwrap(),
|
HazeArgs::parse(vec!["haze", "test"].into_iter()).unwrap(),
|
||||||
HazeArgs {
|
HazeArgs::Test {
|
||||||
id: None,
|
options: Default::default(),
|
||||||
command: HazeCommand::Test,
|
path: None
|
||||||
options: Vec::new(),
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
HazeArgs::parse(vec!["haze", "asdasd"].into_iter()).unwrap(),
|
HazeArgs::parse(vec!["haze", "asdasd"].into_iter()).unwrap(),
|
||||||
HazeArgs {
|
HazeArgs::List {
|
||||||
id: Some("asdasd".to_string()),
|
filter: Some("asdasd".to_string())
|
||||||
command: HazeCommand::List,
|
|
||||||
options: Vec::new(),
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
HazeArgs::parse(vec!["haze", "asdasd", "db"].into_iter()).unwrap(),
|
HazeArgs::parse(vec!["haze", "asdasd", "db"].into_iter()).unwrap(),
|
||||||
HazeArgs {
|
HazeArgs::Db {
|
||||||
id: Some("asdasd".to_string()),
|
filter: Some("asdasd".to_string())
|
||||||
command: HazeCommand::Db,
|
|
||||||
options: Vec::new(),
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
HazeArgs::parse(vec!["haze", "exec", "foo", "bar"].into_iter()).unwrap(),
|
HazeArgs::parse(vec!["haze", "exec", "foo", "bar"].into_iter()).unwrap(),
|
||||||
HazeArgs {
|
HazeArgs::Exec {
|
||||||
id: None,
|
filter: None,
|
||||||
command: HazeCommand::Exec,
|
command: vec!["foo".to_string(), "bar".to_string()],
|
||||||
options: vec!["foo".to_string(), "bar".to_string()],
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
HazeArgs::parse(vec!["haze", "asdasd", "exec", "foo", "bar"].into_iter()).unwrap(),
|
HazeArgs::parse(vec!["haze", "asdasd", "exec", "foo", "bar"].into_iter()).unwrap(),
|
||||||
HazeArgs {
|
HazeArgs::Exec {
|
||||||
id: Some("asdasd".to_string()),
|
filter: Some("asdasd".to_string()),
|
||||||
command: HazeCommand::Exec,
|
command: vec!["foo".to_string(), "bar".to_string()],
|
||||||
options: vec!["foo".to_string(), "bar".to_string()],
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
77
src/cloud.rs
77
src/cloud.rs
|
|
@ -11,7 +11,9 @@ use color_eyre::{eyre::WrapErr, Report, Result};
|
||||||
use futures_util::stream::StreamExt;
|
use futures_util::stream::StreamExt;
|
||||||
use min_id::generate_id;
|
use min_id::generate_id;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::fmt::Display;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::iter::Peekable;
|
||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
use std::os::unix::fs::MetadataExt;
|
use std::os::unix::fs::MetadataExt;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
@ -19,85 +21,82 @@ use std::time::Duration;
|
||||||
use tokio::fs::{create_dir_all, remove_dir_all, write};
|
use tokio::fs::{create_dir_all, remove_dir_all, write};
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
|
|
||||||
#[derive(Default, Debug, Eq, PartialEq)]
|
#[derive(Clone, Default, Debug, Eq, PartialEq)]
|
||||||
pub struct CloudOptions {
|
pub struct CloudOptions {
|
||||||
db: Database,
|
db: Database,
|
||||||
php: PhpVersion,
|
php: PhpVersion,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CloudOptions {
|
impl CloudOptions {
|
||||||
pub fn parse<S>(options: Vec<S>) -> Result<(CloudOptions, Vec<S>)>
|
pub fn parse<I, S>(args: &mut Peekable<I>) -> Result<CloudOptions>
|
||||||
where
|
where
|
||||||
S: AsRef<str> + Clone,
|
S: AsRef<str> + Into<String> + Display,
|
||||||
|
I: Iterator<Item = S>,
|
||||||
{
|
{
|
||||||
let mut db = Database::default();
|
let mut db = None;
|
||||||
let mut php = PhpVersion::default();
|
let mut php = None;
|
||||||
let mut used = 0;
|
|
||||||
|
|
||||||
for option in options.iter() {
|
while let Some(option) = args.peek() {
|
||||||
if let Ok(db_option) = Database::from_str(option.as_ref()) {
|
if let Ok(db_option) = Database::from_str(option.as_ref()) {
|
||||||
db = db_option;
|
db = Some(db_option);
|
||||||
used += 1;
|
let _ = args.next();
|
||||||
continue;
|
} else if let Ok(php_option) = PhpVersion::from_str(option.as_ref()) {
|
||||||
|
php = Some(php_option);
|
||||||
|
let _ = args.next();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if let Ok(php_option) = PhpVersion::from_str(option.as_ref()) {
|
|
||||||
php = php_option;
|
if db.is_some() && php.is_some() {
|
||||||
used += 1;
|
break;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let rest = options[used..].to_vec();
|
Ok(CloudOptions {
|
||||||
|
db: db.unwrap_or_default(),
|
||||||
Ok((CloudOptions { db, php }, rest))
|
php: php.unwrap_or_default(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_option_parse() {
|
fn test_option_parse() {
|
||||||
|
let mut args = vec![].into_iter().peekable();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
CloudOptions::parse::<&str>(vec![]).unwrap(),
|
CloudOptions::parse::<_, &str>(&mut args).unwrap(),
|
||||||
(CloudOptions::default(), vec![])
|
CloudOptions::default()
|
||||||
);
|
);
|
||||||
|
let mut args = vec!["mariadb"].into_iter().peekable();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
CloudOptions::parse(vec!["mariadb"]).unwrap(),
|
CloudOptions::parse(&mut args).unwrap(),
|
||||||
(
|
|
||||||
CloudOptions {
|
CloudOptions {
|
||||||
db: Database::MariaDB,
|
db: Database::MariaDB,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
}
|
||||||
vec![]
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
let mut args = vec!["rest"].into_iter().peekable();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
CloudOptions::parse(vec!["rest"]).unwrap(),
|
CloudOptions::parse(&mut args).unwrap(),
|
||||||
(
|
|
||||||
CloudOptions {
|
CloudOptions {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
}
|
||||||
vec!["rest"]
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
let mut args = vec!["7"].into_iter().peekable();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
CloudOptions::parse(vec!["7"]).unwrap(),
|
CloudOptions::parse(&mut args).unwrap(),
|
||||||
(
|
|
||||||
CloudOptions {
|
CloudOptions {
|
||||||
php: PhpVersion::Php74,
|
php: PhpVersion::Php74,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
}
|
||||||
vec![]
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
let mut args = vec!["7", "pgsql", "rest"].into_iter().peekable();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
CloudOptions::parse(vec!["7", "pgsql", "rest"]).unwrap(),
|
CloudOptions::parse(&mut args).unwrap(),
|
||||||
(
|
|
||||||
CloudOptions {
|
CloudOptions {
|
||||||
php: PhpVersion::Php74,
|
php: PhpVersion::Php74,
|
||||||
db: Database::Postgres,
|
db: Database::Postgres,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
}
|
||||||
vec!["rest"]
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ impl DatabaseFamily {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub enum Database {
|
pub enum Database {
|
||||||
Sqlite,
|
Sqlite,
|
||||||
|
|
|
||||||
63
src/main.rs
63
src/main.rs
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::args::{HazeArgs, HazeCommand};
|
use crate::args::HazeArgs;
|
||||||
use crate::cloud::{Cloud, CloudOptions};
|
use crate::cloud::Cloud;
|
||||||
use crate::config::HazeConfig;
|
use crate::config::HazeConfig;
|
||||||
use bollard::Docker;
|
use bollard::Docker;
|
||||||
use color_eyre::{eyre::WrapErr, Report, Result};
|
use color_eyre::{eyre::WrapErr, Result};
|
||||||
|
|
||||||
mod args;
|
mod args;
|
||||||
mod cloud;
|
mod cloud;
|
||||||
|
|
@ -20,8 +20,8 @@ async fn main() -> Result<()> {
|
||||||
|
|
||||||
let args = HazeArgs::parse(std::env::args())?;
|
let args = HazeArgs::parse(std::env::args())?;
|
||||||
|
|
||||||
match args.command {
|
match args {
|
||||||
HazeCommand::Clean => {
|
HazeArgs::Clean => {
|
||||||
let list = Cloud::list(&mut docker, None, &config).await?;
|
let list = Cloud::list(&mut docker, None, &config).await?;
|
||||||
for cloud in list {
|
for cloud in list {
|
||||||
if let Err(e) = cloud.destroy(&mut docker).await {
|
if let Err(e) = cloud.destroy(&mut docker).await {
|
||||||
|
|
@ -29,14 +29,9 @@ async fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HazeCommand::List => {
|
HazeArgs::List { filter } => {
|
||||||
let list = Cloud::list(&mut docker, args.options.first().cloned(), &config).await?;
|
let list = Cloud::list(&mut docker, filter, &config).await?;
|
||||||
for cloud in list {
|
for cloud in list {
|
||||||
if let Some(filter) = &args.id {
|
|
||||||
if !cloud.id.contains(filter.as_str()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
match cloud.ip {
|
match cloud.ip {
|
||||||
Some(ip) => println!(
|
Some(ip) => println!(
|
||||||
"Cloud {}, {}, {}, running on http://{}",
|
"Cloud {}, {}, {}, running on http://{}",
|
||||||
|
|
@ -54,56 +49,54 @@ async fn main() -> Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HazeCommand::Start => {
|
HazeArgs::Start { options } => {
|
||||||
let (options, rest) = CloudOptions::parse(args.options)?;
|
|
||||||
if let Some(next) = rest.first() {
|
|
||||||
return Err(Report::msg(format!("Unknown option {}", next)));
|
|
||||||
}
|
|
||||||
let cloud = Cloud::create(&mut docker, options, &config).await?;
|
let cloud = Cloud::create(&mut docker, options, &config).await?;
|
||||||
println!("http://{}", cloud.ip.unwrap());
|
println!("http://{}", cloud.ip.unwrap());
|
||||||
}
|
}
|
||||||
HazeCommand::Stop => {
|
HazeArgs::Stop { filter } => {
|
||||||
let cloud = Cloud::get_by_filter(&mut docker, args.id, &config).await?;
|
let cloud = Cloud::get_by_filter(&mut docker, filter, &config).await?;
|
||||||
cloud.destroy(&mut docker).await?;
|
cloud.destroy(&mut docker).await?;
|
||||||
}
|
}
|
||||||
HazeCommand::Logs => {
|
HazeArgs::Logs { filter } => {
|
||||||
let cloud = Cloud::get_by_filter(&mut docker, args.id, &config).await?;
|
let cloud = Cloud::get_by_filter(&mut docker, filter, &config).await?;
|
||||||
let logs = cloud.logs(&mut docker).await?;
|
let logs = cloud.logs(&mut docker).await?;
|
||||||
for log in logs {
|
for log in logs {
|
||||||
print!("{}", log);
|
print!("{}", log);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HazeCommand::Exec => {
|
HazeArgs::Exec { filter, command } => {
|
||||||
let cloud = Cloud::get_by_filter(&mut docker, args.id, &config).await?;
|
let cloud = Cloud::get_by_filter(&mut docker, filter, &config).await?;
|
||||||
cloud
|
cloud
|
||||||
.exec(
|
.exec(
|
||||||
&mut docker,
|
&mut docker,
|
||||||
if args.options.is_empty() {
|
if command.is_empty() {
|
||||||
vec!["bash".to_string()]
|
vec!["bash".to_string()]
|
||||||
} else {
|
} else {
|
||||||
args.options
|
command
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
HazeCommand::Occ => {
|
HazeArgs::Occ {
|
||||||
let cloud = Cloud::get_by_filter(&mut docker, args.id, &config).await?;
|
filter,
|
||||||
let mut options = args.options;
|
mut command,
|
||||||
options.insert(0, "occ".to_string());
|
} => {
|
||||||
cloud.exec(&mut docker, options).await?;
|
let cloud = Cloud::get_by_filter(&mut docker, filter, &config).await?;
|
||||||
|
command.insert(0, "occ".to_string());
|
||||||
|
cloud.exec(&mut docker, command).await?;
|
||||||
}
|
}
|
||||||
HazeCommand::Db => {
|
HazeArgs::Db { filter } => {
|
||||||
let cloud = Cloud::get_by_filter(&mut docker, args.id, &config).await?;
|
let cloud = Cloud::get_by_filter(&mut docker, filter, &config).await?;
|
||||||
cloud.db.exec(&mut docker, &cloud.id).await?;
|
cloud.db.exec(&mut docker, &cloud.id).await?;
|
||||||
}
|
}
|
||||||
HazeCommand::Open => {
|
HazeArgs::Open { filter } => {
|
||||||
let cloud = Cloud::get_by_filter(&mut docker, args.id, &config).await?;
|
let cloud = Cloud::get_by_filter(&mut docker, filter, &config).await?;
|
||||||
match cloud.ip {
|
match cloud.ip {
|
||||||
Some(ip) => opener::open(format!("http://{}", ip))?,
|
Some(ip) => opener::open(format!("http://{}", ip))?,
|
||||||
None => eprintln!("{} is not running", cloud.id),
|
None => eprintln!("{} is not running", cloud.id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HazeCommand::Test => {
|
HazeArgs::Test { .. } => {
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use color_eyre::Result;
|
||||||
use maplit::hashmap;
|
use maplit::hashmap;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub enum PhpVersion {
|
pub enum PhpVersion {
|
||||||
Latest,
|
Latest,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue