git_index/file/
init.rs

1#![allow(unused)]
2
3use std::path::{Path, PathBuf};
4
5use memmap2::Mmap;
6
7use crate::{decode, extension, File, State};
8
9mod error {
10
11    /// The error returned by [File::at()][super::File::at()].
12    #[derive(Debug, thiserror::Error)]
13    #[allow(missing_docs)]
14    pub enum Error {
15        #[error("An IO error occurred while opening the index")]
16        Io(#[from] std::io::Error),
17        #[error(transparent)]
18        Decode(#[from] crate::decode::Error),
19        #[error(transparent)]
20        LinkExtension(#[from] crate::extension::link::decode::Error),
21    }
22}
23
24pub use error::Error;
25
26/// Initialization
27impl File {
28    /// Try to open the index file at `path` with `options`, assuming `object_hash` is used throughout the file, or create a new
29    /// index that merely exists in memory and is empty.
30    ///
31    /// Note that the `path` will not be written if it doesn't exist.
32    pub fn at_or_default(
33        path: impl Into<PathBuf>,
34        object_hash: git_hash::Kind,
35        options: decode::Options,
36    ) -> Result<Self, Error> {
37        let path = path.into();
38        Ok(match Self::at(&path, object_hash, options) {
39            Ok(f) => f,
40            Err(Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => {
41                File::from_state(State::new(object_hash), path)
42            }
43            Err(err) => return Err(err),
44        })
45    }
46
47    /// Open an index file at `path` with `options`, assuming `object_hash` is used throughout the file.
48    pub fn at(path: impl Into<PathBuf>, object_hash: git_hash::Kind, options: decode::Options) -> Result<Self, Error> {
49        let path = path.into();
50        let (data, mtime) = {
51            // SAFETY: we have to take the risk of somebody changing the file underneath. Git never writes into the same file.
52            let file = std::fs::File::open(&path)?;
53            #[allow(unsafe_code)]
54            let data = unsafe { Mmap::map(&file)? };
55            (data, filetime::FileTime::from_last_modification_time(&file.metadata()?))
56        };
57
58        let (state, checksum) = State::from_bytes(&data, mtime, object_hash, options)?;
59        let mut file = File {
60            state,
61            path,
62            checksum: Some(checksum),
63        };
64        if let Some(mut link) = file.link.take() {
65            link.dissolve_into(&mut file, object_hash, options)?;
66        }
67
68        Ok(file)
69    }
70
71    /// Consume `state` and pretend it was read from `path`, setting our checksum to `null`.
72    ///
73    /// `File` instances created like that should be written to disk to set the correct checksum via `[File::write()]`.
74    pub fn from_state(state: crate::State, path: impl Into<PathBuf>) -> Self {
75        File {
76            state,
77            path: path.into(),
78            checksum: None,
79        }
80    }
81}