anodizer_core/packagers.rs
1//! Packaging-axis config types lifted out of the monolithic
2//! `crate::config` module per the WAVE 5 split (see
3//! `.claude/known-bugs.md`'s "WAVE 5 deferred" entry).
4//!
5//! Currently houses [`MakeselfConfig`] + helpers and [`SrpmConfig`].
6//! The remaining packaging types (`NfpmConfig`, `SnapcraftConfig`,
7//! `FlatpakConfig`, `AppBundleConfig`, `DmgConfig`, `PkgConfig`,
8//! `MsiConfig`, `NsisConfig`) still live in `config.rs` and will move
9//! here in subsequent extraction passes — each with their dedicated
10//! deserializer / `*_schema()` helper alongside.
11//!
12//! Public API path is preserved by re-exports in `config.rs` so consumers
13//! can keep importing from `anodizer_core::config::*`.
14
15use crate::config::{
16 NfpmContent, NfpmSignatureConfig, StringOrBool, deserialize_string_or_bool_opt,
17};
18use schemars::JsonSchema;
19use serde::{Deserialize, Deserializer, Serialize};
20
21// ---------------------------------------------------------------------------
22// MakeselfConfig
23// ---------------------------------------------------------------------------
24
25#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
26#[serde(default)]
27pub struct MakeselfConfig {
28 /// Unique identifier for this makeself config (default: "default").
29 pub id: Option<String>,
30 /// Build IDs filter: only include artifacts whose `id` is in this list.
31 pub ids: Option<Vec<String>>,
32 /// Output filename template (default includes project, version, os, arch).
33 pub filename: Option<String>,
34 /// Display name embedded in the self-extracting archive.
35 pub name: Option<String>,
36 /// Startup script to run when the archive is extracted and executed.
37 /// Required — the archive will not be created without this.
38 pub script: Option<String>,
39 /// Description for LSM metadata.
40 pub description: Option<String>,
41 /// Maintainer for LSM metadata.
42 pub maintainer: Option<String>,
43 /// Keywords for LSM metadata.
44 pub keywords: Option<Vec<String>>,
45 /// Homepage URL for LSM metadata.
46 pub homepage: Option<String>,
47 /// License for LSM metadata.
48 pub license: Option<String>,
49 /// Compression algorithm: gzip, bzip2, xz, lzo, compress, or none.
50 pub compression: Option<String>,
51 /// Extra arguments passed to the makeself command.
52 pub extra_args: Option<Vec<String>>,
53 /// Additional files to include in the archive.
54 pub files: Option<Vec<MakeselfFile>>,
55 /// Target OS filter (default: ["linux", "darwin"]).
56 pub goos: Option<Vec<String>>,
57 /// Target architecture filter.
58 pub goarch: Option<Vec<String>>,
59 /// Skip this config. Accepts bool or template string.
60 #[serde(deserialize_with = "deserialize_string_or_bool_opt", default)]
61 pub skip: Option<StringOrBool>,
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
65#[serde(default)]
66pub struct MakeselfFile {
67 /// Source file path (relative to project root).
68 pub source: String,
69 /// Destination path inside the archive.
70 pub destination: Option<String>,
71 /// Strip the parent directory from the source path.
72 pub strip_parent: Option<bool>,
73}
74
75/// Deserialize makeselfs: single object → vec of one, array → vec of many.
76pub(crate) fn deserialize_makeselfs<'de, D>(
77 deserializer: D,
78) -> Result<Vec<MakeselfConfig>, D::Error>
79where
80 D: Deserializer<'de>,
81{
82 use serde::de::{self, Visitor};
83
84 struct MakeselfVisitor;
85
86 impl<'de> Visitor<'de> for MakeselfVisitor {
87 type Value = Vec<MakeselfConfig>;
88
89 fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90 f.write_str("a makeself config object or an array of makeself config objects")
91 }
92
93 fn visit_seq<A: de::SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
94 let mut configs = Vec::new();
95 while let Some(item) = seq.next_element::<MakeselfConfig>()? {
96 configs.push(item);
97 }
98 Ok(configs)
99 }
100
101 fn visit_map<M: de::MapAccess<'de>>(self, map: M) -> Result<Self::Value, M::Error> {
102 let config = MakeselfConfig::deserialize(de::value::MapAccessDeserializer::new(map))?;
103 Ok(vec![config])
104 }
105
106 fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
107 Ok(Vec::new())
108 }
109
110 fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
111 Ok(Vec::new())
112 }
113 }
114
115 deserializer.deserialize_any(MakeselfVisitor)
116}
117
118pub(crate) fn makeselfs_schema(
119 generator: &mut schemars::r#gen::SchemaGenerator,
120) -> schemars::schema::Schema {
121 let mut schema = generator.subschema_for::<Vec<MakeselfConfig>>();
122 if let schemars::schema::Schema::Object(ref mut obj) = schema {
123 obj.metadata().description = Some(
124 "Makeself self-extracting archive configurations. Accepts a single object or array."
125 .to_owned(),
126 );
127 }
128 schema
129}
130
131// ---------------------------------------------------------------------------
132// SrpmConfig
133// ---------------------------------------------------------------------------
134
135#[derive(Debug, Clone, Serialize, Deserialize, Default, JsonSchema)]
136#[serde(default)]
137pub struct SrpmConfig {
138 /// Enable source RPM generation. Default: false.
139 pub enabled: Option<bool>,
140 /// Package name (default: project_name).
141 pub package_name: Option<String>,
142 /// Output filename template.
143 pub file_name_template: Option<String>,
144 /// Path to the RPM spec file template.
145 pub spec_file: Option<String>,
146 /// RPM epoch.
147 pub epoch: Option<String>,
148 /// RPM section.
149 pub section: Option<String>,
150 /// Package maintainer.
151 pub maintainer: Option<String>,
152 /// Package vendor.
153 pub vendor: Option<String>,
154 /// Summary line.
155 pub summary: Option<String>,
156 /// RPM group.
157 pub group: Option<String>,
158 /// Package description.
159 pub description: Option<String>,
160 /// License identifier.
161 pub license: Option<String>,
162 /// License file name to include.
163 pub license_file_name: Option<String>,
164 /// Homepage URL.
165 pub url: Option<String>,
166 /// RPM packager field.
167 pub packager: Option<String>,
168 /// Compression algorithm (gzip, xz, zstd, none).
169 pub compression: Option<String>,
170 /// Documentation files to include.
171 pub docs: Option<Vec<String>>,
172 /// Additional contents to include in the source RPM. Shares the unified
173 /// [`NfpmContent`] type with nFPM contents; SRPM-style `source:` /
174 /// `destination:` / `type:` keys are accepted via serde aliases.
175 pub contents: Option<Vec<NfpmContent>>,
176 /// RPM signature configuration. Shares the unified
177 /// [`NfpmSignatureConfig`] type with nFPM.
178 pub signature: Option<NfpmSignatureConfig>,
179 /// Build IDs whose binaries are bundled into the source RPM. When set,
180 /// only artifacts produced by builds with these IDs are packaged.
181 /// Mirrors GR `NFPM.Builds`.
182 pub bins: Option<Vec<String>>,
183 /// Project import path (Go-style; for Rust this is the canonical
184 /// repository URL, e.g. `github.com/owner/repo`). Used in spec file
185 /// generation for downstream tooling that expects a vcs-rooted path.
186 pub import_path: Option<String>,
187 /// Filesystem prefixes the package may install to (RPM `Prefix:` tag).
188 /// Each entry becomes one `Prefix:` directive — relocatable RPMs need
189 /// at least one prefix declared.
190 pub prefixes: Option<Vec<String>>,
191 /// Override the build host recorded in the RPM header. Useful for
192 /// reproducible builds where the actual hostname leaks build-env detail.
193 pub build_host: Option<String>,
194 /// `%pretrans` scriptlet — executed on the package transaction *before*
195 /// any package in the transaction is installed. Path to a script file.
196 pub pretrans: Option<String>,
197 /// `%posttrans` scriptlet — executed *after* all packages in the
198 /// transaction have been installed. Path to a script file.
199 pub posttrans: Option<String>,
200 /// Prerelease suffix appended to the version (e.g. `rc1`, `beta2`).
201 /// Mirrors GR `NFPM.Prerelease`.
202 pub prerelease: Option<String>,
203 /// Build metadata appended to the version (e.g. git commit hash).
204 /// Mirrors GR `NFPM.VersionMetadata`.
205 pub version_metadata: Option<String>,
206 /// Skip this config. Accepts bool or template string.
207 #[serde(deserialize_with = "deserialize_string_or_bool_opt", default)]
208 pub skip: Option<StringOrBool>,
209}
210
211// SRPM signatures share [`NfpmSignatureConfig`]; the SRPM-style
212// `passphrase:` key is accepted as a serde alias for `key_passphrase:`.
213//
214// SRPM contents share [`NfpmContent`]; both the canonical `src` / `dst`
215// keys and the SRPM-style `source` / `destination` aliases parse.