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={v}, host supports 1. \
39 Ignoring image labels."
40 );
41 return;
42 }
43 None => return,
44 }
45
46 let int = &mut config.integration;
47
48 apply_bool_compat(
49 labels,
50 "podbox.integration.wayland",
51 "podmgr.integration.wayland",
52 &mut int.wayland,
53 );
54 apply_bool_compat(
55 labels,
56 "podbox.integration.audio",
57 "podmgr.integration.audio",
58 &mut int.audio,
59 );
60 apply_bool_compat(
61 labels,
62 "podbox.integration.dbus",
63 "podmgr.integration.dbus",
64 &mut int.dbus,
65 );
66 apply_bool_compat(
67 labels,
68 "podbox.integration.notify",
69 "podmgr.integration.notify",
70 &mut int.notify,
71 );
72 apply_bool_compat(
73 labels,
74 "podbox.integration.xdg_open",
75 "podmgr.integration.xdg_open",
76 &mut int.xdg_open,
77 );
78 apply_bool_compat(
79 labels,
80 "podbox.integration.clipboard",
81 "podmgr.integration.clipboard",
82 &mut int.clipboard,
83 );
84 apply_bool_compat(
85 labels,
86 "podbox.integration.sync_fonts",
87 "podmgr.integration.sync_fonts",
88 &mut int.sync_fonts,
89 );
90 apply_bool_compat(
91 labels,
92 "podbox.integration.sync_icons",
93 "podmgr.integration.sync_icons",
94 &mut int.sync_icons,
95 );
96 apply_bool_compat(
97 labels,
98 "podbox.integration.sync_themes",
99 "podmgr.integration.sync_themes",
100 &mut int.sync_themes,
101 );
102
103 apply_xdg_compat(
104 labels,
105 "podbox.xdg_dirs.documents",
106 "podmgr.xdg_dirs.documents",
107 &mut int.xdg_dirs.documents,
108 );
109 apply_xdg_compat(
110 labels,
111 "podbox.xdg_dirs.downloads",
112 "podmgr.xdg_dirs.downloads",
113 &mut int.xdg_dirs.downloads,
114 );
115 apply_xdg_compat(
116 labels,
117 "podbox.xdg_dirs.pictures",
118 "podmgr.xdg_dirs.pictures",
119 &mut int.xdg_dirs.pictures,
120 );
121 apply_xdg_compat(
122 labels,
123 "podbox.xdg_dirs.music",
124 "podmgr.xdg_dirs.music",
125 &mut int.xdg_dirs.music,
126 );
127 apply_xdg_compat(
128 labels,
129 "podbox.xdg_dirs.videos",
130 "podmgr.xdg_dirs.videos",
131 &mut int.xdg_dirs.videos,
132 );
133 apply_xdg_compat(
134 labels,
135 "podbox.xdg_dirs.desktop",
136 "podmgr.xdg_dirs.desktop",
137 &mut int.xdg_dirs.desktop,
138 );
139 apply_xdg_compat(
140 labels,
141 "podbox.xdg_dirs.projects",
142 "podmgr.xdg_dirs.projects",
143 &mut int.xdg_dirs.projects,
144 );
145
146 let gpu_key = if labels.contains_key("podbox.integration.gpu") {
148 "podbox.integration.gpu"
149 } else {
150 "podmgr.integration.gpu"
151 };
152 if let Some(gpu_str) = labels.get(gpu_key) {
153 if config.integration.gpu == GpuMode::Auto {
154 config.integration.gpu = match gpu_str.as_str() {
155 "true" => GpuMode::Enabled,
156 "false" => GpuMode::Disabled,
157 "nvidia" => GpuMode::Nvidia,
158 _ => GpuMode::Auto,
159 };
160 }
161 }
162
163 let shell_key = if labels.contains_key("podbox.default_shell") {
165 "podbox.default_shell"
166 } else {
167 "podmgr.default_shell"
168 };
169 if let Some(shell) = labels.get(shell_key) {
170 if config.container.shell == "fish" {
171 config.container.shell.clone_from(shell);
172 }
173 }
174}
175
176fn apply_bool(labels: &LabelMap, key: &str, field: &mut bool) {
177 if let Some(v) = labels.get(key) {
178 *field = v == "true";
179 }
180}
181
182fn apply_bool_compat(labels: &LabelMap, new_key: &str, old_key: &str, field: &mut bool) {
183 if labels.contains_key(new_key) {
185 apply_bool(labels, new_key, field);
186 } else {
187 apply_bool(labels, old_key, field);
188 }
189}
190
191fn apply_xdg_compat(labels: &LabelMap, new_key: &str, old_key: &str, field: &mut XdgDirValue) {
192 let key = if labels.contains_key(new_key) {
193 new_key
194 } else {
195 old_key
196 };
197 if let Some(v) = labels.get(key) {
198 if v == "true" {
199 *field = XdgDirValue::Simple(true);
200 }
201 }
202}