1
0
Fork 0
mirror of https://codeberg.org/icewind/haze.git synced 2026-06-03 09:04:12 +02:00

default to max supported php version

This commit is contained in:
Robin Appelman 2025-08-26 13:32:18 +02:00
commit 86a68339b4
5 changed files with 122 additions and 49 deletions

View file

@ -1,5 +1,5 @@
use crate::cloud::CloudOptions; use crate::cloud::CloudOptions;
use crate::config::Preset; use crate::config::{HazeConfig, Preset};
use crate::service::{Service, ServiceTrait}; use crate::service::{Service, ServiceTrait};
use miette::{IntoDiagnostic, Report, Result}; use miette::{IntoDiagnostic, Report, Result};
use parse_display::Display; use parse_display::Display;
@ -105,7 +105,7 @@ pub enum ExecService {
} }
impl HazeArgs { impl HazeArgs {
pub fn parse<I, S>(presets: &[Preset], mut args: I) -> Result<HazeArgs> pub fn parse<I, S>(config: &HazeConfig, mut args: I) -> Result<HazeArgs>
where where
S: AsRef<str> + Into<String> + Display, S: AsRef<str> + Into<String> + Display,
I: Iterator<Item = S>, I: Iterator<Item = S>,
@ -142,7 +142,7 @@ impl HazeArgs {
}), }),
HazeCommand::Start => { HazeCommand::Start => {
let mut args = args.peekable(); let mut args = args.peekable();
let options = CloudOptions::parse(presets, &mut args)?; let options = CloudOptions::parse(config, &mut args)?;
if let Some(leftover) = args.next() { if let Some(leftover) = args.next() {
return Err(Report::msg(format!("unrecognized option {}", leftover))); return Err(Report::msg(format!("unrecognized option {}", leftover)));
} }
@ -151,13 +151,13 @@ impl HazeArgs {
HazeCommand::Stop => Ok(HazeArgs::Stop { filter }), HazeCommand::Stop => Ok(HazeArgs::Stop { filter }),
HazeCommand::Test => { HazeCommand::Test => {
let mut args = args.peekable(); let mut args = args.peekable();
let options = CloudOptions::parse(presets, &mut args)?; let options = CloudOptions::parse(config, &mut args)?;
let args = args.map(S::into).collect(); let args = args.map(S::into).collect();
Ok(HazeArgs::Test { options, args }) Ok(HazeArgs::Test { options, args })
} }
HazeCommand::Integration => { HazeCommand::Integration => {
let mut args = args.peekable(); let mut args = args.peekable();
let options = CloudOptions::parse(presets, &mut args)?; let options = CloudOptions::parse(config, &mut args)?;
let args = args.map(S::into).collect(); let args = args.map(S::into).collect();
Ok(HazeArgs::Integration { options, args }) Ok(HazeArgs::Integration { options, args })
} }
@ -218,8 +218,8 @@ impl HazeArgs {
let mut args = args.peekable(); let mut args = args.peekable();
let follow = args.next_if(|arg| arg.as_ref() == "-f").is_some(); let follow = args.next_if(|arg| arg.as_ref() == "-f").is_some();
let service = args let service = args
.next_if(|arg| LogService::from_type(presets, arg.as_ref()).is_some()) .next_if(|arg| LogService::from_type(&config.preset, arg.as_ref()).is_some())
.and_then(|arg| LogService::from_type(presets, arg.as_ref())); .and_then(|arg| LogService::from_type(&config.preset, arg.as_ref()));
Ok(HazeArgs::Logs { Ok(HazeArgs::Logs {
filter, filter,
follow, follow,
@ -241,7 +241,7 @@ impl HazeArgs {
} }
HazeCommand::Shell => { HazeCommand::Shell => {
let mut args = args.peekable(); let mut args = args.peekable();
let options = CloudOptions::parse(presets, &mut args)?; let options = CloudOptions::parse(config, &mut args)?;
let command = args.map(S::into).collect(); let command = args.map(S::into).collect();
Ok(HazeArgs::Shell { options, command }) Ok(HazeArgs::Shell { options, command })
} }
@ -348,25 +348,35 @@ impl HazeCommand {
#[test] #[test]
fn test_arg_parse() { fn test_arg_parse() {
let config = HazeConfig {
sources_root: Default::default(),
work_dir: Default::default(),
auto_setup: Default::default(),
volume: vec![],
blackfire: None,
proxy: Default::default(),
preset: vec![],
};
assert_eq!( assert_eq!(
HazeArgs::parse(&[], vec!["haze"].into_iter()).unwrap(), HazeArgs::parse(&config, vec!["haze"].into_iter()).unwrap(),
HazeArgs::List { filter: None } HazeArgs::List { filter: None }
); );
assert_eq!( assert_eq!(
HazeArgs::parse(&[], vec!["haze", "test"].into_iter()).unwrap(), HazeArgs::parse(&config, vec!["haze", "test"].into_iter()).unwrap(),
HazeArgs::Test { HazeArgs::Test {
options: Default::default(), options: Default::default(),
args: vec![] args: vec![]
} }
); );
assert_eq!( assert_eq!(
HazeArgs::parse(&[], vec!["haze", "asdasd"].into_iter()).unwrap(), HazeArgs::parse(&config, vec!["haze", "asdasd"].into_iter()).unwrap(),
HazeArgs::List { HazeArgs::List {
filter: Some("asdasd".to_string()) filter: Some("asdasd".to_string())
} }
); );
assert_eq!( assert_eq!(
HazeArgs::parse(&[], vec!["haze", "asdasd", "db"].into_iter()).unwrap(), HazeArgs::parse(&config, vec!["haze", "asdasd", "db"].into_iter()).unwrap(),
HazeArgs::Db { HazeArgs::Db {
filter: Some("asdasd".to_string()), filter: Some("asdasd".to_string()),
root: false, root: false,
@ -375,7 +385,7 @@ fn test_arg_parse() {
} }
); );
assert_eq!( assert_eq!(
HazeArgs::parse(&[], vec!["haze", "asdasd", "db", "root"].into_iter()).unwrap(), HazeArgs::parse(&config, vec!["haze", "asdasd", "db", "root"].into_iter()).unwrap(),
HazeArgs::Db { HazeArgs::Db {
filter: Some("asdasd".to_string()), filter: Some("asdasd".to_string()),
root: true, root: true,
@ -384,7 +394,11 @@ fn test_arg_parse() {
} }
); );
assert_eq!( assert_eq!(
HazeArgs::parse(&[], vec!["haze", "asdasd", "db", "select", "1"].into_iter()).unwrap(), HazeArgs::parse(
&config,
vec!["haze", "asdasd", "db", "select", "1"].into_iter()
)
.unwrap(),
HazeArgs::Db { HazeArgs::Db {
filter: Some("asdasd".to_string()), filter: Some("asdasd".to_string()),
root: false, root: false,
@ -394,7 +408,7 @@ fn test_arg_parse() {
); );
assert_eq!( assert_eq!(
HazeArgs::parse( HazeArgs::parse(
&[], &config,
vec!["haze", "asdasd", "db", "root", "select 1"].into_iter() vec!["haze", "asdasd", "db", "root", "select 1"].into_iter()
) )
.unwrap(), .unwrap(),
@ -407,7 +421,7 @@ fn test_arg_parse() {
); );
assert_eq!( assert_eq!(
HazeArgs::parse( HazeArgs::parse(
&[], &config,
vec!["haze", "asdasd", "db", "root", "1", "select 1"].into_iter() vec!["haze", "asdasd", "db", "root", "1", "select 1"].into_iter()
) )
.unwrap(), .unwrap(),
@ -420,7 +434,7 @@ fn test_arg_parse() {
); );
assert_eq!( assert_eq!(
HazeArgs::parse( HazeArgs::parse(
&[], &config,
vec!["haze", "asdasd", "db", "all", "select 1"].into_iter() vec!["haze", "asdasd", "db", "all", "select 1"].into_iter()
) )
.unwrap(), .unwrap(),
@ -432,7 +446,7 @@ fn test_arg_parse() {
} }
); );
assert_eq!( assert_eq!(
HazeArgs::parse(&[], vec!["haze", "exec", "foo", "bar"].into_iter()).unwrap(), HazeArgs::parse(&config, vec!["haze", "exec", "foo", "bar"].into_iter()).unwrap(),
HazeArgs::Exec { HazeArgs::Exec {
filter: None, filter: None,
service: None, service: None,
@ -441,7 +455,7 @@ fn test_arg_parse() {
); );
assert_eq!( assert_eq!(
HazeArgs::parse( HazeArgs::parse(
&[], &config,
vec!["haze", "asdasd", "exec", "foo", "bar"].into_iter() vec!["haze", "asdasd", "exec", "foo", "bar"].into_iter()
) )
.unwrap(), .unwrap(),
@ -453,7 +467,7 @@ fn test_arg_parse() {
); );
assert_eq!( assert_eq!(
HazeArgs::parse( HazeArgs::parse(
&[], &config,
vec!["haze", "asdasd", "exec", "db", "foo", "bar"].into_iter() vec!["haze", "asdasd", "exec", "db", "foo", "bar"].into_iter()
) )
.unwrap(), .unwrap(),
@ -464,14 +478,14 @@ fn test_arg_parse() {
} }
); );
assert_eq!( assert_eq!(
HazeArgs::parse(&[], vec!["haze", "test", "foo", "bar"].into_iter()).unwrap(), HazeArgs::parse(&config, vec!["haze", "test", "foo", "bar"].into_iter()).unwrap(),
HazeArgs::Test { HazeArgs::Test {
options: Default::default(), options: Default::default(),
args: vec!["foo".into(), "bar".into()] args: vec!["foo".into(), "bar".into()]
} }
); );
assert_eq!( assert_eq!(
HazeArgs::parse(&[], vec!["haze", "logs", "-f", "smb"].into_iter()).unwrap(), HazeArgs::parse(&config, vec!["haze", "logs", "-f", "smb"].into_iter()).unwrap(),
HazeArgs::Logs { HazeArgs::Logs {
filter: None, filter: None,
follow: true, follow: true,
@ -481,7 +495,7 @@ fn test_arg_parse() {
); );
assert_eq!( assert_eq!(
HazeArgs::parse( HazeArgs::parse(
&[], &config,
vec!["haze", "asdasd", "logs", "smb", "123"].into_iter() vec!["haze", "asdasd", "logs", "smb", "123"].into_iter()
) )
.unwrap(), .unwrap(),

View file

@ -1,4 +1,4 @@
use crate::config::{HazeConfig, HazeVolumeConfig, Preset}; use crate::config::{HazeConfig, HazeVolumeConfig};
use crate::database::Database; use crate::database::Database;
use crate::exec::{exec, exec_io, exec_tty, ExitCode}; use crate::exec::{exec, exec_io, exec_tty, ExitCode};
use crate::mapping::{default_mappings, Mapping}; use crate::mapping::{default_mappings, Mapping};
@ -9,7 +9,7 @@ use bollard::container::{ListContainersOptions, RemoveContainerOptions, UpdateCo
use bollard::models::ContainerState; use bollard::models::ContainerState;
use bollard::network::CreateNetworkOptions; use bollard::network::CreateNetworkOptions;
use bollard::Docker; use bollard::Docker;
use camino::Utf8PathBuf; use camino::{Utf8Path, Utf8PathBuf};
use flate2::read::GzDecoder; use flate2::read::GzDecoder;
use futures_util::future::try_join_all; use futures_util::future::try_join_all;
use miette::{IntoDiagnostic, Report, Result, WrapErr}; use miette::{IntoDiagnostic, Report, Result, WrapErr};
@ -18,6 +18,7 @@ use serde_json::Value;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::Display; use std::fmt::Display;
use std::fs; use std::fs;
use std::fs::read_to_string;
use std::io::{stdout, Cursor, Read, Stdout, Write}; use std::io::{stdout, Cursor, Read, Stdout, Write};
use std::iter::Peekable; use std::iter::Peekable;
use std::net::IpAddr; use std::net::IpAddr;
@ -29,7 +30,26 @@ use tokio::fs::remove_dir_all;
use tokio::task::spawn; use tokio::task::spawn;
use tokio::time::sleep; use tokio::time::sleep;
#[derive(Clone, Default, Debug, Eq, PartialEq)] fn get_max_php_version(base_path: &Utf8Path) -> Option<PhpVersion> {
let version_check_code = read_to_string(base_path.join("lib/versioncheck.php")).ok()?;
let start = version_check_code.find("PHP_VERSION_ID >= ")?;
let code_part = &version_check_code[start + "PHP_VERSION_ID >= ".len()..];
let end = code_part.find(")")?;
let version_code = &code_part[0..end];
let mut major: u8 = version_code.get(0..1)?.parse().ok()?;
let mut minor: u8 = version_code.get(1..3)?.parse().ok()?;
if minor > 0 {
minor -= 1;
} else {
major -= 1;
minor = PhpVersion::max_minor(major);
}
PhpVersion::from_number(major, minor)
}
#[derive(Clone, Debug, Eq, PartialEq, Default)]
pub struct CloudOptions { pub struct CloudOptions {
pub name: Option<String>, pub name: Option<String>,
pub db: Database, pub db: Database,
@ -39,7 +59,19 @@ pub struct CloudOptions {
} }
impl CloudOptions { impl CloudOptions {
pub fn parse<I, S>(presets: &[Preset], args: &mut Peekable<I>) -> Result<CloudOptions> pub fn new(config: &HazeConfig) -> Self {
let php = get_max_php_version(&config.sources_root).unwrap_or_default();
CloudOptions {
name: None,
php,
db: Database::default(),
services: vec![],
app_packages: vec![],
}
}
pub fn parse<I, S>(config: &HazeConfig, args: &mut Peekable<I>) -> Result<CloudOptions>
where where
S: AsRef<str> + Into<String> + Display, S: AsRef<str> + Into<String> + Display,
I: Iterator<Item = S>, I: Iterator<Item = S>,
@ -57,7 +89,7 @@ impl CloudOptions {
} else if let Ok(php_option) = PhpVersion::from_str(option.as_ref()) { } else if let Ok(php_option) = PhpVersion::from_str(option.as_ref()) {
php = Some(php_option); php = Some(php_option);
let _ = args.next(); let _ = args.next();
} else if let Some(service) = Service::from_type(presets, option.as_ref()) { } else if let Some(service) = Service::from_type(&config.preset, option.as_ref()) {
services.extend_from_slice(&service); services.extend_from_slice(&service);
let _ = args.next(); let _ = args.next();
} else if option.as_ref().ends_with(".tar.gz") { } else if option.as_ref().ends_with(".tar.gz") {
@ -74,7 +106,9 @@ impl CloudOptions {
Ok(CloudOptions { Ok(CloudOptions {
name, name,
db: db.unwrap_or_default(), db: db.unwrap_or_default(),
php: php.unwrap_or_default(), php: php
.or_else(|| get_max_php_version(&config.sources_root))
.unwrap_or_default(),
services, services,
app_packages: app_package, app_packages: app_package,
}) })
@ -87,14 +121,16 @@ fn test_option_parse() {
use crate::service::PresetService; use crate::service::PresetService;
use crate::service::{Ldap, LdapAdmin}; use crate::service::{Ldap, LdapAdmin};
let config = HazeConfig::default();
let mut args = vec![].into_iter().peekable(); let mut args = vec![].into_iter().peekable();
assert_eq!( assert_eq!(
CloudOptions::parse::<_, &str>(&[], &mut args).unwrap(), CloudOptions::parse::<_, &str>(&config, &mut args).unwrap(),
CloudOptions::default() CloudOptions::default()
); );
let mut args = vec!["mariadb"].into_iter().peekable(); let mut args = vec!["mariadb"].into_iter().peekable();
assert_eq!( assert_eq!(
CloudOptions::parse(&[], &mut args).unwrap(), CloudOptions::parse(&config, &mut args).unwrap(),
CloudOptions { CloudOptions {
db: Database::MariaDB, db: Database::MariaDB,
..Default::default() ..Default::default()
@ -102,14 +138,14 @@ fn test_option_parse() {
); );
let mut args = vec!["rest"].into_iter().peekable(); let mut args = vec!["rest"].into_iter().peekable();
assert_eq!( assert_eq!(
CloudOptions::parse(&[], &mut args).unwrap(), CloudOptions::parse(&config, &mut args).unwrap(),
CloudOptions { CloudOptions {
..Default::default() ..Default::default()
} }
); );
let mut args = vec!["7"].into_iter().peekable(); let mut args = vec!["7"].into_iter().peekable();
assert_eq!( assert_eq!(
CloudOptions::parse(&[], &mut args).unwrap(), CloudOptions::parse(&config, &mut args).unwrap(),
CloudOptions { CloudOptions {
php: PhpVersion::Php74, php: PhpVersion::Php74,
..Default::default() ..Default::default()
@ -117,7 +153,7 @@ fn test_option_parse() {
); );
let mut args = vec!["7", "pgsql", "rest"].into_iter().peekable(); let mut args = vec!["7", "pgsql", "rest"].into_iter().peekable();
assert_eq!( assert_eq!(
CloudOptions::parse(&[], &mut args).unwrap(), CloudOptions::parse(&config, &mut args).unwrap(),
CloudOptions { CloudOptions {
php: PhpVersion::Php74, php: PhpVersion::Php74,
db: Database::Postgres, db: Database::Postgres,
@ -126,7 +162,7 @@ fn test_option_parse() {
); );
let mut args = vec!["7", "ldap", "pgsql"].into_iter().peekable(); let mut args = vec!["7", "ldap", "pgsql"].into_iter().peekable();
assert_eq!( assert_eq!(
CloudOptions::parse(&[], &mut args).unwrap(), CloudOptions::parse(&config, &mut args).unwrap(),
CloudOptions { CloudOptions {
php: PhpVersion::Php74, php: PhpVersion::Php74,
db: Database::Postgres, db: Database::Postgres,
@ -136,7 +172,7 @@ fn test_option_parse() {
); );
let mut args = vec!["7", "pgsql", "ldap"].into_iter().peekable(); let mut args = vec!["7", "pgsql", "ldap"].into_iter().peekable();
assert_eq!( assert_eq!(
CloudOptions::parse(&[], &mut args).unwrap(), CloudOptions::parse(&config, &mut args).unwrap(),
CloudOptions { CloudOptions {
php: PhpVersion::Php74, php: PhpVersion::Php74,
db: Database::Postgres, db: Database::Postgres,
@ -147,17 +183,19 @@ fn test_option_parse() {
let mut args = vec!["7", "pgsql", "ldap", "mypreset"] let mut args = vec!["7", "pgsql", "ldap", "mypreset"]
.into_iter() .into_iter()
.peekable(); .peekable();
let config = HazeConfig {
preset: vec![Preset {
name: "mypreset".to_string(),
commands: Vec::new(),
apps: Vec::new(),
config: HashMap::default(),
}],
..HazeConfig::default()
};
assert_eq!( assert_eq!(
CloudOptions::parse( CloudOptions::parse(&config, &mut args).unwrap(),
&[Preset {
name: "mypreset".to_string(),
commands: Vec::new(),
apps: Vec::new(),
config: HashMap::default(),
}],
&mut args
)
.unwrap(),
CloudOptions { CloudOptions {
php: PhpVersion::Php74, php: PhpVersion::Php74,
db: Database::Postgres, db: Database::Postgres,

View file

@ -9,7 +9,7 @@ use std::fs::read_to_string;
use std::net::IpAddr; use std::net::IpAddr;
use toml::Value; use toml::Value;
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize, Default)]
#[serde(from = "RawHazeConfig")] #[serde(from = "RawHazeConfig")]
pub struct HazeConfig { pub struct HazeConfig {
pub sources_root: Utf8PathBuf, pub sources_root: Utf8PathBuf,

View file

@ -57,7 +57,7 @@ async fn main() -> Result<ExitCode> {
.wrap_err("Failed to connect to docker")?; .wrap_err("Failed to connect to docker")?;
let config = HazeConfig::load().wrap_err("Failed to load config")?; let config = HazeConfig::load().wrap_err("Failed to load config")?;
let args = HazeArgs::parse(&config.preset, std::env::args())?; let args = HazeArgs::parse(&config, std::env::args())?;
match args { match args {
HazeArgs::Clean => { HazeArgs::Clean => {
@ -265,7 +265,7 @@ async fn main() -> Result<ExitCode> {
cloud.destroy(&docker).await?; cloud.destroy(&docker).await?;
} }
HazeArgs::Fmt { path } => { HazeArgs::Fmt { path } => {
let cloud = Cloud::create(&docker, CloudOptions::default(), &config).await?; let cloud = Cloud::create(&docker, CloudOptions::new(&config), &config).await?;
let mut out_buffer = Vec::<u8>::with_capacity(1024); let mut out_buffer = Vec::<u8>::with_capacity(1024);
println!("Waiting for servers to start"); println!("Waiting for servers to start");
cloud.wait_for_start(&docker).await?; cloud.wait_for_start(&docker).await?;

View file

@ -106,6 +106,27 @@ impl PhpVersion {
} }
} }
pub fn from_number(major: u8, minor: u8) -> Option<Self> {
match (major, minor) {
(7, 3) => Some(PhpVersion::Php73),
(7, 4) => Some(PhpVersion::Php74),
(8, 0) => Some(PhpVersion::Php80),
(8, 1) => Some(PhpVersion::Php81),
(8, 2) => Some(PhpVersion::Php82),
(8, 3) => Some(PhpVersion::Php83),
(8, 4) => Some(PhpVersion::Php84),
_ => None,
}
}
pub fn max_minor(major: u8) -> u8 {
match major {
7 => 4,
8 => 4,
_ => 0,
}
}
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub async fn spawn( pub async fn spawn(
&self, &self,