1#![deny(rust_2018_idioms, missing_docs)]
3#![forbid(unsafe_code)]
4
5use std::{borrow::Cow, collections::BTreeMap};
6
7#[derive(Clone)]
13pub struct File {
14 config: gix_config::File<'static>,
15}
16
17mod access;
18
19pub mod config;
21
22pub mod is_active_platform;
24
25pub struct IsActivePlatform {
27 pub(crate) search: Option<gix_pathspec::Search>,
28}
29
30impl File {
32 pub fn append_submodule_overrides(&mut self, config: &gix_config::File<'_>) -> &mut Self {
42 let mut values = BTreeMap::<_, Vec<_>>::new();
43 for (module_name, section) in config
44 .sections_by_name("submodule")
45 .into_iter()
46 .flatten()
47 .filter_map(|s| s.header().subsection_name().map(|n| (n, s)))
48 {
49 for field in ["url", "fetchRecurseSubmodules", "ignore", "update", "branch"] {
50 if let Some(value) = section.value(field) {
51 values.entry((module_name, field)).or_default().push(value);
52 }
53 }
54 }
55
56 let values = {
57 let mut v: Vec<_> = values.into_iter().collect();
58 v.sort_by_key(|a| a.0 .0);
59 v
60 };
61
62 let mut config_to_append = gix_config::File::new(config.meta_owned());
63 let mut prev_name = None;
64 for ((module_name, field), values) in values {
65 if prev_name != Some(module_name) {
66 config_to_append
67 .new_section("submodule", Some(Cow::Owned(module_name.to_owned())))
68 .expect("all names come from valid configuration, so remain valid");
69 prev_name = Some(module_name);
70 }
71 config_to_append
72 .section_mut("submodule", Some(module_name))
73 .expect("always set at this point")
74 .push(
75 field.try_into().expect("statically known key"),
76 Some(values.last().expect("at least one value or we wouldn't be here")),
77 );
78 }
79
80 self.config.append(config_to_append);
81 self
82 }
83}
84
85mod init {
87 use std::path::PathBuf;
88
89 use crate::File;
90
91 impl std::fmt::Debug for File {
92 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93 f.debug_struct("File")
94 .field("config_path", &self.config_path())
95 .field("config", &format_args!("r#\"{}\"#", self.config))
96 .finish()
97 }
98 }
99
100 pub(crate) const META_MARKER: gix_config::Source = gix_config::Source::Api;
102
103 impl File {
105 pub fn from_bytes(
118 bytes: &[u8],
119 path: impl Into<Option<PathBuf>>,
120 config: &gix_config::File<'_>,
121 ) -> Result<Self, gix_config::parse::Error> {
122 let metadata = {
123 let mut meta = gix_config::file::Metadata::from(META_MARKER);
124 meta.path = path.into();
125 meta
126 };
127 let modules = gix_config::File::from_parse_events_no_includes(
128 gix_config::parse::Events::from_bytes_owned(bytes, None)?,
129 metadata,
130 );
131
132 let mut res = Self { config: modules };
133 res.append_submodule_overrides(config);
134 Ok(res)
135 }
136
137 pub fn into_config(self) -> gix_config::File<'static> {
139 self.config
140 }
141 }
142}