mirror of
https://codeberg.org/icewind/haze.git
synced 2026-06-03 09:04:12 +02:00
allow configuring additional app directories and add a writable app directory
fixes #15
This commit is contained in:
parent
862d33b017
commit
b7ea4e9760
6 changed files with 130 additions and 34 deletions
|
|
@ -505,6 +505,7 @@ impl SubCommand for HazeCommand {
|
|||
fn test_arg_parse() {
|
||||
let config = HazeConfig {
|
||||
sources_root: Default::default(),
|
||||
app_directories: Default::default(),
|
||||
work_dir: Default::default(),
|
||||
auto_setup: Default::default(),
|
||||
volume: vec![],
|
||||
|
|
|
|||
69
src/cloud.rs
69
src/cloud.rs
|
|
@ -1,7 +1,7 @@
|
|||
use crate::config::{HazeConfig, HazeVolumeConfig};
|
||||
use crate::database::Database;
|
||||
use crate::exec::{exec, exec_io, exec_tty, ExitCode};
|
||||
use crate::mapping::{default_mappings, Mapping};
|
||||
use crate::mapping::{for_config, Mapping};
|
||||
use crate::php::{PhpVersion, PHP_MEMORY_LIMIT};
|
||||
use crate::service::Service;
|
||||
use crate::service::ServiceTrait;
|
||||
|
|
@ -15,14 +15,14 @@ use flate2::read::GzDecoder;
|
|||
use futures_util::future::try_join_all;
|
||||
use miette::{IntoDiagnostic, Report, Result, WrapErr};
|
||||
use petname::petname;
|
||||
use serde_json::Value;
|
||||
use serde_json::{Map, Value};
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Display;
|
||||
use std::fs;
|
||||
use std::fs::read_to_string;
|
||||
use std::fs::{read_to_string, write};
|
||||
use std::io::{stdout, Cursor, Read, Stdout, Write};
|
||||
use std::iter::Peekable;
|
||||
use std::iter::{once, Peekable};
|
||||
use std::net::IpAddr;
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
use std::str::FromStr;
|
||||
|
|
@ -286,11 +286,8 @@ impl Cloud {
|
|||
})
|
||||
})
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
let mappings = config
|
||||
.volume
|
||||
.iter()
|
||||
.map(Mapping::from)
|
||||
.chain(default_mappings())
|
||||
|
||||
let mappings = for_config(config)
|
||||
.chain(app_volumes.iter().map(Mapping::from))
|
||||
.collect::<Vec<_>>();
|
||||
for mapping in &mappings {
|
||||
|
|
@ -300,6 +297,48 @@ impl Cloud {
|
|||
.wrap_err_with(|| format!("Failed to setup work directory {}", mapping.source))?;
|
||||
}
|
||||
|
||||
let mut nc_config = Value::Object(Map::new());
|
||||
nc_config["apps_paths"] = Value::Array(
|
||||
once("apps")
|
||||
.chain(
|
||||
config
|
||||
.app_directories
|
||||
.iter()
|
||||
.filter_map(|dir| dir.file_name()),
|
||||
)
|
||||
.map(|name| {
|
||||
[
|
||||
(
|
||||
String::from("path"),
|
||||
Value::from(format!("/var/www/html/{}", name)),
|
||||
),
|
||||
(String::from("url"), Value::from(format!("/{}", name))),
|
||||
(String::from("writable"), Value::from(false)),
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
})
|
||||
.chain(once(
|
||||
[
|
||||
(
|
||||
String::from("path"),
|
||||
Value::from("/var/www/html/store_apps"),
|
||||
),
|
||||
(String::from("url"), Value::from("/store_apps")),
|
||||
(String::from("writable"), Value::from(true)),
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
))
|
||||
.collect(),
|
||||
);
|
||||
write(
|
||||
workdir.join("config/nextcloud.json"),
|
||||
serde_json::to_string_pretty(&nc_config).unwrap(),
|
||||
)
|
||||
.into_diagnostic()
|
||||
.wrap_err("Failed to write config json")?;
|
||||
|
||||
let network = docker
|
||||
.create_network(NetworkCreateRequest {
|
||||
name: id.clone(),
|
||||
|
|
@ -500,10 +539,7 @@ impl Cloud {
|
|||
pub async fn destroy(self, docker: &Docker) -> Result<()> {
|
||||
for container in self.containers {
|
||||
docker
|
||||
.kill_container(
|
||||
container.trim_start_matches('/'),
|
||||
None,
|
||||
)
|
||||
.kill_container(container.trim_start_matches('/'), None)
|
||||
.await
|
||||
.into_diagnostic()
|
||||
.wrap_err("Failed to kill container")?;
|
||||
|
|
@ -802,12 +838,7 @@ impl Cloud {
|
|||
format!("/var/www/html/{path}").into()
|
||||
};
|
||||
|
||||
let mut mappings = config
|
||||
.volume
|
||||
.iter()
|
||||
.map(Mapping::from)
|
||||
.chain(default_mappings())
|
||||
.collect::<Vec<_>>();
|
||||
let mut mappings = for_config(config).collect::<Vec<_>>();
|
||||
mappings.sort_by_key(|mapping| usize::MAX - mapping.target.as_str().len());
|
||||
|
||||
for mapping in mappings {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use miette::{IntoDiagnostic, Report, Result, WrapErr};
|
|||
use serde::Deserialize;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::env::var;
|
||||
use std::env::home_dir;
|
||||
use std::fs::read_to_string;
|
||||
use std::net::IpAddr;
|
||||
use toml::Value;
|
||||
|
|
@ -13,6 +13,7 @@ use toml::Value;
|
|||
#[serde(from = "RawHazeConfig")]
|
||||
pub struct HazeConfig {
|
||||
pub sources_root: Utf8PathBuf,
|
||||
pub app_directories: Vec<Utf8PathBuf>,
|
||||
pub work_dir: Utf8PathBuf,
|
||||
pub auto_setup: HazeAutoSetupConfig,
|
||||
pub volume: Vec<HazeVolumeConfig>,
|
||||
|
|
@ -27,6 +28,8 @@ pub struct RawHazeConfig {
|
|||
#[serde(default = "default_work_dir")]
|
||||
pub work_dir: Utf8PathBuf,
|
||||
#[serde(default)]
|
||||
pub app_directories: Vec<Utf8PathBuf>,
|
||||
#[serde(default)]
|
||||
pub auto_setup: HazeAutoSetupConfig,
|
||||
#[serde(default)]
|
||||
pub volume: Vec<HazeVolumeConfig>,
|
||||
|
|
@ -42,7 +45,11 @@ impl From<RawHazeConfig> for HazeConfig {
|
|||
fn from(raw: RawHazeConfig) -> Self {
|
||||
fn normalize_path(path: Utf8PathBuf) -> Utf8PathBuf {
|
||||
if path.starts_with("~") {
|
||||
let home = var("HOME").expect("HOME not set");
|
||||
let home = home_dir().expect("can't detect home directory");
|
||||
let home = home
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.expect("non-utf8 home directory");
|
||||
format!("{}{}", home, &path.as_str()[1..]).into()
|
||||
} else {
|
||||
path
|
||||
|
|
@ -51,6 +58,11 @@ impl From<RawHazeConfig> for HazeConfig {
|
|||
|
||||
HazeConfig {
|
||||
sources_root: normalize_path(raw.sources_root),
|
||||
app_directories: raw
|
||||
.app_directories
|
||||
.into_iter()
|
||||
.map(normalize_path)
|
||||
.collect(),
|
||||
work_dir: normalize_path(raw.work_dir),
|
||||
auto_setup: raw.auto_setup,
|
||||
volume: raw.volume,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
use crate::config::{HazeConfig, HazeVolumeConfig};
|
||||
use camino::{Utf8Path, Utf8PathBuf};
|
||||
use miette::{IntoDiagnostic, Result};
|
||||
use std::borrow::Cow;
|
||||
use tokio::fs::{create_dir_all, write};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Mapping<'a> {
|
||||
source_type: MappingSourceType,
|
||||
pub source: &'a Utf8Path,
|
||||
pub target: &'a Utf8Path,
|
||||
pub source: Cow<'a, Utf8Path>,
|
||||
pub target: Cow<'a, Utf8Path>,
|
||||
mapping_type: MappingType,
|
||||
read_only: bool,
|
||||
map: bool,
|
||||
|
|
@ -23,6 +24,26 @@ impl<'a> Mapping<'a> {
|
|||
where
|
||||
Target: Into<&'a Utf8Path>,
|
||||
Source: Into<&'a Utf8Path>,
|
||||
{
|
||||
Mapping {
|
||||
source_type,
|
||||
source: Cow::Borrowed(source.into()),
|
||||
target: Cow::Borrowed(target.into()),
|
||||
mapping_type: MappingType::Folder,
|
||||
read_only: false,
|
||||
map: true,
|
||||
create: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn owned<Source, Target>(
|
||||
source_type: MappingSourceType,
|
||||
source: Source,
|
||||
target: Target,
|
||||
) -> Self
|
||||
where
|
||||
Target: Into<Cow<'a, Utf8Path>>,
|
||||
Source: Into<Cow<'a, Utf8Path>>,
|
||||
{
|
||||
Mapping {
|
||||
source_type,
|
||||
|
|
@ -65,10 +86,10 @@ impl<'a> Mapping<'a> {
|
|||
return Ok(());
|
||||
}
|
||||
let source = match self.source_type {
|
||||
MappingSourceType::WorkDir => config.work_dir.join(id).join(self.source),
|
||||
MappingSourceType::GlobalWorkDir => config.work_dir.join(self.source),
|
||||
MappingSourceType::WorkDir => config.work_dir.join(id).join(self.source.as_ref()),
|
||||
MappingSourceType::GlobalWorkDir => config.work_dir.join(self.source.as_ref()),
|
||||
MappingSourceType::Sources => return Ok(()),
|
||||
MappingSourceType::Absolute => self.source.into(),
|
||||
MappingSourceType::Absolute => self.source.as_ref().into(),
|
||||
};
|
||||
match self.mapping_type {
|
||||
MappingType::Folder => create_dir_all(source).await.into_diagnostic()?,
|
||||
|
|
@ -80,10 +101,10 @@ impl<'a> Mapping<'a> {
|
|||
|
||||
pub fn source(&self, id: &str, config: &HazeConfig, source_root: &Utf8Path) -> Utf8PathBuf {
|
||||
match self.source_type {
|
||||
MappingSourceType::WorkDir => config.work_dir.join(id).join(self.source),
|
||||
MappingSourceType::GlobalWorkDir => config.work_dir.join(self.source),
|
||||
MappingSourceType::Sources => source_root.join(self.source),
|
||||
MappingSourceType::Absolute => self.source.into(),
|
||||
MappingSourceType::WorkDir => config.work_dir.join(id).join(self.source.as_ref()),
|
||||
MappingSourceType::GlobalWorkDir => config.work_dir.join(self.source.as_ref()),
|
||||
MappingSourceType::Sources => source_root.join(self.source.as_ref()),
|
||||
MappingSourceType::Absolute => self.source.as_ref().into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -112,6 +133,7 @@ pub fn default_mappings<'a>() -> impl IntoIterator<Item = Mapping<'a>> {
|
|||
Mapping::new(Sources, "", "/var/www/html"),
|
||||
Mapping::new(WorkDir, "data", "/var/www/html/data"),
|
||||
Mapping::new(WorkDir, "config", "/var/www/html/config"),
|
||||
Mapping::new(WorkDir, "store_app", "/var/www/html/store_app"),
|
||||
Mapping::new(WorkDir, "data-autotest", "/var/www/html/data-autotest"),
|
||||
Mapping::new(WorkDir, "skeleton", "/var/www/html/core/skeleton"),
|
||||
Mapping::new(
|
||||
|
|
@ -168,9 +190,30 @@ pub fn default_mappings<'a>() -> impl IntoIterator<Item = Mapping<'a>> {
|
|||
Mapping::new(WorkDir, "profiling", "/tmp/profiling"),
|
||||
Mapping::new(WorkDir, "php-config", "/config"),
|
||||
];
|
||||
|
||||
IntoIterator::into_iter(mappings)
|
||||
}
|
||||
|
||||
pub fn for_config<'a>(config: &'a HazeConfig) -> impl Iterator<Item = Mapping<'a>> {
|
||||
let app_dir_mappings = config.app_directories.iter().map(|dir| {
|
||||
Mapping::owned(
|
||||
MappingSourceType::Absolute,
|
||||
dir.as_path(),
|
||||
Cow::Owned(Utf8PathBuf::from(format!(
|
||||
"/var/www/html/{}",
|
||||
dir.file_name().unwrap()
|
||||
))),
|
||||
)
|
||||
});
|
||||
|
||||
config
|
||||
.volume
|
||||
.iter()
|
||||
.map(Mapping::from)
|
||||
.chain(app_dir_mappings)
|
||||
.chain(default_mappings())
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum MappingSourceType {
|
||||
Sources,
|
||||
|
|
@ -194,8 +237,8 @@ impl<'a> From<&'a HazeVolumeConfig> for Mapping<'a> {
|
|||
};
|
||||
Mapping {
|
||||
source_type: MappingSourceType::Absolute,
|
||||
source: config.source.as_path(),
|
||||
target: config.target.as_path(),
|
||||
source: Cow::Borrowed(config.source.as_path()),
|
||||
target: Cow::Borrowed(config.target.as_path()),
|
||||
mapping_type: ty,
|
||||
read_only: config.read_only,
|
||||
map: true,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue