1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use super::{
    guid::decode_guid,
    unescape::{unescape, UnescapeError},
    GuidError,
};
use crate::{Guid, Launchd};
use std::convert::TryFrom;
use thiserror::Error;

#[derive(Debug, Clone, Error)]
pub enum LaunchdError {
    #[error("Could not unescape: {0}")]
    UnescapeError(#[from] UnescapeError),
    #[error("GUID error: {0}")]
    GuidError(#[from] GuidError),
    #[error("Unknown key")]
    UnknownKey,
    #[error("Env is duplicate")]
    EnvDuplicate,
    #[error("Env is missing")]
    EnvMissing,
}

impl Launchd {
    fn decode_env(env_str: &str, env: &mut Option<String>) -> Result<(), LaunchdError> {
        if env.is_none() {
            let env_str = unescape(env_str)?;
            *env = Some(env_str);
            Ok(())
        } else {
            Err(LaunchdError::EnvDuplicate)
        }
    }

    fn decode_key_value(
        key_value: &str,
        env: &mut Option<String>,
        guid: &mut Option<Guid>,
    ) -> Result<(), LaunchdError> {
        if let Some(env_str) = key_value.strip_prefix("env=") {
            Launchd::decode_env(env_str, env)
        } else if let Some(guid_str) = key_value.strip_prefix("guid=") {
            decode_guid(guid_str, guid)?;
            Ok(())
        } else {
            Err(LaunchdError::UnknownKey)
        }
    }
}

impl TryFrom<&str> for Launchd {
    type Error = LaunchdError;

    fn try_from(server_address: &str) -> Result<Self, Self::Error> {
        let mut env = None;
        let mut guid = None;

        for key_value in server_address.split(',') {
            Launchd::decode_key_value(key_value, &mut env, &mut guid)?;
        }

        if let Some(env) = env {
            Ok(Launchd { env, guid })
        } else {
            Err(LaunchdError::EnvMissing)
        }
    }
}