Skip to main content

anodizer_core/config/
snapcraft.rs

1use std::collections::HashMap;
2
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6use super::archives::TemplatedExtraFile;
7use super::{StringOrBool, deserialize_string_or_bool_opt};
8
9// ---------------------------------------------------------------------------
10// SnapcraftConfig
11// ---------------------------------------------------------------------------
12
13#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
14#[serde(default, deny_unknown_fields)]
15pub struct SnapcraftConfig {
16    /// Unique identifier for this snapcraft config.
17    pub id: Option<String>,
18    /// Build IDs to include. Empty means all builds.
19    pub ids: Option<Vec<String>>,
20    /// Snap package name in the store.
21    pub name: Option<String>,
22    /// Canonical application title (user-facing in store).
23    pub title: Option<String>,
24    /// Single-line elevator pitch (max 79 characters).
25    pub summary: Option<String>,
26    /// Extended description (user-facing in store).
27    pub description: Option<String>,
28    /// Path to icon image file.
29    pub icon: Option<String>,
30    /// Runtime base snap: core, core18, core20, core22, core24, bare.
31    pub base: Option<String>,
32    /// Release stability level: stable, devel.
33    pub grade: Option<String>,
34    /// License identifier (SPDX format).
35    pub license: Option<String>,
36    /// Whether to publish to the snapcraft store.
37    pub publish: Option<bool>,
38    /// Distribution channels: edge, beta, candidate, stable.
39    pub channel_templates: Option<Vec<String>>,
40    /// Security confinement level: strict, devmode, classic.
41    pub confinement: Option<String>,
42    /// Top-level snap plug definitions (structured map).
43    /// Keys are plug names, values are either `null` (simple plug) or an object
44    /// with `interface` and optional attributes (e.g. `{ interface: "content", target: "$SNAP/shared" }`).
45    /// GoReleaser uses `map[string]any` for this field.
46    pub plugs: Option<HashMap<String, serde_json::Value>>,
47    // No top-level `slots:` — Snapcraft itself has no top-level slots
48    // concept; use `apps.<name>.slots` for per-app slots.
49    /// Required snapd features/versions.
50    pub assumes: Option<Vec<String>>,
51    /// Application configurations defining daemons, commands, env vars.
52    pub apps: Option<HashMap<String, SnapcraftApp>>,
53    /// Directory mappings for sandbox accessibility.
54    pub layouts: Option<HashMap<String, SnapcraftLayout>>,
55    /// Additional static files to bundle (string shorthand or structured form).
56    pub extra_files: Option<Vec<SnapcraftExtraFileSpec>>,
57    /// Extra files whose contents are rendered through the template engine before bundling.
58    /// Unlike `extra_files` which copy as-is, template variables like `{{ .Tag }}` are expanded.
59    /// GoReleaser Pro feature.
60    pub templated_extra_files: Option<Vec<TemplatedExtraFile>>,
61    /// Template for the output snap filename.
62    pub name_template: Option<String>,
63    /// Skip this snapcraft config. Accepts bool or template string
64    /// (e.g. `"{{ if .IsSnapshot }}true{{ endif }}"` for conditional skip).
65    /// Accepts the legacy `disable:` spelling via serde alias for back-compat
66    /// with imported GoReleaser configs (GR's snapcraft config field is
67    /// `pkg/config/config.go:1033` `Disable string`).
68    #[serde(
69        default,
70        alias = "disable",
71        deserialize_with = "deserialize_string_or_bool_opt"
72    )]
73    pub skip: Option<StringOrBool>,
74    /// Remove source archives from artifacts, keeping only snap.
75    pub replace: Option<bool>,
76    /// Output timestamp for reproducible builds.
77    pub mod_timestamp: Option<String>,
78    /// Snap hooks — maps hook name to arbitrary hook config.
79    pub hooks: Option<HashMap<String, serde_json::Value>>,
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
83#[serde(default)]
84pub struct SnapcraftApp {
85    /// Command to run (relative to snap root).
86    pub command: Option<String>,
87    /// Daemon type: simple, forking, oneshot, notify, dbus.
88    pub daemon: Option<String>,
89    /// How to stop the daemon: sigterm, sigkill, etc.
90    #[serde(alias = "stop-mode")]
91    pub stop_mode: Option<String>,
92    /// Interface plugs the app needs.
93    pub plugs: Option<Vec<String>>,
94    /// Environment variables for the app (supports string, integer, and boolean values).
95    pub environment: Option<HashMap<String, serde_json::Value>>,
96    /// Additional arguments passed to the command.
97    pub args: Option<String>,
98    /// Restart condition: on-failure, always, on-success, on-abnormal, on-abort, on-watchdog, never.
99    #[serde(alias = "restart-condition")]
100    pub restart_condition: Option<String>,
101    /// Snap adapter type: "none" or "full" (default: "full").
102    pub adapter: Option<String>,
103    /// Services that must start before this app.
104    pub after: Option<Vec<String>>,
105    /// Alternative names for the command.
106    pub aliases: Option<Vec<String>>,
107    /// Desktop file for autostart.
108    pub autostart: Option<String>,
109    /// Services that must start after this app.
110    pub before: Option<Vec<String>>,
111    /// D-Bus well-known bus name.
112    #[serde(alias = "bus-name")]
113    pub bus_name: Option<String>,
114    /// Wrapper commands run before the main command.
115    #[serde(alias = "command-chain")]
116    pub command_chain: Option<Vec<String>>,
117    /// AppStream metadata common ID.
118    #[serde(alias = "common-id")]
119    pub common_id: Option<String>,
120    /// Path to bash completion script relative to snap.
121    pub completer: Option<String>,
122    /// Path to .desktop file relative to snap.
123    pub desktop: Option<String>,
124    /// Snap extensions to apply.
125    pub extensions: Option<Vec<String>>,
126    /// Installation mode: "enable" or "disable".
127    #[serde(alias = "install-mode")]
128    pub install_mode: Option<String>,
129    /// Arbitrary YAML passed through to snap.yaml.
130    pub passthrough: Option<HashMap<String, serde_json::Value>>,
131    /// Command to run after daemon stops.
132    #[serde(alias = "post-stop-command")]
133    pub post_stop_command: Option<String>,
134    /// Refresh behavior: "endure" or "restart".
135    #[serde(alias = "refresh-mode")]
136    pub refresh_mode: Option<String>,
137    /// Command to reload daemon config.
138    #[serde(alias = "reload-command")]
139    pub reload_command: Option<String>,
140    /// Delay between restarts (duration string).
141    #[serde(alias = "restart-delay")]
142    pub restart_delay: Option<String>,
143    /// Interface slots this app provides.
144    pub slots: Option<Vec<String>>,
145    /// Socket definitions map.
146    pub sockets: Option<HashMap<String, serde_json::Value>>,
147    /// Start timeout duration string.
148    #[serde(alias = "start-timeout")]
149    pub start_timeout: Option<String>,
150    /// Command to gracefully stop the daemon.
151    #[serde(alias = "stop-command")]
152    pub stop_command: Option<String>,
153    /// Stop timeout duration string.
154    #[serde(alias = "stop-timeout")]
155    pub stop_timeout: Option<String>,
156    /// Timer definition (systemd timer syntax).
157    pub timer: Option<String>,
158    /// Watchdog timeout duration string.
159    #[serde(alias = "watchdog-timeout")]
160    pub watchdog_timeout: Option<String>,
161}
162
163#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
164#[serde(default)]
165pub struct SnapcraftLayout {
166    /// Bind-mount a directory to the snap's layout.
167    pub bind: Option<String>,
168    /// Bind-mount a single file to the snap's layout.
169    pub bind_file: Option<String>,
170    /// Symlink a path to a location in the snap.
171    pub symlink: Option<String>,
172    /// Layout entry type.
173    #[serde(rename = "type")]
174    pub type_: Option<String>,
175}
176
177/// Specifies an extra file for snapcraft. Can be a simple source path string or
178/// a structured object with source, destination, and mode fields (matching
179/// GoReleaser's SnapcraftExtraFiles).
180#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
181#[serde(untagged)]
182pub enum SnapcraftExtraFileSpec {
183    /// Simple source path string.
184    Source(String),
185    /// Structured form with source, destination, and mode.
186    Detailed {
187        source: String,
188        #[serde(skip_serializing_if = "Option::is_none")]
189        destination: Option<String>,
190        #[serde(skip_serializing_if = "Option::is_none")]
191        mode: Option<u32>,
192    },
193}
194
195impl SnapcraftExtraFileSpec {
196    /// Return the source path for this spec.
197    pub fn source(&self) -> &str {
198        match self {
199            SnapcraftExtraFileSpec::Source(s) => s,
200            SnapcraftExtraFileSpec::Detailed { source, .. } => source,
201        }
202    }
203
204    /// Return the optional destination path.
205    pub fn destination(&self) -> Option<&str> {
206        match self {
207            SnapcraftExtraFileSpec::Source(_) => None,
208            SnapcraftExtraFileSpec::Detailed { destination, .. } => destination.as_deref(),
209        }
210    }
211
212    /// Return the optional file mode.
213    pub fn mode(&self) -> Option<u32> {
214        match self {
215            SnapcraftExtraFileSpec::Source(_) => None,
216            SnapcraftExtraFileSpec::Detailed { mode, .. } => *mode,
217        }
218    }
219}