casc_lib/config/
build_config.rs1use std::collections::HashMap;
9
10use crate::error::Result;
11
12#[derive(Debug, Clone)]
17pub struct BuildConfig {
18 pub root_ckey: String,
20 pub encoding_ckey: String,
22 pub encoding_ekey: String,
24 pub encoding_size: Vec<u64>,
26 pub install_ckey: String,
28 pub install_ekey: String,
30 pub download_ckey: String,
32 pub download_ekey: String,
34 pub build_name: String,
36 pub build_uid: String,
38 pub build_product: String,
40 pub raw: HashMap<String, String>,
42}
43
44pub fn parse_build_config(content: &str) -> Result<BuildConfig> {
46 let mut raw: HashMap<String, String> = HashMap::new();
47
48 for line in content.lines() {
49 let trimmed = line.trim();
50 if trimmed.is_empty() || trimmed.starts_with('#') {
51 continue;
52 }
53
54 if let Some((key, value)) = trimmed.split_once(" = ") {
55 raw.insert(key.to_string(), value.to_string());
56 }
57 }
58
59 let get = |key: &str| -> String { raw.get(key).cloned().unwrap_or_default() };
60
61 let split_pair = |key: &str| -> (String, String) {
62 let val = get(key);
63 let mut parts = val.splitn(2, ' ');
64 let first = parts.next().unwrap_or("").to_string();
65 let second = parts.next().unwrap_or("").to_string();
66 (first, second)
67 };
68
69 let parse_sizes = |key: &str| -> Vec<u64> {
70 let val = get(key);
71 if val.is_empty() {
72 return Vec::new();
73 }
74 val.split(' ')
75 .filter_map(|s| s.parse::<u64>().ok())
76 .collect()
77 };
78
79 let (encoding_ckey, encoding_ekey) = split_pair("encoding");
80 let (install_ckey, install_ekey) = split_pair("install");
81 let (download_ckey, download_ekey) = split_pair("download");
82
83 Ok(BuildConfig {
84 root_ckey: get("root"),
85 encoding_ckey,
86 encoding_ekey,
87 encoding_size: parse_sizes("encoding-size"),
88 install_ckey,
89 install_ekey,
90 download_ckey,
91 download_ekey,
92 build_name: get("build-name"),
93 build_uid: get("build-uid"),
94 build_product: get("build-product"),
95 raw,
96 })
97}
98
99pub fn config_path(hash: &str) -> String {
103 format!("config/{}/{}/{}", &hash[..2], &hash[2..4], hash)
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109
110 const FIXTURE: &str = "# Build Configuration\nroot = 0ff1247849a5cd6049624d3a105811f8\ninstall = a33a459aa7585d626a3e4209858b4eed a9f3ece675323e1bbd2c17a765adc3c4\ninstall-size = 23286 22368\ndownload = 108fa2da5f5337d8eb4e35e0d3573925 697b5503715187be840f15ee5862adf4\ndownload-size = 72504201 61674341\nencoding = d2f601fe389b9a1133709e716899a633 d3e25753d9f33b6ab55c56532e2131cc\nencoding-size = 194221474 182793061\nbuild-name = WOW-66192patch12.0.1_Retail\nbuild-uid = wow\nbuild-product = WoW\n";
111
112 #[test]
113 fn parse_root_ckey() {
114 let config = parse_build_config(FIXTURE).unwrap();
115 assert_eq!(config.root_ckey, "0ff1247849a5cd6049624d3a105811f8");
116 }
117
118 #[test]
119 fn parse_encoding_pair() {
120 let config = parse_build_config(FIXTURE).unwrap();
121 assert_eq!(config.encoding_ckey, "d2f601fe389b9a1133709e716899a633");
122 assert_eq!(config.encoding_ekey, "d3e25753d9f33b6ab55c56532e2131cc");
123 }
124
125 #[test]
126 fn parse_encoding_sizes() {
127 let config = parse_build_config(FIXTURE).unwrap();
128 assert_eq!(config.encoding_size, vec![194221474, 182793061]);
129 }
130
131 #[test]
132 fn parse_build_name() {
133 let config = parse_build_config(FIXTURE).unwrap();
134 assert_eq!(config.build_name, "WOW-66192patch12.0.1_Retail");
135 }
136
137 #[test]
138 fn parse_build_uid() {
139 let config = parse_build_config(FIXTURE).unwrap();
140 assert_eq!(config.build_uid, "wow");
141 }
142
143 #[test]
144 fn parse_skips_comments() {
145 let data = "# comment\nroot = abc123\n";
146 let config = parse_build_config(data).unwrap();
147 assert_eq!(config.root_ckey, "abc123");
148 }
149
150 #[test]
151 fn parse_skips_empty_lines() {
152 let data = "\n\nroot = abc123\n\n";
153 let config = parse_build_config(data).unwrap();
154 assert_eq!(config.root_ckey, "abc123");
155 }
156
157 #[test]
158 fn config_path_from_hash() {
159 let path = config_path("13e1eb56839dfaf734d7fab21b0c8ea4");
160 assert_eq!(path, "config/13/e1/13e1eb56839dfaf734d7fab21b0c8ea4");
161 }
162}