rust_apt/
config.rs

1//! Contains config related structs and functions.
2
3use cxx::UniquePtr;
4
5/// Struct for Apt Configuration
6///
7/// All apt configuration methods do not require this struct.
8/// You can call the bindings directly from raw::apt if you would like.
9#[derive(Debug)]
10pub struct Config {}
11
12// TODO: ConfigTree can (signal: 11, SIGSEGV: invalid memory reference)
13// if you get a ConfigTree object and then clear the config with clear_all
14// Make clear_all consume the Config struct and make ConfigTree have a lifetime
15// to it?
16
17impl Default for Config {
18	/// Create a new config object and safely init the config system.
19	///
20	/// If you initialize the struct without `new()` or `default()`
21	/// You will need to manually initialize the config system.
22	fn default() -> Self { Self::new() }
23}
24// TODO: I think we should not accept &str if we just call to_string() anyway
25impl Config {
26	/// Create a new config object and safely init the config system.
27	///
28	/// If you initialize the struct without `new()` or `default()`
29	/// You will need to manually initialize the config system.
30	pub fn new() -> Self {
31		init_config_system();
32		Self {}
33	}
34
35	/// Clears all configuratations, re-initialize, and returns the config
36	/// object.
37	pub fn new_clear() -> Self {
38		raw::clear_all();
39		Self::new()
40	}
41
42	/// Resets the configurations.
43	///
44	/// If you'd like to clear everything and NOT reinit
45	/// you can call `self.clear_all` or `raw::clear_all` directly
46	pub fn reset(&self) {
47		self.clear_all();
48		init_config_system();
49	}
50
51	/// Clears all values from a key.
52	///
53	/// If the value is a list, the entire list is cleared.
54	/// If you need to clear 1 value from a list see `self.clear_value`
55	pub fn clear(&self, key: &str) { raw::clear(key.to_string()); }
56
57	/// Clear a single value from a list.
58	/// Used for removing one item in an apt configuruation list
59	pub fn clear_value(&self, key: &str, value: &str) {
60		raw::clear_value(key.to_string(), value.to_string());
61	}
62
63	/// Clears all configuratations.
64	///
65	/// This will leave you with an empty configuration object
66	/// and most things probably won't work right.
67	pub fn clear_all(&self) { raw::clear_all(); }
68
69	/// Returns a string dump of configuration options separated by `\n`
70	pub fn dump(&self) -> String { raw::dump() }
71
72	/// Find a key and return it's value as a string.
73	///
74	/// default is what will be returned if nothing is found.
75	pub fn find(&self, key: &str, default: &str) -> String {
76		raw::find(key.to_string(), default.to_string())
77	}
78
79	/// Exactly like find but takes no default and returns an option instead.
80	pub fn get(&self, key: &str) -> Option<String> {
81		let value = raw::find(key.to_string(), "".to_string());
82		if value.is_empty() {
83			return None;
84		}
85		Some(value)
86	}
87
88	/// Find a file and return it's value as a string.
89	///
90	/// default is what will be returned if nothing is found.
91	///
92	/// `key = "Dir::Cache::pkgcache"` should return
93	/// `/var/cache/apt/pkgcache.bin`
94	///
95	/// There is not much difference in `self.dir` and `self.file`
96	///
97	/// `dir` will return with a trailing `/` where `file` will not.
98	pub fn file(&self, key: &str, default: &str) -> String {
99		raw::find_file(key.to_string(), default.to_string())
100	}
101
102	/// Find a directory and return it's value as a string.
103	///
104	/// default is what will be returned if nothing is found.
105	///
106	/// `key = "Dir::Etc::sourceparts"` should return `/etc/apt/sources.list.d/`
107	///
108	/// There is not much difference in `self.dir` and `self.file`
109	///
110	/// `dir` will return with a trailing `/` where `file` will not.
111	pub fn dir(&self, key: &str, default: &str) -> String {
112		raw::find_dir(key.to_string(), default.to_string())
113	}
114
115	/// Same as find, but for boolean values.
116	pub fn bool(&self, key: &str, default: bool) -> bool {
117		raw::find_bool(key.to_string(), default)
118	}
119
120	/// Same as find, but for i32 values.
121	pub fn int(&self, key: &str, default: i32) -> i32 { raw::find_int(key.to_string(), default) }
122
123	/// Return a vector for an Apt configuration list.
124	///
125	/// An example of a common key that contains a list `raw::NeverAutoRemove`.
126	pub fn find_vector(&self, key: &str) -> Vec<String> { raw::find_vector(key.to_string()) }
127
128	/// Return a vector of supported architectures on this system.
129	/// The main architecture is the first in the list.
130	pub fn get_architectures(&self) -> Vec<String> { raw::get_architectures() }
131
132	/// Simply check if a key exists.
133	pub fn contains(&self, key: &str) -> bool { raw::exists(key.to_string()) }
134
135	/// Set the given key to the specified value.
136	pub fn set(&self, key: &str, value: &str) { raw::set(key.to_string(), value.to_string()) }
137
138	pub fn tree(&self, key: &str) -> Option<ConfigTree> {
139		let tree = unsafe { raw::tree(key.to_string()) };
140		if tree.end() {
141			return None;
142		}
143		Some(ConfigTree::new(tree))
144	}
145
146	pub fn root_tree(&self) -> Option<ConfigTree> {
147		let tree = unsafe { raw::root_tree() };
148		if tree.end() {
149			return None;
150		}
151		Some(ConfigTree::new(tree))
152	}
153
154	/// Add strings from a vector into an apt configuration list.
155	///
156	/// If the configuration key is not a list,
157	/// you will receive a vector with one item.
158	///
159	/// Example:
160	/// ```
161	/// use rust_apt::config::Config;
162	/// let config = Config::new();
163	///
164	/// let apt_list = vec!["This", "is", "my", "apt", "list"];
165	/// // Using "AptList" here will not work and will panic.
166	/// config.set_vector("AptList", &apt_list);
167	/// ```
168	pub fn set_vector(&self, key: &str, values: &Vec<&str>) {
169		let mut vec_key = String::from(key);
170		if !vec_key.ends_with("::") {
171			vec_key.push_str("::");
172		}
173
174		for value in values {
175			raw::set(vec_key.to_string(), value.to_string());
176		}
177	}
178}
179
180pub struct ConfigTree {
181	pub ptr: UniquePtr<raw::ConfigTree>,
182}
183
184impl ConfigTree {
185	pub fn new(ptr: UniquePtr<raw::ConfigTree>) -> Self { ConfigTree { ptr } }
186
187	pub fn tag(&self) -> Option<String> {
188		let tag = self.ptr.tag();
189		if tag.is_empty() {
190			return None;
191		}
192		Some(tag)
193	}
194
195	/// Return the fully scoped tag
196	pub fn full_tag(&self) -> Option<String> {
197		let tag = self.ptr.full_tag();
198		if tag.is_empty() {
199			return None;
200		}
201		Some(tag)
202	}
203
204	pub fn value(&self) -> Option<String> {
205		let value = self.ptr.value();
206		if value.is_empty() {
207			return None;
208		}
209		Some(value)
210	}
211
212	pub fn child(&self) -> Option<ConfigTree> {
213		let child = unsafe { self.ptr.child() };
214		if child.end() { None } else { Some(ConfigTree::new(child)) }
215	}
216
217	pub fn sibling(&self) -> Option<ConfigTree> {
218		let child = unsafe { self.ptr.raw_next() };
219		if child.end() { None } else { Some(ConfigTree::new(child)) }
220	}
221
222	pub fn parent(&self) -> Option<ConfigTree> {
223		let parent = unsafe { self.ptr.parent() };
224		if parent.end() { None } else { Some(ConfigTree::new(parent)) }
225	}
226
227	pub fn iter(&self) -> IterConfigTree {
228		IterConfigTree(unsafe { ConfigTree::new(self.ptr.unique()) })
229	}
230}
231
232impl IntoIterator for ConfigTree {
233	type IntoIter = IterConfigTree;
234	type Item = ConfigTree;
235
236	fn into_iter(self) -> Self::IntoIter { IterConfigTree(self) }
237}
238
239pub struct IterConfigTree(ConfigTree);
240
241impl Iterator for IterConfigTree {
242	type Item = ConfigTree;
243
244	fn next(&mut self) -> Option<Self::Item> {
245		if self.0.ptr.end() {
246			None
247		} else {
248			let ret = unsafe { self.0.ptr.unique() };
249			let next = unsafe { self.0.ptr.raw_next() };
250			self.0.ptr = next;
251			Some(ConfigTree::new(ret))
252		}
253	}
254}
255
256/// Safely Init Apt Configuration and System.
257///
258/// If the configuration has already been initialized, don't reinit.
259///
260/// This could cause some things to get reset.
261pub fn init_config_system() {
262	if !raw::exists("APT::Architecture".to_string()) {
263		raw::init_config();
264	}
265	raw::init_system();
266}
267
268#[cxx::bridge]
269pub(crate) mod raw {
270	unsafe extern "C++" {
271		include!("rust-apt/apt-pkg-c/configuration.h");
272
273		type ConfigTree;
274
275		/// init the system. This must occur before creating the cache.
276		pub fn init_system();
277
278		/// init the config. This must occur before creating the cache.
279		pub fn init_config();
280
281		/// Returns a string dump of configuration options separated by `\n`
282		pub fn dump() -> String;
283
284		/// Find a key and return it's value as a string.
285		pub fn find(key: String, default_value: String) -> String;
286
287		/// Find a file and return it's value as a string.
288		pub fn find_file(key: String, default_value: String) -> String;
289
290		/// Find a directory and return it's value as a string.
291		pub fn find_dir(key: String, default_value: String) -> String;
292
293		/// Same as find, but for boolean values.
294		pub fn find_bool(key: String, default_value: bool) -> bool;
295
296		/// Same as find, but for i32 values.
297		pub fn find_int(key: String, default_value: i32) -> i32;
298
299		/// Return a vector for an Apt configuration list.
300		pub fn find_vector(key: String) -> Vec<String>;
301
302		/// Return a vector of supported architectures on this system.
303		/// The main architecture is the first in the list.
304		pub fn get_architectures() -> Vec<String>;
305
306		/// Set the given key to the specified value.
307		pub fn set(key: String, value: String);
308
309		/// Simply check if a key exists.
310		pub fn exists(key: String) -> bool;
311
312		/// Clears all values from a key.
313		///
314		/// If the value is a list, the entire list is cleared.
315		/// If you need to clear 1 value from a list see `clear_value`
316		pub fn clear(key: String);
317
318		/// Clears all configuratations.
319		pub fn clear_all();
320
321		/// Clear a single value from a list.
322		/// Used for removing one item in an apt configuruation list
323		pub fn clear_value(key: String, value: String);
324
325		unsafe fn tree(key: String) -> UniquePtr<ConfigTree>;
326		unsafe fn root_tree() -> UniquePtr<ConfigTree>;
327
328		pub fn end(self: &ConfigTree) -> bool;
329		unsafe fn raw_next(self: &ConfigTree) -> UniquePtr<ConfigTree>;
330		unsafe fn unique(self: &ConfigTree) -> UniquePtr<ConfigTree>;
331
332		unsafe fn parent(self: &ConfigTree) -> UniquePtr<ConfigTree>;
333		unsafe fn child(self: &ConfigTree) -> UniquePtr<ConfigTree>;
334		pub fn tag(self: &ConfigTree) -> String;
335		pub fn full_tag(self: &ConfigTree) -> String;
336		pub fn value(self: &ConfigTree) -> String;
337	}
338}