dnf_repofile/builder.rs
1//! Builder-pattern API for constructing [`Repo`] values.
2//!
3//! [`RepoBuilder`] provides a fluent interface for programmatic creation of
4//! repository configurations without manually setting each field on a
5//! [`Repo`] struct.
6//!
7//! # Examples
8//!
9//! ```
10//! use dnf_repofile::{RepoBuilder, RepoId, RepoName, DnfBool, Priority};
11//!
12//! let repo = RepoBuilder::new(RepoId::try_new("custom").unwrap())
13//! .name(RepoName::try_new("Custom Repository").unwrap())
14//! .baseurl("https://example.com/".parse().unwrap())
15//! .enabled(DnfBool::yes())
16//! .gpgcheck(DnfBool::yes())
17//! .priority(Priority::try_new(50).unwrap())
18//! .build();
19//!
20//! assert_eq!(repo.name.as_ref().unwrap().as_ref(), "Custom Repository");
21//! ```
22
23use crate::repo::Repo;
24use crate::types::*;
25use url::Url;
26
27/// Builder-pattern API for constructing a [`Repo`] with a fluent interface.
28///
29/// Create a new builder with [`RepoBuilder::new`] or clone an existing repo
30/// with [`RepoBuilder::from`].
31///
32/// # Examples
33///
34/// ```
35/// use dnf_repofile::{RepoBuilder, RepoId, DnfBool};
36///
37/// let repo = RepoBuilder::new(RepoId::try_new("myrepo").unwrap())
38/// .enabled(DnfBool::yes())
39/// .build();
40/// ```
41#[derive(Debug, Clone)]
42pub struct RepoBuilder {
43 repo: Repo,
44}
45
46impl RepoBuilder {
47 /// Create a new builder with the given repository ID.
48 ///
49 /// All other fields are initialized to `None` or empty.
50 ///
51 /// # Examples
52 ///
53 /// ```
54 /// use dnf_repofile::{RepoBuilder, RepoId};
55 ///
56 /// let builder = RepoBuilder::new(RepoId::try_new("test").unwrap());
57 /// ```
58 pub fn new(id: RepoId) -> Self {
59 RepoBuilder {
60 repo: Repo::new(id),
61 }
62 }
63
64 /// Create a builder pre-populated from an existing [`Repo`].
65 ///
66 /// Useful for making a modified copy of an existing configuration.
67 ///
68 /// # Examples
69 ///
70 /// ```
71 /// use dnf_repofile::{RepoBuilder, Repo, RepoId};
72 ///
73 /// let original = Repo::new(RepoId::try_new("test").unwrap());
74 /// let builder = RepoBuilder::from(&original);
75 /// ```
76 pub fn from(existing: &Repo) -> Self {
77 RepoBuilder {
78 repo: existing.clone(),
79 }
80 }
81
82 /// Consume the builder and produce the final [`Repo`].
83 ///
84 /// # Examples
85 ///
86 /// ```
87 /// use dnf_repofile::{RepoBuilder, RepoId};
88 ///
89 /// let repo = RepoBuilder::new(RepoId::try_new("test").unwrap()).build();
90 /// ```
91 #[must_use]
92 pub fn build(self) -> Repo {
93 self.repo
94 }
95
96 /// Set the human-readable repository name.
97 pub fn name(mut self, v: RepoName) -> Self {
98 self.repo.name = Some(v);
99 self
100 }
101
102 /// Add a base URL to the repository.
103 ///
104 /// Multiple URLs can be added by chaining this method.
105 pub fn baseurl(mut self, v: Url) -> Self {
106 self.repo.baseurl.push(v);
107 self
108 }
109
110 /// Set all base URLs at once, replacing any existing URLs.
111 pub fn baseurls(mut self, v: Vec<Url>) -> Self {
112 self.repo.baseurl = v;
113 self
114 }
115
116 /// Set the mirror list URL.
117 pub fn mirrorlist(mut self, v: Url) -> Self {
118 self.repo.mirrorlist = Some(v);
119 self
120 }
121
122 /// Set the metalink URL.
123 pub fn metalink(mut self, v: Url) -> Self {
124 self.repo.metalink = Some(v);
125 self
126 }
127
128 /// Add a GPG key URL.
129 ///
130 /// Multiple keys can be added by chaining this method.
131 pub fn gpgkey(mut self, v: &str) -> Self {
132 self.repo.gpgkey.push(v.to_string());
133 self
134 }
135
136 /// Set all GPG key URLs at once, replacing any existing keys.
137 pub fn gpgkeys(mut self, v: Vec<String>) -> Self {
138 self.repo.gpgkey = v;
139 self
140 }
141
142 /// Set whether the repository is enabled.
143 pub fn enabled(mut self, v: DnfBool) -> Self {
144 self.repo.enabled = Some(v);
145 self
146 }
147
148 /// Set whether to GPG-check packages from this repo.
149 pub fn gpgcheck(mut self, v: DnfBool) -> Self {
150 self.repo.gpgcheck = Some(v);
151 self
152 }
153
154 /// Set whether to GPG-check repository metadata.
155 pub fn repo_gpgcheck(mut self, v: DnfBool) -> Self {
156 self.repo.repo_gpgcheck = Some(v);
157 self
158 }
159
160 /// Set the repository priority (1–99, lower = higher priority).
161 pub fn priority(mut self, v: Priority) -> Self {
162 self.repo.priority = Some(v);
163 self
164 }
165
166 /// Set the repository cost (higher = less preferred).
167 pub fn cost(mut self, v: Cost) -> Self {
168 self.repo.cost = Some(v);
169 self
170 }
171
172 /// Mark the repository as a module hotfix repository.
173 pub fn module_hotfixes(mut self, v: DnfBool) -> Self {
174 self.repo.module_hotfixes = Some(v);
175 self
176 }
177
178 /// Set the repository metadata type (e.g., `rpm-md`).
179 pub fn metadata_type(mut self, v: RepoMetadataType) -> Self {
180 self.repo.metadata_type = Some(v);
181 self
182 }
183
184 /// Set the media ID for DVD/media-based repositories.
185 pub fn mediaid(mut self, v: &str) -> Self {
186 self.repo.mediaid = Some(v.to_string());
187 self
188 }
189
190 /// Add a package name glob to the exclude list.
191 pub fn excludepkgs(mut self, v: &str) -> Self {
192 self.repo.excludepkgs.push(v.to_string());
193 self
194 }
195
196 /// Add a package name glob to the include list.
197 pub fn includepkgs(mut self, v: &str) -> Self {
198 self.repo.includepkgs.push(v.to_string());
199 self
200 }
201
202 /// Set whether to skip the repository if it is unavailable.
203 pub fn skip_if_unavailable(mut self, v: DnfBool) -> Self {
204 self.repo.skip_if_unavailable = Some(v);
205 self
206 }
207
208 /// Set the number of retries for network operations.
209 pub fn retries(mut self, v: Retries) -> Self {
210 self.repo.retries = Some(v);
211 self
212 }
213
214 /// Set the network timeout in seconds.
215 pub fn timeout(mut self, v: TimeoutSeconds) -> Self {
216 self.repo.timeout = Some(v);
217 self
218 }
219
220 /// Set the maximum number of parallel downloads.
221 pub fn max_parallel_downloads(mut self, v: MaxParallelDownloads) -> Self {
222 self.repo.max_parallel_downloads = Some(v);
223 self
224 }
225
226 /// Set the proxy configuration.
227 pub fn proxy(mut self, v: ProxySetting) -> Self {
228 self.repo.proxy = v;
229 self
230 }
231
232 /// Set the username for repository authentication.
233 pub fn username(mut self, v: Username) -> Self {
234 self.repo.username = Some(v);
235 self
236 }
237
238 /// Set the password for repository authentication.
239 pub fn password(mut self, v: Password) -> Self {
240 self.repo.password = Some(v);
241 self
242 }
243
244 /// Add an extra (unknown) key-value pair to the repository configuration.
245 ///
246 /// Unknown keys are preserved for round-trip fidelity when rendering.
247 /// If the same key is added multiple times, the values are appended.
248 pub fn extra(mut self, key: &str, value: &str) -> Self {
249 self.repo
250 .extras
251 .entry(key.to_string())
252 .or_default()
253 .push(value.to_string());
254 self
255 }
256}