1use std::collections::HashMap;
2
3use crate::config::{Config, GpuMode, XdgDirValue};
4
5pub type LabelMap = HashMap<String, String>;
7
8pub fn fetch(image_ref: &str) -> anyhow::Result<LabelMap> {
10 let output = std::process::Command::new("podman")
11 .args(["inspect", "--format", "{{json .Labels}}", image_ref])
12 .output()?;
13
14 if !output.status.success() {
15 return Ok(LabelMap::new());
16 }
17
18 let stdout = String::from_utf8_lossy(&output.stdout);
19 let map: LabelMap = serde_json::from_str(stdout.trim()).unwrap_or_default();
20 Ok(map)
21}
22
23pub fn apply_defaults(config: &mut Config, labels: &LabelMap) {
29 match labels
31 .get("podbox.schema")
32 .or_else(|| labels.get("podmgr.schema"))
33 .map(|s| s.as_str())
34 {
35 Some("1") => {}
36 Some(v) => {
37 eprintln!(
38 "Warning: image declares podbox.schema={}, host supports 1. \
39 Ignoring image labels.",
40 v
41 );
42 return;
43 }
44 None => return,
45 }
46
47 let int = &mut config.integration;
48
49 apply_bool_compat(
50 labels,
51 "podbox.integration.wayland",
52 "podmgr.integration.wayland",
53 &mut int.wayland,
54 );
55 apply_bool_compat(
56 labels,
57 "podbox.integration.audio",
58 "podmgr.integration.audio",
59 &mut int.audio,
60 );
61 apply_bool_compat(
62 labels,
63 "podbox.integration.dbus",
64 "podmgr.integration.dbus",
65 &mut int.dbus,
66 );
67 apply_bool_compat(
68 labels,
69 "podbox.integration.notify",
70 "podmgr.integration.notify",
71 &mut int.notify,
72 );
73 apply_bool_compat(
74 labels,
75 "podbox.integration.xdg_open",
76 "podmgr.integration.xdg_open",
77 &mut int.xdg_open,
78 );
79 apply_bool_compat(
80 labels,
81 "podbox.integration.clipboard",
82 "podmgr.integration.clipboard",
83 &mut int.clipboard,
84 );
85 apply_bool_compat(
86 labels,
87 "podbox.integration.sync_fonts",
88 "podmgr.integration.sync_fonts",
89 &mut int.sync_fonts,
90 );
91 apply_bool_compat(
92 labels,
93 "podbox.integration.sync_icons",
94 "podmgr.integration.sync_icons",
95 &mut int.sync_icons,
96 );
97 apply_bool_compat(
98 labels,
99 "podbox.integration.sync_themes",
100 "podmgr.integration.sync_themes",
101 &mut int.sync_themes,
102 );
103
104 apply_xdg_compat(
105 labels,
106 "podbox.xdg_dirs.documents",
107 "podmgr.xdg_dirs.documents",
108 &mut int.xdg_dirs.documents,
109 );
110 apply_xdg_compat(
111 labels,
112 "podbox.xdg_dirs.downloads",
113 "podmgr.xdg_dirs.downloads",
114 &mut int.xdg_dirs.downloads,
115 );
116 apply_xdg_compat(
117 labels,
118 "podbox.xdg_dirs.pictures",
119 "podmgr.xdg_dirs.pictures",
120 &mut int.xdg_dirs.pictures,
121 );
122 apply_xdg_compat(
123 labels,
124 "podbox.xdg_dirs.music",
125 "podmgr.xdg_dirs.music",
126 &mut int.xdg_dirs.music,
127 );
128 apply_xdg_compat(
129 labels,
130 "podbox.xdg_dirs.videos",
131 "podmgr.xdg_dirs.videos",
132 &mut int.xdg_dirs.videos,
133 );
134 apply_xdg_compat(
135 labels,
136 "podbox.xdg_dirs.desktop",
137 "podmgr.xdg_dirs.desktop",
138 &mut int.xdg_dirs.desktop,
139 );
140 apply_xdg_compat(
141 labels,
142 "podbox.xdg_dirs.projects",
143 "podmgr.xdg_dirs.projects",
144 &mut int.xdg_dirs.projects,
145 );
146
147 let gpu_key = if labels.contains_key("podbox.integration.gpu") {
149 "podbox.integration.gpu"
150 } else {
151 "podmgr.integration.gpu"
152 };
153 if let Some(gpu_str) = labels.get(gpu_key) {
154 if config.integration.gpu == GpuMode::Auto {
155 config.integration.gpu = match gpu_str.as_str() {
156 "true" => GpuMode::Enabled,
157 "false" => GpuMode::Disabled,
158 "nvidia" => GpuMode::Nvidia,
159 _ => GpuMode::Auto,
160 };
161 }
162 }
163
164 let shell_key = if labels.contains_key("podbox.default_shell") {
166 "podbox.default_shell"
167 } else {
168 "podmgr.default_shell"
169 };
170 if let Some(shell) = labels.get(shell_key) {
171 if config.container.shell == "fish" {
172 config.container.shell = shell.clone();
173 }
174 }
175}
176
177fn apply_bool(labels: &LabelMap, key: &str, field: &mut bool) {
178 if let Some(v) = labels.get(key) {
179 *field = v == "true";
180 }
181}
182
183fn apply_bool_compat(labels: &LabelMap, new_key: &str, old_key: &str, field: &mut bool) {
184 if labels.contains_key(new_key) {
186 apply_bool(labels, new_key, field);
187 } else {
188 apply_bool(labels, old_key, field);
189 }
190}
191
192fn apply_xdg_compat(labels: &LabelMap, new_key: &str, old_key: &str, field: &mut XdgDirValue) {
193 let key = if labels.contains_key(new_key) {
194 new_key
195 } else {
196 old_key
197 };
198 if let Some(v) = labels.get(key) {
199 if v == "true" {
200 *field = XdgDirValue::Simple(true);
201 }
202 }
203}