1use crate::{
2 config,
3 config::tree::{keys, Core, Key, Section},
4};
5
6impl Core {
7 pub const ABBREV: Abbrev = Abbrev::new_with_validate("abbrev", &config::Tree::CORE, validate::Abbrev);
9 pub const BARE: keys::Boolean = keys::Boolean::new_boolean("bare", &config::Tree::CORE);
11 pub const BIG_FILE_THRESHOLD: keys::UnsignedInteger =
13 keys::UnsignedInteger::new_unsigned_integer("bigFileThreshold", &config::Tree::CORE);
14 pub const CHECK_STAT: CheckStat =
16 CheckStat::new_with_validate("checkStat", &config::Tree::CORE, validate::CheckStat);
17 pub const DELTA_BASE_CACHE_LIMIT: keys::UnsignedInteger =
19 keys::UnsignedInteger::new_unsigned_integer("deltaBaseCacheLimit", &config::Tree::CORE)
20 .with_environment_override("GIX_PACK_CACHE_MEMORY")
21 .with_note("if unset, we default to a small 64 slot fixed-size cache that holds at most 64 full delta base objects of any size. Set to 0 to deactivate it entirely");
22 pub const DISAMBIGUATE: Disambiguate =
24 Disambiguate::new_with_validate("disambiguate", &config::Tree::CORE, validate::Disambiguate);
25 pub const EDITOR: keys::Program = keys::Program::new_program("editor", &config::Tree::CORE);
27 pub const FILE_MODE: keys::Boolean = keys::Boolean::new_boolean("fileMode", &config::Tree::CORE);
29 pub const IGNORE_CASE: keys::Boolean = keys::Boolean::new_boolean("ignoreCase", &config::Tree::CORE);
31 pub const FILES_REF_LOCK_TIMEOUT: keys::LockTimeout =
33 keys::LockTimeout::new_lock_timeout("filesRefLockTimeout", &config::Tree::CORE);
34 pub const PACKED_REFS_TIMEOUT: keys::LockTimeout =
36 keys::LockTimeout::new_lock_timeout("packedRefsTimeout", &config::Tree::CORE);
37 pub const MULTIPACK_INDEX: keys::Boolean = keys::Boolean::new_boolean("multiPackIndex", &config::Tree::CORE);
39 pub const LOG_ALL_REF_UPDATES: LogAllRefUpdates =
41 LogAllRefUpdates::new_with_validate("logAllRefUpdates", &config::Tree::CORE, validate::LogAllRefUpdates);
42 pub const PRECOMPOSE_UNICODE: keys::Boolean = keys::Boolean::new_boolean("precomposeUnicode", &config::Tree::CORE)
46 .with_note("application needs to conform all program input by using gix::env::args_os()");
47 pub const PROTECT_HFS: keys::Boolean = keys::Boolean::new_boolean("protectHFS", &config::Tree::CORE);
49 pub const PROTECT_NTFS: keys::Boolean = keys::Boolean::new_boolean("protectNTFS", &config::Tree::CORE);
51 pub const REPOSITORY_FORMAT_VERSION: keys::UnsignedInteger =
53 keys::UnsignedInteger::new_unsigned_integer("repositoryFormatVersion", &config::Tree::CORE);
54 pub const SYMLINKS: keys::Boolean = keys::Boolean::new_boolean("symlinks", &config::Tree::CORE);
56 pub const TRUST_C_TIME: keys::Boolean = keys::Boolean::new_boolean("trustCTime", &config::Tree::CORE);
58 pub const WORKTREE: keys::Any = keys::Any::new("worktree", &config::Tree::CORE)
60 .with_environment_override("GIT_WORK_TREE")
61 .with_deviation("Command-line overrides also work, and they act lie an environment override. If set in the git configuration file, relative paths are relative to it.");
62 pub const ASKPASS: keys::Executable = keys::Executable::new_executable("askPass", &config::Tree::CORE)
64 .with_environment_override("GIT_ASKPASS")
65 .with_note("fallback is 'SSH_ASKPASS'");
66 pub const EXCLUDES_FILE: keys::Path = keys::Path::new_path("excludesFile", &config::Tree::CORE);
68 pub const ATTRIBUTES_FILE: keys::Path =
70 keys::Path::new_path("attributesFile", &config::Tree::CORE)
71 .with_deviation("for checkout - it's already queried but needs building of attributes group, and of course support during checkout");
72 pub const SSH_COMMAND: keys::Executable = keys::Executable::new_executable("sshCommand", &config::Tree::CORE)
74 .with_environment_override("GIT_SSH_COMMAND");
75 pub const USE_REPLACE_REFS: keys::Boolean = keys::Boolean::new_boolean("useReplaceRefs", &config::Tree::CORE)
77 .with_environment_override("GIT_NO_REPLACE_OBJECTS");
78 pub const COMMIT_GRAPH: keys::Boolean = keys::Boolean::new_boolean("commitGraph", &config::Tree::CORE);
80 #[cfg(feature = "attributes")]
82 pub const SAFE_CRLF: SafeCrlf = SafeCrlf::new_with_validate("safecrlf", &config::Tree::CORE, validate::SafeCrlf);
83 #[cfg(feature = "attributes")]
85 pub const AUTO_CRLF: AutoCrlf = AutoCrlf::new_with_validate("autocrlf", &config::Tree::CORE, validate::AutoCrlf);
86 #[cfg(feature = "attributes")]
88 pub const EOL: Eol = Eol::new_with_validate("eol", &config::Tree::CORE, validate::Eol);
89 #[cfg(feature = "attributes")]
91 pub const CHECK_ROUND_TRIP_ENCODING: CheckRoundTripEncoding = CheckRoundTripEncoding::new_with_validate(
92 "checkRoundTripEncoding",
93 &config::Tree::CORE,
94 validate::CheckRoundTripEncoding,
95 );
96}
97
98impl Section for Core {
99 fn name(&self) -> &str {
100 "core"
101 }
102
103 fn keys(&self) -> &[&dyn Key] {
104 &[
105 &Self::ABBREV,
106 &Self::BARE,
107 &Self::BIG_FILE_THRESHOLD,
108 &Self::CHECK_STAT,
109 &Self::DELTA_BASE_CACHE_LIMIT,
110 &Self::DISAMBIGUATE,
111 &Self::EDITOR,
112 &Self::FILE_MODE,
113 &Self::IGNORE_CASE,
114 &Self::FILES_REF_LOCK_TIMEOUT,
115 &Self::PACKED_REFS_TIMEOUT,
116 &Self::MULTIPACK_INDEX,
117 &Self::LOG_ALL_REF_UPDATES,
118 &Self::PRECOMPOSE_UNICODE,
119 &Self::REPOSITORY_FORMAT_VERSION,
120 &Self::SYMLINKS,
121 &Self::TRUST_C_TIME,
122 &Self::WORKTREE,
123 &Self::PROTECT_HFS,
124 &Self::PROTECT_NTFS,
125 &Self::ASKPASS,
126 &Self::EXCLUDES_FILE,
127 &Self::ATTRIBUTES_FILE,
128 &Self::SSH_COMMAND,
129 &Self::USE_REPLACE_REFS,
130 &Self::COMMIT_GRAPH,
131 #[cfg(feature = "attributes")]
132 &Self::SAFE_CRLF,
133 #[cfg(feature = "attributes")]
134 &Self::AUTO_CRLF,
135 #[cfg(feature = "attributes")]
136 &Self::EOL,
137 #[cfg(feature = "attributes")]
138 &Self::CHECK_ROUND_TRIP_ENCODING,
139 ]
140 }
141}
142
143pub type CheckStat = keys::Any<validate::CheckStat>;
145
146pub type Abbrev = keys::Any<validate::Abbrev>;
148
149pub type LogAllRefUpdates = keys::Any<validate::LogAllRefUpdates>;
151
152pub type Disambiguate = keys::Any<validate::Disambiguate>;
154
155#[cfg(feature = "attributes")]
156mod filter {
157 use super::validate;
158 use crate::config::tree::keys;
159
160 pub type SafeCrlf = keys::Any<validate::SafeCrlf>;
162
163 pub type AutoCrlf = keys::Any<validate::AutoCrlf>;
165
166 pub type Eol = keys::Any<validate::Eol>;
168
169 pub type CheckRoundTripEncoding = keys::Any<validate::CheckRoundTripEncoding>;
171
172 mod check_round_trip_encoding {
173 use std::borrow::Cow;
174
175 use crate::{
176 bstr::{BStr, ByteSlice},
177 config,
178 config::tree::{core::CheckRoundTripEncoding, Key},
179 };
180
181 impl CheckRoundTripEncoding {
182 pub fn try_into_encodings(
185 &'static self,
186 value: Option<Cow<'_, BStr>>,
187 ) -> Result<Vec<&'static gix_filter::encoding::Encoding>, config::encoding::Error> {
188 Ok(match value {
189 None => vec![gix_filter::encoding::SHIFT_JIS],
190 Some(value) => {
191 let mut out = Vec::new();
192 for encoding in value
193 .as_ref()
194 .split(|b| *b == b',' || *b == b' ')
195 .filter(|e| !e.trim().is_empty())
196 {
197 out.push(
198 gix_filter::encoding::Encoding::for_label(encoding.trim()).ok_or_else(|| {
199 config::encoding::Error {
200 key: self.logical_name().into(),
201 value: value.as_ref().to_owned(),
202 encoding: encoding.into(),
203 }
204 })?,
205 );
206 }
207 out
208 }
209 })
210 }
211 }
212 }
213
214 mod eol {
215 use std::borrow::Cow;
216
217 use crate::{
218 bstr::{BStr, ByteSlice},
219 config,
220 config::tree::core::Eol,
221 };
222
223 impl Eol {
224 pub fn try_into_eol(
230 &'static self,
231 value: Cow<'_, BStr>,
232 ) -> Result<gix_filter::eol::Mode, config::key::GenericErrorWithValue> {
233 Ok(match value.to_str_lossy().as_ref() {
234 "lf" => gix_filter::eol::Mode::Lf,
235 "crlf" => gix_filter::eol::Mode::CrLf,
236 "native" => gix_filter::eol::Mode::default(),
237 _ => return Err(config::key::GenericErrorWithValue::from_value(self, value.into_owned())),
238 })
239 }
240 }
241 }
242
243 mod safecrlf {
244 use std::borrow::Cow;
245
246 use gix_filter::pipeline::CrlfRoundTripCheck;
247
248 use crate::{bstr::BStr, config, config::tree::core::SafeCrlf};
249
250 impl SafeCrlf {
251 pub fn try_into_safecrlf(
253 &'static self,
254 value: Cow<'_, BStr>,
255 ) -> Result<CrlfRoundTripCheck, config::key::GenericErrorWithValue> {
256 if value.as_ref() == "warn" {
257 return Ok(CrlfRoundTripCheck::Warn);
258 }
259 let value = gix_config::Boolean::try_from(value.as_ref()).map_err(|err| {
260 config::key::GenericErrorWithValue::from_value(self, value.into_owned()).with_source(err)
261 })?;
262 Ok(if value.into() {
263 CrlfRoundTripCheck::Fail
264 } else {
265 CrlfRoundTripCheck::Skip
266 })
267 }
268 }
269 }
270
271 mod autocrlf {
272 use std::borrow::Cow;
273
274 use gix_filter::eol;
275
276 use crate::{bstr::BStr, config, config::tree::core::AutoCrlf};
277
278 impl AutoCrlf {
279 pub fn try_into_autocrlf(
281 &'static self,
282 value: Cow<'_, BStr>,
283 ) -> Result<eol::AutoCrlf, config::key::GenericErrorWithValue> {
284 if value.as_ref() == "input" {
285 return Ok(eol::AutoCrlf::Input);
286 }
287 let value = gix_config::Boolean::try_from(value.as_ref()).map_err(|err| {
288 config::key::GenericErrorWithValue::from_value(self, value.into_owned()).with_source(err)
289 })?;
290 Ok(if value.into() {
291 eol::AutoCrlf::Enabled
292 } else {
293 eol::AutoCrlf::Disabled
294 })
295 }
296 }
297 }
298}
299#[cfg(feature = "attributes")]
300pub use filter::*;
301
302#[cfg(feature = "revision")]
303mod disambiguate {
304 use std::borrow::Cow;
305
306 use crate::{
307 bstr::{BStr, ByteSlice},
308 config,
309 config::tree::core::Disambiguate,
310 revision::spec::parse::ObjectKindHint,
311 };
312
313 impl Disambiguate {
314 pub fn try_into_object_kind_hint(
316 &'static self,
317 value: Cow<'_, BStr>,
318 ) -> Result<Option<ObjectKindHint>, config::key::GenericErrorWithValue> {
319 let hint = match value.as_ref().as_bytes() {
320 b"none" => return Ok(None),
321 b"commit" => ObjectKindHint::Commit,
322 b"committish" => ObjectKindHint::Committish,
323 b"tree" => ObjectKindHint::Tree,
324 b"treeish" => ObjectKindHint::Treeish,
325 b"blob" => ObjectKindHint::Blob,
326 _ => return Err(config::key::GenericErrorWithValue::from_value(self, value.into_owned())),
327 };
328 Ok(Some(hint))
329 }
330 }
331}
332
333mod log_all_ref_updates {
334 use crate::{config, config::tree::core::LogAllRefUpdates};
335
336 impl LogAllRefUpdates {
337 pub fn try_into_ref_updates(
341 &'static self,
342 value: Option<Result<bool, gix_config::value::Error>>,
343 ) -> Result<Option<gix_ref::store::WriteReflog>, config::key::GenericErrorWithValue> {
344 match value {
345 Some(Ok(bool)) => Ok(Some(if bool {
346 gix_ref::store::WriteReflog::Normal
347 } else {
348 gix_ref::store::WriteReflog::Disable
349 })),
350 Some(Err(err)) => match err.input {
351 val if val.eq_ignore_ascii_case(b"always") => Ok(Some(gix_ref::store::WriteReflog::Always)),
352 val => Err(config::key::GenericErrorWithValue::from_value(self, val)),
353 },
354 None => Ok(None),
355 }
356 }
357 }
358}
359
360mod check_stat {
361 use std::borrow::Cow;
362
363 use crate::{
364 bstr::{BStr, ByteSlice},
365 config,
366 config::tree::core::CheckStat,
367 };
368
369 impl CheckStat {
370 pub fn try_into_checkstat(
372 &'static self,
373 value: Cow<'_, BStr>,
374 ) -> Result<bool, config::key::GenericErrorWithValue> {
375 Ok(match value.as_ref().as_bytes() {
376 b"minimal" => false,
377 b"default" => true,
378 _ => {
379 return Err(config::key::GenericErrorWithValue::from_value(self, value.into_owned()));
380 }
381 })
382 }
383 }
384}
385
386mod abbrev {
387 use std::borrow::Cow;
388
389 use config::abbrev::Error;
390
391 use crate::{
392 bstr::{BStr, ByteSlice},
393 config,
394 config::tree::core::Abbrev,
395 };
396
397 impl Abbrev {
398 pub fn try_into_abbreviation(
401 &'static self,
402 hex_len_str: Cow<'_, BStr>,
403 object_hash: gix_hash::Kind,
404 ) -> Result<Option<usize>, Error> {
405 let max = object_hash.len_in_hex() as u8;
406 if hex_len_str.trim().is_empty() {
407 return Err(Error {
408 value: hex_len_str.into_owned(),
409 max,
410 });
411 }
412 if hex_len_str.trim().eq_ignore_ascii_case(b"auto") {
413 Ok(None)
414 } else {
415 let value_bytes = hex_len_str.as_ref();
416 if let Ok(false) = gix_config::Boolean::try_from(value_bytes).map(Into::into) {
417 Ok(object_hash.len_in_hex().into())
418 } else {
419 let value = gix_config::Integer::try_from(value_bytes)
420 .map_err(|_| Error {
421 value: hex_len_str.clone().into_owned(),
422 max,
423 })?
424 .to_decimal()
425 .ok_or_else(|| Error {
426 value: hex_len_str.clone().into_owned(),
427 max,
428 })?;
429 if value < 4 || value as usize > object_hash.len_in_hex() {
430 return Err(Error {
431 value: hex_len_str.clone().into_owned(),
432 max,
433 });
434 }
435 Ok(Some(value as usize))
436 }
437 }
438 }
439 }
440}
441
442mod validate {
443 use crate::{bstr::BStr, config::tree::keys};
444
445 pub struct Disambiguate;
446 impl keys::Validate for Disambiguate {
447 #[cfg_attr(not(feature = "revision"), allow(unused_variables))]
448 fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
449 #[cfg(feature = "revision")]
450 super::Core::DISAMBIGUATE.try_into_object_kind_hint(value.into())?;
451 Ok(())
452 }
453 }
454
455 pub struct LogAllRefUpdates;
456 impl keys::Validate for LogAllRefUpdates {
457 fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
458 super::Core::LOG_ALL_REF_UPDATES
459 .try_into_ref_updates(Some(gix_config::Boolean::try_from(value).map(|b| b.0)))?;
460 Ok(())
461 }
462 }
463
464 pub struct CheckStat;
465 impl keys::Validate for CheckStat {
466 fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
467 super::Core::CHECK_STAT.try_into_checkstat(value.into())?;
468 Ok(())
469 }
470 }
471
472 pub struct Abbrev;
473 impl keys::Validate for Abbrev {
474 fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
475 super::Core::ABBREV.try_into_abbreviation(value.into(), gix_hash::Kind::Sha1)?;
477 Ok(())
478 }
479 }
480
481 pub struct SafeCrlf;
482 impl keys::Validate for SafeCrlf {
483 #[cfg_attr(not(feature = "attributes"), allow(unused_variables))]
484 fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
485 #[cfg(feature = "attributes")]
486 super::Core::SAFE_CRLF.try_into_safecrlf(value.into())?;
487 Ok(())
488 }
489 }
490
491 pub struct AutoCrlf;
492 impl keys::Validate for AutoCrlf {
493 #[cfg_attr(not(feature = "attributes"), allow(unused_variables))]
494 fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
495 #[cfg(feature = "attributes")]
496 super::Core::AUTO_CRLF.try_into_autocrlf(value.into())?;
497 Ok(())
498 }
499 }
500
501 pub struct Eol;
502 impl keys::Validate for Eol {
503 #[cfg_attr(not(feature = "attributes"), allow(unused_variables))]
504 fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
505 #[cfg(feature = "attributes")]
506 super::Core::EOL.try_into_eol(value.into())?;
507 Ok(())
508 }
509 }
510
511 pub struct CheckRoundTripEncoding;
512 impl keys::Validate for CheckRoundTripEncoding {
513 #[cfg_attr(not(feature = "attributes"), allow(unused_variables))]
514 fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
515 #[cfg(feature = "attributes")]
516 super::Core::CHECK_ROUND_TRIP_ENCODING.try_into_encodings(Some(value.into()))?;
517 Ok(())
518 }
519 }
520}