rtb_vcs/git/init.rs
1//! `Repo::init` — initialise a fresh repository.
2//!
3//! v0.5 commit 1. Scaffolder context: `rtb new` (planned v0.6) uses
4//! this to git-init a freshly generated project before its initial
5//! commit. See spec §3.1 for the option set; v0.5 ships with a
6//! minimal [`InitOptions`] and grows the surface as concrete consumer
7//! needs arrive.
8
9use std::path::{Path, PathBuf};
10
11use super::{Repo, RepoError};
12
13/// Options for [`Repo::init`].
14///
15/// v0.5 ships an empty default. Knobs (bare init, initial branch
16/// name, template path) land alongside the first consumer that asks
17/// for them — kept off the API until then so the foundation surface
18/// stays tight.
19#[derive(Debug, Default, Clone)]
20#[non_exhaustive]
21pub struct InitOptions {}
22
23impl Repo {
24 /// Initialise a new repository at `path`. The directory is
25 /// created if it doesn't already exist (mirroring `git init <path>`
26 /// semantics).
27 ///
28 /// # Errors
29 ///
30 /// - [`RepoError::InitFailed`] — gix could not create the
31 /// repository (filesystem permission, an existing repository
32 /// that conflicts, etc.). `cause` carries the backend's
33 /// stringified error.
34 pub async fn init(path: impl AsRef<Path>, _opts: InitOptions) -> Result<Self, RepoError> {
35 let path: PathBuf = path.as_ref().to_path_buf();
36 let path_for_task = path.clone();
37 tokio::task::spawn_blocking(move || {
38 // `gix::init` returns a `Repository`; wrap it as a
39 // thread-safe handle so `Repo` is Send + Sync.
40 let repo = gix::init(&path_for_task).map_err(|e| RepoError::InitFailed {
41 path: path_for_task.clone(),
42 cause: e.to_string(),
43 })?;
44 Ok::<_, RepoError>(Self::from_thread_safe(repo.into_sync(), path_for_task))
45 })
46 .await
47 .map_err(|join_err| RepoError::InitFailed {
48 path: path.clone(),
49 cause: format!("spawn_blocking join error: {join_err}"),
50 })?
51 }
52}