summaryrefslogtreecommitdiffstats
path: root/vendor/gix/src/config/cache/incubate.rs
blob: 44c537b50dd5a2fe75aa398e18e9dda91d450cc4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#![allow(clippy::result_large_err)]
use super::{util, Error};
use crate::config::tree::{Core, Extensions};

/// A utility to deal with the cyclic dependency between the ref store and the configuration. The ref-store needs the
/// object hash kind, and the configuration needs the current branch name to resolve conditional includes with `onbranch`.
pub(crate) struct StageOne {
    pub git_dir_config: gix_config::File<'static>,
    pub buf: Vec<u8>,

    pub is_bare: bool,
    pub lossy: Option<bool>,
    pub object_hash: gix_hash::Kind,
    pub reflog: Option<gix_ref::store::WriteReflog>,
}

/// Initialization
impl StageOne {
    pub fn new(
        common_dir: &std::path::Path,
        git_dir: &std::path::Path,
        git_dir_trust: gix_sec::Trust,
        lossy: Option<bool>,
        lenient: bool,
    ) -> Result<Self, Error> {
        let mut buf = Vec::with_capacity(512);
        let mut config = load_config(
            common_dir.join("config"),
            &mut buf,
            gix_config::Source::Local,
            git_dir_trust,
            lossy,
            lenient,
        )?;

        // Note that we assume the repo is bare by default unless we are told otherwise. This is relevant if
        // the repo doesn't have a configuration file.
        let is_bare = util::config_bool(&config, &Core::BARE, "core.bare", true, lenient)?;
        let repo_format_version = config
            .integer_by_key("core.repositoryFormatVersion")
            .map(|version| Core::REPOSITORY_FORMAT_VERSION.try_into_usize(version))
            .transpose()?
            .unwrap_or_default();
        let object_hash = (repo_format_version != 1)
            .then_some(Ok(gix_hash::Kind::Sha1))
            .or_else(|| {
                config
                    .string("extensions", None, "objectFormat")
                    .map(|format| Extensions::OBJECT_FORMAT.try_into_object_format(format))
            })
            .transpose()?
            .unwrap_or(gix_hash::Kind::Sha1);

        let extension_worktree = util::config_bool(
            &config,
            &Extensions::WORKTREE_CONFIG,
            "extensions.worktreeConfig",
            false,
            lenient,
        )?;
        if extension_worktree {
            let worktree_config = load_config(
                git_dir.join("config.worktree"),
                &mut buf,
                gix_config::Source::Worktree,
                git_dir_trust,
                lossy,
                lenient,
            )?;
            config.append(worktree_config);
        };

        let reflog = util::query_refupdates(&config, lenient)?;
        Ok(StageOne {
            git_dir_config: config,
            buf,
            is_bare,
            lossy,
            object_hash,
            reflog,
        })
    }
}

fn load_config(
    config_path: std::path::PathBuf,
    buf: &mut Vec<u8>,
    source: gix_config::Source,
    git_dir_trust: gix_sec::Trust,
    lossy: Option<bool>,
    lenient: bool,
) -> Result<gix_config::File<'static>, Error> {
    let metadata = gix_config::file::Metadata::from(source)
        .at(&config_path)
        .with(git_dir_trust);
    let mut file = match std::fs::File::open(&config_path) {
        Ok(f) => f,
        Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(gix_config::File::new(metadata)),
        Err(err) => {
            let err = Error::Io {
                source: err,
                path: config_path,
            };
            if lenient {
                log::warn!("ignoring: {err:#?}");
                return Ok(gix_config::File::new(metadata));
            } else {
                return Err(err);
            }
        }
    };

    buf.clear();
    if let Err(err) = std::io::copy(&mut file, buf) {
        let err = Error::Io {
            source: err,
            path: config_path,
        };
        if lenient {
            log::warn!("ignoring: {err:#?}");
            buf.clear();
        } else {
            return Err(err);
        }
    };

    let config = gix_config::File::from_bytes_owned(
        buf,
        metadata,
        gix_config::file::init::Options {
            includes: gix_config::file::includes::Options::no_follow(),
            ..util::base_options(lossy, lenient)
        },
    )?;

    Ok(config)
}