mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-18 14:31:30 +03:00
Merge pull request #2287 from gitbutlerapp/core-git
add core gitbutler-git crate
This commit is contained in:
commit
62c3322154
1
.github/workflows/push.yaml
vendored
1
.github/workflows/push.yaml
vendored
@ -77,3 +77,4 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/init-env-rust
|
||||
- run: cargo clippy --all-targets --all-features --tests
|
||||
- run: cargo clippy --no-default-features --tests -p gitbutler-git
|
||||
|
9
Cargo.lock
generated
9
Cargo.lock
generated
@ -1871,6 +1871,15 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gitbutler-git"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"git2",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glib"
|
||||
version = "0.15.12"
|
||||
|
@ -3,6 +3,7 @@ members = [
|
||||
"gitbutler-app",
|
||||
"gitbutler-core",
|
||||
"gitbutler-diff",
|
||||
"gitbutler-git",
|
||||
]
|
||||
resolver = "2"
|
||||
|
||||
|
15
gitbutler-git/Cargo.toml
Normal file
15
gitbutler-git/Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "gitbutler-git"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
default = ["git2", "serde"]
|
||||
git2 = ["dep:git2", "std"]
|
||||
serde = ["dep:serde"]
|
||||
std = []
|
||||
|
||||
[dependencies]
|
||||
git2 = { workspace = true, optional = true }
|
||||
thiserror.workspace = true
|
||||
serde = { workspace = true, optional = true }
|
2
gitbutler-git/src/backend.rs
Normal file
2
gitbutler-git/src/backend.rs
Normal file
@ -0,0 +1,2 @@
|
||||
#[cfg(feature = "git2")]
|
||||
pub mod git2;
|
8
gitbutler-git/src/backend/git2.rs
Normal file
8
gitbutler-git/src/backend/git2.rs
Normal file
@ -0,0 +1,8 @@
|
||||
//! [libgit2](https://libgit2.org/) implementation of
|
||||
//! the core `gitbutler-git` library traits.
|
||||
//!
|
||||
//! The entry point for this module is the [`Repository`] struct.
|
||||
|
||||
mod repository;
|
||||
|
||||
pub use self::repository::Repository;
|
71
gitbutler-git/src/backend/git2/repository.rs
Normal file
71
gitbutler-git/src/backend/git2/repository.rs
Normal file
@ -0,0 +1,71 @@
|
||||
use std::path::Path;
|
||||
|
||||
use crate::ConfigScope;
|
||||
|
||||
/// A [`crate::Repository`] implementation using the `git2` crate.
|
||||
pub struct Repository {
|
||||
repo: git2::Repository,
|
||||
}
|
||||
|
||||
impl Repository {
|
||||
/// Opens a repository at the given path.
|
||||
#[inline]
|
||||
pub fn open<P: AsRef<Path>>(path: P) -> Result<Self, git2::Error> {
|
||||
Ok(Self {
|
||||
repo: git2::Repository::open(path)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Repository for Repository {
|
||||
type Error = git2::Error;
|
||||
|
||||
async fn config_get(
|
||||
&self,
|
||||
key: &str,
|
||||
scope: ConfigScope,
|
||||
) -> Result<Option<String>, Self::Error> {
|
||||
let config = self.repo.config()?;
|
||||
|
||||
let res = match scope {
|
||||
ConfigScope::Auto => config.get_string(key),
|
||||
ConfigScope::Local => config.open_level(git2::ConfigLevel::Local)?.get_string(key),
|
||||
ConfigScope::System => config
|
||||
.open_level(git2::ConfigLevel::System)?
|
||||
.get_string(key),
|
||||
ConfigScope::Global => config
|
||||
.open_level(git2::ConfigLevel::Global)?
|
||||
.get_string(key),
|
||||
};
|
||||
|
||||
res.map(Some).or_else(|e| {
|
||||
if e.code() == git2::ErrorCode::NotFound {
|
||||
Ok(None)
|
||||
} else {
|
||||
Err(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async fn config_set(
|
||||
&self,
|
||||
key: &str,
|
||||
value: &str,
|
||||
scope: ConfigScope,
|
||||
) -> Result<(), Self::Error> {
|
||||
let mut config = self.repo.config()?;
|
||||
|
||||
match scope {
|
||||
ConfigScope::Auto => config.set_str(key, value),
|
||||
ConfigScope::Local => config
|
||||
.open_level(git2::ConfigLevel::Local)?
|
||||
.set_str(key, value),
|
||||
ConfigScope::System => config
|
||||
.open_level(git2::ConfigLevel::System)?
|
||||
.set_str(key, value),
|
||||
ConfigScope::Global => config
|
||||
.open_level(git2::ConfigLevel::Global)?
|
||||
.set_str(key, value),
|
||||
}
|
||||
}
|
||||
}
|
24
gitbutler-git/src/lib.rs
Normal file
24
gitbutler-git/src/lib.rs
Normal file
@ -0,0 +1,24 @@
|
||||
//! GitButler core library for interacting with Git.
|
||||
//!
|
||||
//! This library houses a number of Git implementations,
|
||||
//! over which we abstract a common interface and provide
|
||||
//! higher-level operations that are implementation-agnostic.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)] // must be first
|
||||
#![feature(error_in_core)]
|
||||
#![deny(missing_docs, unsafe_code)]
|
||||
#![allow(async_fn_in_trait)]
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
extern crate alloc;
|
||||
|
||||
mod backend;
|
||||
pub mod ops;
|
||||
mod repository;
|
||||
|
||||
pub(crate) mod prelude;
|
||||
|
||||
#[cfg(feature = "git2")]
|
||||
pub use backend::git2;
|
||||
|
||||
pub use self::repository::{ConfigScope, Repository};
|
30
gitbutler-git/src/ops.rs
Normal file
30
gitbutler-git/src/ops.rs
Normal file
@ -0,0 +1,30 @@
|
||||
//! High-level operations that are implementation-agnostic.
|
||||
//!
|
||||
//! These operations are similar to Git's non-plumbing commands,
|
||||
//! in that they compose both high- and low-level operations
|
||||
//! into more complex operations, without caring about the
|
||||
//! underlying implementation.
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use crate::prelude::*;
|
||||
|
||||
use crate::{ConfigScope, Repository};
|
||||
|
||||
/// Returns whether or not the repository has GitButler's
|
||||
/// utmost discretion enabled.
|
||||
pub async fn has_utmost_discretion<R: Repository>(repo: &R) -> Result<bool, R::Error> {
|
||||
let config = repo
|
||||
.config_get("gitbutler.utmostDiscretion", ConfigScope::Auto)
|
||||
.await?;
|
||||
Ok(config == Some("true".to_string()))
|
||||
}
|
||||
|
||||
/// Sets whether or not the repository has GitButler's utmost discretion.
|
||||
pub async fn set_utmost_discretion<R: Repository>(repo: &R, value: bool) -> Result<(), R::Error> {
|
||||
repo.config_set(
|
||||
"gitbutler.utmostDiscretion",
|
||||
if value { "true" } else { "false" },
|
||||
ConfigScope::Local,
|
||||
)
|
||||
.await
|
||||
}
|
2
gitbutler-git/src/prelude.rs
Normal file
2
gitbutler-git/src/prelude.rs
Normal file
@ -0,0 +1,2 @@
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub use alloc::string::{String, ToString};
|
44
gitbutler-git/src/repository.rs
Normal file
44
gitbutler-git/src/repository.rs
Normal file
@ -0,0 +1,44 @@
|
||||
#[allow(unused_imports)]
|
||||
use crate::prelude::*;
|
||||
|
||||
/// The scope from/to which a configuration value is read/written.
|
||||
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum ConfigScope {
|
||||
/// Pull from the most appropriate scope.
|
||||
/// This is the default, and will fall back to a higher
|
||||
/// scope if the value is not initially found.
|
||||
#[default]
|
||||
Auto = 0,
|
||||
/// Pull from the local scope (`.git/config`) _only_.
|
||||
Local = 1,
|
||||
/// Pull from the system-wide scope (`${prefix}/etc/gitconfig`) _only_.
|
||||
System = 2,
|
||||
/// Pull from the global (user) scope (typically `~/.gitconfig`) _only_.
|
||||
Global = 3,
|
||||
}
|
||||
|
||||
/// A handle to an open Git repository.
|
||||
pub trait Repository {
|
||||
/// The type of error returned by this repository.
|
||||
type Error: core::error::Error + Send + Sync + 'static;
|
||||
|
||||
/// Reads a configuration value.
|
||||
///
|
||||
/// Errors if the value is not valid UTF-8.
|
||||
async fn config_get(
|
||||
&self,
|
||||
key: &str,
|
||||
scope: ConfigScope,
|
||||
) -> Result<Option<String>, Self::Error>;
|
||||
|
||||
/// Writes a configuration value.
|
||||
///
|
||||
/// Errors if the new value is not valid UTF-8.
|
||||
async fn config_set(
|
||||
&self,
|
||||
key: &str,
|
||||
value: &str,
|
||||
scope: ConfigScope,
|
||||
) -> Result<(), Self::Error>;
|
||||
}
|
Loading…
Reference in New Issue
Block a user