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