1use std::path::PathBuf;
6
7use config::{ConfigError, File};
8use sozu_command_lib::config::{Config, ConfigBuilder, ConfigError as ConfigBuilderError};
9
10#[derive(thiserror::Error, Debug)]
14pub enum Error {
15 #[error("failed to load configuration from path '{0}', {1}")]
16 Build(String, ConfigError),
17 #[error("failed to deserialize configuration keys-values into internal structure, {0}")]
18 Deserialize(ConfigError),
19 #[error("failed to convert configuration into internal representation structure, {0}")]
20 Convert(ConfigBuilderError),
21 #[error("failed to convert path to utf-8 string, there is incompatibility, {0}")]
22 PathIsInvalid(String),
23 #[error("failed to canonicalize the command socket path, {0}")]
24 Canonicalize(std::io::Error),
25}
26
27#[tracing::instrument]
32pub fn try_from(path: &PathBuf) -> Result<Config, Error> {
33 let file_config = config::Config::builder()
34 .add_source(File::from(path.as_path()).required(true))
35 .build()
36 .map_err(|err| Error::Build(path.display().to_string(), err))?
37 .try_deserialize()
38 .map_err(Error::Deserialize)?;
39
40 let config_path = path
41 .to_str()
42 .ok_or_else(|| Error::PathIsInvalid(path.display().to_string()))?;
43
44 ConfigBuilder::new(file_config, config_path)
45 .into_config()
46 .map_err(Error::Convert)
47}
48
49#[tracing::instrument(skip_all)]
53pub fn canonicalize_command_socket(path: &PathBuf, config: &Config) -> Result<PathBuf, Error> {
54 match &config.command_socket {
55 socket if socket.starts_with('/') => Ok(PathBuf::from(socket)),
57 socket => {
59 let mut socket_path = PathBuf::from(socket)
60 .parent()
61 .ok_or_else(|| Error::PathIsInvalid(path.display().to_string()))?
62 .to_owned();
63
64 socket_path.push(path);
65 socket_path.canonicalize().map_err(Error::Canonicalize)
66 }
67 }
68}