101 lines · 3.8 KB · Rust
RawDownload
#![allow(clippy::result_large_err)]use std::{borrow::Cow, convert::TryInto, path::Path}; use gix_ref::{    store::WriteReflog,    transaction::{PreviousValue, RefEdit},    FullName, Target,}; use crate::{bstr::BString, config::tree::Init, ThreadSafeRepository}; /// The name of the branch to use if non is configured via git configuration.////// # Deviation////// We use `main` instead of `master`.pub const DEFAULT_BRANCH_NAME: &str = "main"; /// The error returned by [`crate::init()`].#[derive(Debug, thiserror::Error)]#[allow(missing_docs)]pub enum Error {    #[error("Could not obtain the current directory")]    CurrentDir(#[from] std::io::Error),    #[error(transparent)]    Init(#[from] crate::create::Error),    #[error(transparent)]    Open(#[from] crate::open::Error),    #[error("Invalid default branch name: {name:?}")]    InvalidBranchName {        name: BString,        source: gix_validate::refname::Error,    },    #[error("Could not edit HEAD reference with new default name")]    EditHeadForDefaultBranch(#[from] crate::reference::edit::Error),} impl ThreadSafeRepository {    /// Create a repository with work-tree within `directory`, creating intermediate directories as needed.    ///    /// Fails without action if there is already a `.git` repository inside of `directory`, but    /// won't mind if the `directory` otherwise is non-empty.    pub fn init(        directory: impl AsRef<Path>,        kind: crate::create::Kind,        options: crate::create::Options,    ) -> Result<Self, Error> {        use gix_sec::trust::DefaultForLevel;        let open_options = crate::open::Options::default_for_level(gix_sec::Trust::Full);        Self::init_opts(directory, kind, options, open_options)    }     /// Similar to [`init`][Self::init()], but allows to determine how exactly to open the newly created repository.    ///    /// # Deviation    ///    /// Instead of naming the default branch `master`, we name it `main` unless configured explicitly using the `init.defaultBranch`    /// configuration key.    pub fn init_opts(        directory: impl AsRef<Path>,        kind: crate::create::Kind,        create_options: crate::create::Options,        mut open_options: crate::open::Options,    ) -> Result<Self, Error> {        let path = crate::create::into(directory.as_ref(), kind, create_options)?;        let (git_dir, worktree_dir) = path.into_repository_and_work_tree_directories();        open_options.git_dir_trust = Some(gix_sec::Trust::Full);        open_options.current_dir = std::env::current_dir()?.into();        let repo = ThreadSafeRepository::open_from_paths(git_dir, worktree_dir, open_options)?;         let branch_name = repo            .config            .resolved            .string("init", None, Init::DEFAULT_BRANCH.name)            .unwrap_or_else(|| Cow::Borrowed(DEFAULT_BRANCH_NAME.into()));        if branch_name.as_ref() != DEFAULT_BRANCH_NAME {            let sym_ref: FullName =                format!("refs/heads/{branch_name}")                    .try_into()                    .map_err(|err| Error::InvalidBranchName {                        name: branch_name.into_owned(),                        source: err,                    })?;            let mut repo = repo.to_thread_local();            let prev_write_reflog = repo.refs.write_reflog;            repo.refs.write_reflog = WriteReflog::Disable;            repo.edit_reference(RefEdit {                change: gix_ref::transaction::Change::Update {                    log: Default::default(),                    expected: PreviousValue::Any,                    new: Target::Symbolic(sym_ref),                },                name: "HEAD".try_into().expect("valid"),                deref: false,            })?;            repo.refs.write_reflog = prev_write_reflog;        }         Ok(repo)    }}