mirror of
https://github.com/extrawurst/gitui.git
synced 2024-11-22 02:12:58 +03:00
support bare repos (#1028)
This commit is contained in:
parent
ecabee02da
commit
006cdd6373
@ -30,6 +30,7 @@ The way this works got changed and simplified ([See docs](https://github.com/ext
|
||||
- dedicated fuzzy finder up/down keys to allow vim overrides ([#993](https://github.com/extrawurst/gitui/pull/993))
|
||||
- pull will also download tags ([#1013](https://github.com/extrawurst/gitui/pull/1013))
|
||||
- allow editing file from filetree ([#989](https://github.com/extrawurst/gitui/pull/989))
|
||||
- support bare repos (new `workdir` argument) ([#1026](https://github.com/extrawurst/gitui/pull/1026))
|
||||
|
||||
### Fixed
|
||||
- honor options (for untracked files) in `stage_all` command ([#933](https://github.com/extrawurst/gitui/issues/933))
|
||||
|
2
Makefile
2
Makefile
@ -2,7 +2,7 @@
|
||||
.PHONY: debug build-release release-linux-musl test clippy clippy-pedantic install install-debug
|
||||
|
||||
ARGS=-l
|
||||
# ARGS=-l -d <some_path>
|
||||
# ARGS=-l -d ~/code/git-bare-test.git -w ~/code/git-bare-test
|
||||
|
||||
profile:
|
||||
cargo run --features=timing,pprof -- ${ARGS}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::{
|
||||
error::Result,
|
||||
hash,
|
||||
sync::{self, FileBlame},
|
||||
AsyncGitNotification, CWD,
|
||||
sync::{self, FileBlame, RepoPath},
|
||||
AsyncGitNotification,
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
use std::{
|
||||
@ -34,12 +34,17 @@ pub struct AsyncBlame {
|
||||
last: Arc<Mutex<Option<LastResult<BlameParams, FileBlame>>>>,
|
||||
sender: Sender<AsyncGitNotification>,
|
||||
pending: Arc<AtomicUsize>,
|
||||
repo: RepoPath,
|
||||
}
|
||||
|
||||
impl AsyncBlame {
|
||||
///
|
||||
pub fn new(sender: &Sender<AsyncGitNotification>) -> Self {
|
||||
pub fn new(
|
||||
repo: RepoPath,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
) -> Self {
|
||||
Self {
|
||||
repo,
|
||||
current: Arc::new(Mutex::new(Request(0, None))),
|
||||
last: Arc::new(Mutex::new(None)),
|
||||
sender: sender.clone(),
|
||||
@ -96,11 +101,13 @@ impl AsyncBlame {
|
||||
let arc_last = Arc::clone(&self.last);
|
||||
let sender = self.sender.clone();
|
||||
let arc_pending = Arc::clone(&self.pending);
|
||||
let repo = self.repo.clone();
|
||||
|
||||
self.pending.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
rayon_core::spawn(move || {
|
||||
let notify = Self::get_blame_helper(
|
||||
&repo,
|
||||
params,
|
||||
&arc_last,
|
||||
&arc_current,
|
||||
@ -130,6 +137,7 @@ impl AsyncBlame {
|
||||
}
|
||||
|
||||
fn get_blame_helper(
|
||||
repo_path: &RepoPath,
|
||||
params: BlameParams,
|
||||
arc_last: &Arc<
|
||||
Mutex<Option<LastResult<BlameParams, FileBlame>>>,
|
||||
@ -138,7 +146,7 @@ impl AsyncBlame {
|
||||
hash: u64,
|
||||
) -> Result<bool> {
|
||||
let file_blame =
|
||||
sync::blame::blame_file(CWD, ¶ms.file_path)?;
|
||||
sync::blame::blame_file(repo_path, ¶ms.file_path)?;
|
||||
|
||||
let mut notify = false;
|
||||
{
|
||||
|
@ -1,28 +1,27 @@
|
||||
use crate::{
|
||||
error::Result,
|
||||
sync::{self, branch::get_branch_name},
|
||||
sync::{self, branch::get_branch_name, RepoPathRef},
|
||||
};
|
||||
use sync::Head;
|
||||
|
||||
///
|
||||
pub struct BranchName {
|
||||
last_result: Option<(Head, String)>,
|
||||
repo_path: String,
|
||||
repo: RepoPathRef,
|
||||
}
|
||||
|
||||
impl BranchName {
|
||||
///
|
||||
pub fn new(path: &str) -> Self {
|
||||
pub const fn new(repo: RepoPathRef) -> Self {
|
||||
Self {
|
||||
repo_path: path.to_string(),
|
||||
repo,
|
||||
last_result: None,
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
pub fn lookup(&mut self) -> Result<String> {
|
||||
let current_head =
|
||||
sync::get_head_tuple(self.repo_path.as_str())?;
|
||||
let current_head = sync::get_head_tuple(&self.repo.borrow())?;
|
||||
|
||||
if let Some((last_head, branch_name)) =
|
||||
self.last_result.as_ref()
|
||||
@ -41,7 +40,7 @@ impl BranchName {
|
||||
}
|
||||
|
||||
fn fetch(&mut self, head: Head) -> Result<String> {
|
||||
let name = get_branch_name(self.repo_path.as_str())?;
|
||||
let name = get_branch_name(&self.repo.borrow())?;
|
||||
self.last_result = Some((head, name.clone()));
|
||||
Ok(name)
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
error::Result,
|
||||
sync::{self, CommitId},
|
||||
AsyncGitNotification, StatusItem, CWD,
|
||||
sync::{self, CommitId, RepoPath},
|
||||
AsyncGitNotification, StatusItem,
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
use std::sync::{
|
||||
@ -42,12 +42,17 @@ pub struct AsyncCommitFiles {
|
||||
Arc<Mutex<Option<Request<CommitFilesParams, ResultType>>>>,
|
||||
sender: Sender<AsyncGitNotification>,
|
||||
pending: Arc<AtomicUsize>,
|
||||
repo: RepoPath,
|
||||
}
|
||||
|
||||
impl AsyncCommitFiles {
|
||||
///
|
||||
pub fn new(sender: &Sender<AsyncGitNotification>) -> Self {
|
||||
pub fn new(
|
||||
repo: RepoPath,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
) -> Self {
|
||||
Self {
|
||||
repo,
|
||||
current: Arc::new(Mutex::new(None)),
|
||||
sender: sender.clone(),
|
||||
pending: Arc::new(AtomicUsize::new(0)),
|
||||
@ -89,11 +94,12 @@ impl AsyncCommitFiles {
|
||||
let arc_current = Arc::clone(&self.current);
|
||||
let sender = self.sender.clone();
|
||||
let arc_pending = Arc::clone(&self.pending);
|
||||
let repo = self.repo.clone();
|
||||
|
||||
self.pending.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
rayon_core::spawn(move || {
|
||||
Self::fetch_helper(params, &arc_current)
|
||||
Self::fetch_helper(&repo, params, &arc_current)
|
||||
.expect("failed to fetch");
|
||||
|
||||
arc_pending.fetch_sub(1, Ordering::Relaxed);
|
||||
@ -107,13 +113,17 @@ impl AsyncCommitFiles {
|
||||
}
|
||||
|
||||
fn fetch_helper(
|
||||
repo_path: &RepoPath,
|
||||
params: CommitFilesParams,
|
||||
arc_current: &Arc<
|
||||
Mutex<Option<Request<CommitFilesParams, ResultType>>>,
|
||||
>,
|
||||
) -> Result<()> {
|
||||
let res =
|
||||
sync::get_commit_files(CWD, params.id, params.other)?;
|
||||
let res = sync::get_commit_files(
|
||||
repo_path,
|
||||
params.id,
|
||||
params.other,
|
||||
)?;
|
||||
|
||||
log::trace!("get_commit_files: {:?} ({})", params, res.len());
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::{
|
||||
error::Result,
|
||||
hash,
|
||||
sync::{self, diff::DiffOptions, CommitId},
|
||||
AsyncGitNotification, FileDiff, CWD,
|
||||
sync::{self, diff::DiffOptions, CommitId, RepoPath},
|
||||
AsyncGitNotification, FileDiff,
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
use std::{
|
||||
@ -51,12 +51,17 @@ pub struct AsyncDiff {
|
||||
last: Arc<Mutex<Option<LastResult<DiffParams, FileDiff>>>>,
|
||||
sender: Sender<AsyncGitNotification>,
|
||||
pending: Arc<AtomicUsize>,
|
||||
repo: RepoPath,
|
||||
}
|
||||
|
||||
impl AsyncDiff {
|
||||
///
|
||||
pub fn new(sender: &Sender<AsyncGitNotification>) -> Self {
|
||||
pub fn new(
|
||||
repo: RepoPath,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
) -> Self {
|
||||
Self {
|
||||
repo,
|
||||
current: Arc::new(Mutex::new(Request(0, None))),
|
||||
last: Arc::new(Mutex::new(None)),
|
||||
sender: sender.clone(),
|
||||
@ -109,11 +114,13 @@ impl AsyncDiff {
|
||||
let arc_last = Arc::clone(&self.last);
|
||||
let sender = self.sender.clone();
|
||||
let arc_pending = Arc::clone(&self.pending);
|
||||
let repo = self.repo.clone();
|
||||
|
||||
self.pending.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
rayon_core::spawn(move || {
|
||||
let notify = Self::get_diff_helper(
|
||||
&repo,
|
||||
params,
|
||||
&arc_last,
|
||||
&arc_current,
|
||||
@ -143,6 +150,7 @@ impl AsyncDiff {
|
||||
}
|
||||
|
||||
fn get_diff_helper(
|
||||
repo_path: &RepoPath,
|
||||
params: DiffParams,
|
||||
arc_last: &Arc<
|
||||
Mutex<Option<LastResult<DiffParams, FileDiff>>>,
|
||||
@ -152,24 +160,24 @@ impl AsyncDiff {
|
||||
) -> Result<bool> {
|
||||
let res = match params.diff_type {
|
||||
DiffType::Stage => sync::diff::get_diff(
|
||||
CWD,
|
||||
repo_path,
|
||||
¶ms.path,
|
||||
true,
|
||||
Some(params.options),
|
||||
)?,
|
||||
DiffType::WorkDir => sync::diff::get_diff(
|
||||
CWD,
|
||||
repo_path,
|
||||
¶ms.path,
|
||||
false,
|
||||
Some(params.options),
|
||||
)?,
|
||||
DiffType::Commit(id) => sync::diff::get_diff_commit(
|
||||
CWD,
|
||||
repo_path,
|
||||
id,
|
||||
params.path.clone(),
|
||||
)?,
|
||||
DiffType::Commits(ids) => sync::diff::get_diff_commits(
|
||||
CWD,
|
||||
repo_path,
|
||||
ids,
|
||||
params.path.clone(),
|
||||
)?,
|
||||
|
@ -3,9 +3,9 @@
|
||||
use crate::{
|
||||
asyncjob::{AsyncJob, RunParams},
|
||||
error::Result,
|
||||
sync::cred::BasicAuthCredential,
|
||||
sync::remotes::fetch_all,
|
||||
AsyncGitNotification, ProgressPercent, CWD,
|
||||
sync::{cred::BasicAuthCredential, RepoPath},
|
||||
AsyncGitNotification, ProgressPercent,
|
||||
};
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
@ -16,18 +16,21 @@ enum JobState {
|
||||
}
|
||||
|
||||
///
|
||||
#[derive(Clone, Default)]
|
||||
#[derive(Clone)]
|
||||
pub struct AsyncFetchJob {
|
||||
state: Arc<Mutex<Option<JobState>>>,
|
||||
repo: RepoPath,
|
||||
}
|
||||
|
||||
///
|
||||
impl AsyncFetchJob {
|
||||
///
|
||||
pub fn new(
|
||||
repo: RepoPath,
|
||||
basic_credential: Option<BasicAuthCredential>,
|
||||
) -> Self {
|
||||
Self {
|
||||
repo,
|
||||
state: Arc::new(Mutex::new(Some(JobState::Request(
|
||||
basic_credential,
|
||||
)))),
|
||||
@ -61,8 +64,11 @@ impl AsyncJob for AsyncFetchJob {
|
||||
*state = state.take().map(|state| match state {
|
||||
JobState::Request(basic_credentials) => {
|
||||
//TODO: support progress
|
||||
let result =
|
||||
fetch_all(CWD, &basic_credentials, &None);
|
||||
let result = fetch_all(
|
||||
&self.repo,
|
||||
&basic_credentials,
|
||||
&None,
|
||||
);
|
||||
|
||||
JobState::Response(result)
|
||||
}
|
||||
|
@ -94,9 +94,6 @@ pub enum AsyncGitNotification {
|
||||
Fetch,
|
||||
}
|
||||
|
||||
/// current working directory `./`
|
||||
pub static CWD: &str = "./";
|
||||
|
||||
/// helper function to calculate the hash of an arbitrary type that implements the `Hash` trait
|
||||
pub fn hash<T: Hash + ?Sized>(v: &T) -> u64 {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
|
@ -3,8 +3,9 @@ use crate::{
|
||||
sync::{
|
||||
cred::BasicAuthCredential,
|
||||
remotes::{fetch, push::ProgressNotification},
|
||||
RepoPath,
|
||||
},
|
||||
AsyncGitNotification, RemoteProgress, CWD,
|
||||
AsyncGitNotification, RemoteProgress,
|
||||
};
|
||||
use crossbeam_channel::{unbounded, Sender};
|
||||
use std::{
|
||||
@ -33,12 +34,17 @@ pub struct AsyncPull {
|
||||
last_result: Arc<Mutex<Option<(usize, String)>>>,
|
||||
progress: Arc<Mutex<Option<ProgressNotification>>>,
|
||||
sender: Sender<AsyncGitNotification>,
|
||||
repo: RepoPath,
|
||||
}
|
||||
|
||||
impl AsyncPull {
|
||||
///
|
||||
pub fn new(sender: &Sender<AsyncGitNotification>) -> Self {
|
||||
pub fn new(
|
||||
repo: RepoPath,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
) -> Self {
|
||||
Self {
|
||||
repo,
|
||||
state: Arc::new(Mutex::new(None)),
|
||||
last_result: Arc::new(Mutex::new(None)),
|
||||
progress: Arc::new(Mutex::new(None)),
|
||||
@ -79,6 +85,7 @@ impl AsyncPull {
|
||||
let arc_res = Arc::clone(&self.last_result);
|
||||
let arc_progress = Arc::clone(&self.progress);
|
||||
let sender = self.sender.clone();
|
||||
let repo = self.repo.clone();
|
||||
|
||||
thread::spawn(move || {
|
||||
let (progress_sender, receiver) = unbounded();
|
||||
@ -91,7 +98,7 @@ impl AsyncPull {
|
||||
);
|
||||
|
||||
let res = fetch(
|
||||
CWD,
|
||||
&repo,
|
||||
¶ms.branch,
|
||||
params.basic_credential,
|
||||
Some(progress_sender.clone()),
|
||||
|
@ -2,9 +2,9 @@ use crate::{
|
||||
error::{Error, Result},
|
||||
sync::{
|
||||
cred::BasicAuthCredential, remotes::push::push,
|
||||
remotes::push::ProgressNotification,
|
||||
remotes::push::ProgressNotification, RepoPath,
|
||||
},
|
||||
AsyncGitNotification, RemoteProgress, CWD,
|
||||
AsyncGitNotification, RemoteProgress,
|
||||
};
|
||||
use crossbeam_channel::{unbounded, Sender};
|
||||
use std::{
|
||||
@ -37,12 +37,17 @@ pub struct AsyncPush {
|
||||
last_result: Arc<Mutex<Option<String>>>,
|
||||
progress: Arc<Mutex<Option<ProgressNotification>>>,
|
||||
sender: Sender<AsyncGitNotification>,
|
||||
repo: RepoPath,
|
||||
}
|
||||
|
||||
impl AsyncPush {
|
||||
///
|
||||
pub fn new(sender: &Sender<AsyncGitNotification>) -> Self {
|
||||
pub fn new(
|
||||
repo: RepoPath,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
) -> Self {
|
||||
Self {
|
||||
repo,
|
||||
state: Arc::new(Mutex::new(None)),
|
||||
last_result: Arc::new(Mutex::new(None)),
|
||||
progress: Arc::new(Mutex::new(None)),
|
||||
@ -83,6 +88,7 @@ impl AsyncPush {
|
||||
let arc_res = Arc::clone(&self.last_result);
|
||||
let arc_progress = Arc::clone(&self.progress);
|
||||
let sender = self.sender.clone();
|
||||
let repo = self.repo.clone();
|
||||
|
||||
thread::spawn(move || {
|
||||
let (progress_sender, receiver) = unbounded();
|
||||
@ -95,7 +101,7 @@ impl AsyncPush {
|
||||
);
|
||||
|
||||
let res = push(
|
||||
CWD,
|
||||
&repo,
|
||||
params.remote.as_str(),
|
||||
params.branch.as_str(),
|
||||
params.force,
|
||||
|
@ -3,8 +3,9 @@ use crate::{
|
||||
sync::{
|
||||
cred::BasicAuthCredential,
|
||||
remotes::tags::{push_tags, PushTagsProgress},
|
||||
RepoPath,
|
||||
},
|
||||
AsyncGitNotification, RemoteProgress, CWD,
|
||||
AsyncGitNotification, RemoteProgress,
|
||||
};
|
||||
use crossbeam_channel::{unbounded, Sender};
|
||||
use std::{
|
||||
@ -31,12 +32,17 @@ pub struct AsyncPushTags {
|
||||
last_result: Arc<Mutex<Option<String>>>,
|
||||
progress: Arc<Mutex<Option<PushTagsProgress>>>,
|
||||
sender: Sender<AsyncGitNotification>,
|
||||
repo: RepoPath,
|
||||
}
|
||||
|
||||
impl AsyncPushTags {
|
||||
///
|
||||
pub fn new(sender: &Sender<AsyncGitNotification>) -> Self {
|
||||
pub fn new(
|
||||
repo: RepoPath,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
) -> Self {
|
||||
Self {
|
||||
repo,
|
||||
state: Arc::new(Mutex::new(None)),
|
||||
last_result: Arc::new(Mutex::new(None)),
|
||||
progress: Arc::new(Mutex::new(None)),
|
||||
@ -77,6 +83,7 @@ impl AsyncPushTags {
|
||||
let arc_res = Arc::clone(&self.last_result);
|
||||
let arc_progress = Arc::clone(&self.progress);
|
||||
let sender = self.sender.clone();
|
||||
let repo = self.repo.clone();
|
||||
|
||||
thread::spawn(move || {
|
||||
let (progress_sender, receiver) = unbounded();
|
||||
@ -89,7 +96,7 @@ impl AsyncPushTags {
|
||||
);
|
||||
|
||||
let res = push_tags(
|
||||
CWD,
|
||||
&repo,
|
||||
params.remote.as_str(),
|
||||
params.basic_credential.clone(),
|
||||
Some(progress_sender),
|
||||
|
@ -4,8 +4,11 @@ use crate::{
|
||||
asyncjob::{AsyncJob, RunParams},
|
||||
error::Result,
|
||||
sync::cred::BasicAuthCredential,
|
||||
sync::remotes::{get_default_remote, tags_missing_remote},
|
||||
AsyncGitNotification, CWD,
|
||||
sync::{
|
||||
remotes::{get_default_remote, tags_missing_remote},
|
||||
RepoPath,
|
||||
},
|
||||
AsyncGitNotification,
|
||||
};
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
@ -16,18 +19,21 @@ enum JobState {
|
||||
}
|
||||
|
||||
///
|
||||
#[derive(Clone, Default)]
|
||||
#[derive(Clone)]
|
||||
pub struct AsyncRemoteTagsJob {
|
||||
state: Arc<Mutex<Option<JobState>>>,
|
||||
repo: RepoPath,
|
||||
}
|
||||
|
||||
///
|
||||
impl AsyncRemoteTagsJob {
|
||||
///
|
||||
pub fn new(
|
||||
repo: RepoPath,
|
||||
basic_credential: Option<BasicAuthCredential>,
|
||||
) -> Self {
|
||||
Self {
|
||||
repo,
|
||||
state: Arc::new(Mutex::new(Some(JobState::Request(
|
||||
basic_credential,
|
||||
)))),
|
||||
@ -60,10 +66,10 @@ impl AsyncJob for AsyncRemoteTagsJob {
|
||||
if let Ok(mut state) = self.state.lock() {
|
||||
*state = state.take().map(|state| match state {
|
||||
JobState::Request(basic_credential) => {
|
||||
let result =
|
||||
get_default_remote(CWD).and_then(|remote| {
|
||||
let result = get_default_remote(&self.repo)
|
||||
.and_then(|remote| {
|
||||
tags_missing_remote(
|
||||
CWD,
|
||||
&self.repo,
|
||||
&remote,
|
||||
basic_credential,
|
||||
)
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
error::Result,
|
||||
sync::{utils::repo, CommitId, LogWalker, LogWalkerFilter},
|
||||
AsyncGitNotification, CWD,
|
||||
sync::{repo, CommitId, LogWalker, LogWalkerFilter, RepoPath},
|
||||
AsyncGitNotification,
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
use git2::Oid;
|
||||
@ -33,6 +33,7 @@ pub struct AsyncLog {
|
||||
pending: Arc<AtomicBool>,
|
||||
background: Arc<AtomicBool>,
|
||||
filter: Option<LogWalkerFilter>,
|
||||
repo: RepoPath,
|
||||
}
|
||||
|
||||
static LIMIT_COUNT: usize = 3000;
|
||||
@ -42,10 +43,12 @@ static SLEEP_BACKGROUND: Duration = Duration::from_millis(1000);
|
||||
impl AsyncLog {
|
||||
///
|
||||
pub fn new(
|
||||
repo: RepoPath,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
filter: Option<LogWalkerFilter>,
|
||||
) -> Self {
|
||||
Self {
|
||||
repo,
|
||||
current: Arc::new(Mutex::new(Vec::new())),
|
||||
sender: sender.clone(),
|
||||
pending: Arc::new(AtomicBool::new(false)),
|
||||
@ -102,7 +105,7 @@ impl AsyncLog {
|
||||
|
||||
///
|
||||
fn head_changed(&self) -> Result<bool> {
|
||||
if let Ok(head) = repo(CWD)?.head() {
|
||||
if let Ok(head) = repo(&self.repo)?.head() {
|
||||
if let Some(head) = head.target() {
|
||||
return Ok(head != self.current_head()?.into());
|
||||
}
|
||||
@ -128,15 +131,16 @@ impl AsyncLog {
|
||||
let sender = self.sender.clone();
|
||||
let arc_pending = Arc::clone(&self.pending);
|
||||
let arc_background = Arc::clone(&self.background);
|
||||
let filter = self.filter.clone();
|
||||
let repo = self.repo.clone();
|
||||
|
||||
self.pending.store(true, Ordering::Relaxed);
|
||||
|
||||
let filter = self.filter.clone();
|
||||
|
||||
rayon_core::spawn(move || {
|
||||
scope_time!("async::revlog");
|
||||
|
||||
Self::fetch_helper(
|
||||
&repo,
|
||||
&arc_current,
|
||||
&arc_background,
|
||||
&sender,
|
||||
@ -153,13 +157,14 @@ impl AsyncLog {
|
||||
}
|
||||
|
||||
fn fetch_helper(
|
||||
repo_path: &RepoPath,
|
||||
arc_current: &Arc<Mutex<Vec<CommitId>>>,
|
||||
arc_background: &Arc<AtomicBool>,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
filter: Option<LogWalkerFilter>,
|
||||
) -> Result<()> {
|
||||
let mut entries = Vec::with_capacity(LIMIT_COUNT);
|
||||
let r = repo(CWD)?;
|
||||
let r = repo(repo_path)?;
|
||||
let mut walker =
|
||||
LogWalker::new(&r, LIMIT_COUNT)?.filter(filter);
|
||||
loop {
|
||||
|
@ -1,8 +1,10 @@
|
||||
use crate::{
|
||||
error::Result,
|
||||
hash,
|
||||
sync::{self, status::StatusType, ShowUntrackedFilesConfig},
|
||||
AsyncGitNotification, StatusItem, CWD,
|
||||
sync::{
|
||||
self, status::StatusType, RepoPath, ShowUntrackedFilesConfig,
|
||||
},
|
||||
AsyncGitNotification, StatusItem,
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
use std::{
|
||||
@ -56,12 +58,17 @@ pub struct AsyncStatus {
|
||||
last: Arc<Mutex<Status>>,
|
||||
sender: Sender<AsyncGitNotification>,
|
||||
pending: Arc<AtomicUsize>,
|
||||
repo: RepoPath,
|
||||
}
|
||||
|
||||
impl AsyncStatus {
|
||||
///
|
||||
pub fn new(sender: Sender<AsyncGitNotification>) -> Self {
|
||||
pub fn new(
|
||||
repo: RepoPath,
|
||||
sender: Sender<AsyncGitNotification>,
|
||||
) -> Self {
|
||||
Self {
|
||||
repo,
|
||||
current: Arc::new(Mutex::new(Request(0, None))),
|
||||
last: Arc::new(Mutex::new(Status::default())),
|
||||
sender,
|
||||
@ -115,11 +122,13 @@ impl AsyncStatus {
|
||||
let arc_pending = Arc::clone(&self.pending);
|
||||
let status_type = params.status_type;
|
||||
let config = params.config;
|
||||
let repo = self.repo.clone();
|
||||
|
||||
self.pending.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
rayon_core::spawn(move || {
|
||||
let ok = Self::fetch_helper(
|
||||
&repo,
|
||||
status_type,
|
||||
config,
|
||||
hash_request,
|
||||
@ -141,13 +150,14 @@ impl AsyncStatus {
|
||||
}
|
||||
|
||||
fn fetch_helper(
|
||||
repo: &RepoPath,
|
||||
status_type: StatusType,
|
||||
config: Option<ShowUntrackedFilesConfig>,
|
||||
hash_request: u64,
|
||||
arc_current: &Arc<Mutex<Request<u64, Status>>>,
|
||||
arc_last: &Arc<Mutex<Status>>,
|
||||
) -> Result<()> {
|
||||
let res = Self::get_status(status_type, config)?;
|
||||
let res = Self::get_status(repo, status_type, config)?;
|
||||
log::trace!(
|
||||
"status fetched: {} (type: {:?})",
|
||||
hash_request,
|
||||
@ -170,12 +180,13 @@ impl AsyncStatus {
|
||||
}
|
||||
|
||||
fn get_status(
|
||||
repo: &RepoPath,
|
||||
status_type: StatusType,
|
||||
config: Option<ShowUntrackedFilesConfig>,
|
||||
) -> Result<Status> {
|
||||
Ok(Status {
|
||||
items: sync::status::get_status(
|
||||
CWD,
|
||||
repo,
|
||||
status_type,
|
||||
config,
|
||||
)?,
|
||||
|
@ -1,9 +1,9 @@
|
||||
//! Sync git API for fetching a file blame
|
||||
|
||||
use super::{utils, CommitId};
|
||||
use super::{utils, CommitId, RepoPath};
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
sync::get_commits_info,
|
||||
sync::{get_commits_info, repository::repo},
|
||||
};
|
||||
use scopetime::scope_time;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
@ -54,12 +54,12 @@ fn fixup_windows_path(path: &str) -> String {
|
||||
|
||||
///
|
||||
pub fn blame_file(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
file_path: &str,
|
||||
) -> Result<FileBlame> {
|
||||
scope_time!("blame_file");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
|
||||
let commit_id = utils::get_head_repo(&repo)?;
|
||||
|
||||
@ -142,9 +142,9 @@ pub fn blame_file(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::error::Result;
|
||||
use crate::sync::{
|
||||
commit, stage_add_file, tests::repo_init_empty,
|
||||
use crate::{
|
||||
error::Result,
|
||||
sync::{commit, stage_add_file, tests::repo_init_empty},
|
||||
};
|
||||
use std::{
|
||||
fs::{File, OpenOptions},
|
||||
@ -157,7 +157,8 @@ mod tests {
|
||||
let file_path = Path::new("foo");
|
||||
let (_td, repo) = repo_init_empty()?;
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
assert!(matches!(blame_file(&repo_path, "foo"), Err(_)));
|
||||
|
||||
@ -237,7 +238,8 @@ mod tests {
|
||||
let file_path = Path::new("bar\\foo");
|
||||
let (_td, repo) = repo_init_empty().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
std::fs::create_dir(&root.join("bar")).unwrap();
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
use super::BranchType;
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
sync::{merge_msg, utils, CommitId},
|
||||
sync::{merge_msg, repository::repo, CommitId, RepoPath},
|
||||
};
|
||||
use git2::Commit;
|
||||
use scopetime::scope_time;
|
||||
@ -12,12 +12,12 @@ use scopetime::scope_time;
|
||||
/// if we did not create conflicts we create a merge commit and return the commit id.
|
||||
/// Otherwise we return `None`
|
||||
pub fn merge_upstream_commit(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
branch_name: &str,
|
||||
) -> Result<Option<CommitId>> {
|
||||
scope_time!("merge_upstream_commit");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
|
||||
let branch = repo.find_branch(branch_name, BranchType::Local)?;
|
||||
let upstream = branch.upstream()?;
|
||||
@ -130,7 +130,7 @@ mod test {
|
||||
);
|
||||
|
||||
push(
|
||||
clone1_dir.path().to_str().unwrap(),
|
||||
&clone1_dir.path().to_str().unwrap().into(),
|
||||
"origin",
|
||||
"master",
|
||||
false,
|
||||
@ -152,28 +152,36 @@ mod test {
|
||||
|
||||
//push should fail since origin diverged
|
||||
assert!(push(
|
||||
clone2_dir, "origin", "master", false, false, None, None,
|
||||
&clone2_dir.into(),
|
||||
"origin",
|
||||
"master",
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
None.into(),
|
||||
)
|
||||
.is_err());
|
||||
|
||||
//lets fetch from origin
|
||||
let bytes = fetch(clone2_dir, "master", None, None).unwrap();
|
||||
let bytes =
|
||||
fetch(&clone2_dir.into(), "master", None, None).unwrap();
|
||||
assert!(bytes > 0);
|
||||
|
||||
//we should be one commit behind
|
||||
assert_eq!(
|
||||
branch_compare_upstream(clone2_dir, "master")
|
||||
branch_compare_upstream(&clone2_dir.into(), "master")
|
||||
.unwrap()
|
||||
.behind,
|
||||
1
|
||||
);
|
||||
|
||||
let merge_commit =
|
||||
merge_upstream_commit(clone2_dir, "master")
|
||||
merge_upstream_commit(&clone2_dir.into(), "master")
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let state = crate::sync::repo_state(clone2_dir).unwrap();
|
||||
let state =
|
||||
crate::sync::repo_state(&clone2_dir.into()).unwrap();
|
||||
assert_eq!(state, RepoState::Clean);
|
||||
|
||||
assert!(!clone2.head_detached().unwrap());
|
||||
@ -185,9 +193,11 @@ mod test {
|
||||
assert_eq!(commits[2], commit1);
|
||||
|
||||
//verify commit msg
|
||||
let details =
|
||||
crate::sync::get_commit_details(clone2_dir, merge_commit)
|
||||
.unwrap();
|
||||
let details = crate::sync::get_commit_details(
|
||||
&clone2_dir.into(),
|
||||
merge_commit.into(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
details.message.unwrap().combine(),
|
||||
String::from("Merge remote-tracking branch 'refs/remotes/origin/master'")
|
||||
@ -214,12 +224,12 @@ mod test {
|
||||
);
|
||||
|
||||
debug_cmd_print(
|
||||
clone2_dir.path().to_str().unwrap(),
|
||||
&clone2_dir.path().to_str().unwrap().into(),
|
||||
"git status",
|
||||
);
|
||||
|
||||
push(
|
||||
clone1_dir.path().to_str().unwrap(),
|
||||
&clone1_dir.path().to_str().unwrap().into(),
|
||||
"origin",
|
||||
"master",
|
||||
false,
|
||||
@ -239,7 +249,7 @@ mod test {
|
||||
);
|
||||
|
||||
let bytes = fetch(
|
||||
clone2_dir.path().to_str().unwrap(),
|
||||
&clone2_dir.path().to_str().unwrap().into(),
|
||||
"master",
|
||||
None,
|
||||
None,
|
||||
@ -248,7 +258,7 @@ mod test {
|
||||
assert!(bytes > 0);
|
||||
|
||||
let res = merge_upstream_commit(
|
||||
clone2_dir.path().to_str().unwrap(),
|
||||
&clone2_dir.path().to_str().unwrap().into(),
|
||||
"master",
|
||||
)
|
||||
.unwrap();
|
||||
@ -257,7 +267,7 @@ mod test {
|
||||
assert_eq!(res, None);
|
||||
|
||||
let state = crate::sync::repo_state(
|
||||
clone2_dir.path().to_str().unwrap(),
|
||||
&clone2_dir.path().to_str().unwrap().into(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
@ -3,18 +3,18 @@
|
||||
use super::BranchType;
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
sync::utils,
|
||||
sync::{repository::repo, RepoPath},
|
||||
};
|
||||
use scopetime::scope_time;
|
||||
|
||||
///
|
||||
pub fn branch_merge_upstream_fastforward(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
branch: &str,
|
||||
) -> Result<()> {
|
||||
scope_time!("branch_merge_upstream");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
|
||||
let branch = repo.find_branch(branch, BranchType::Local)?;
|
||||
let upstream = branch.upstream()?;
|
||||
@ -76,7 +76,7 @@ pub mod test {
|
||||
write_commit_file(&clone1, "test.txt", "test", "commit1");
|
||||
|
||||
push(
|
||||
clone1_dir.path().to_str().unwrap(),
|
||||
&clone1_dir.path().to_str().unwrap().into(),
|
||||
"origin",
|
||||
"master",
|
||||
false,
|
||||
@ -88,7 +88,7 @@ pub mod test {
|
||||
|
||||
// clone2
|
||||
debug_cmd_print(
|
||||
clone2_dir.path().to_str().unwrap(),
|
||||
&clone2_dir.path().to_str().unwrap().into(),
|
||||
"git pull --ff",
|
||||
);
|
||||
|
||||
@ -100,7 +100,7 @@ pub mod test {
|
||||
);
|
||||
|
||||
push(
|
||||
clone2_dir.path().to_str().unwrap(),
|
||||
&clone2_dir.path().to_str().unwrap().into(),
|
||||
"origin",
|
||||
"master",
|
||||
false,
|
||||
@ -113,7 +113,7 @@ pub mod test {
|
||||
// clone1 again
|
||||
|
||||
let bytes = fetch(
|
||||
clone1_dir.path().to_str().unwrap(),
|
||||
&clone1_dir.path().to_str().unwrap().into(),
|
||||
"master",
|
||||
None,
|
||||
None,
|
||||
@ -122,7 +122,7 @@ pub mod test {
|
||||
assert!(bytes > 0);
|
||||
|
||||
let bytes = fetch(
|
||||
clone1_dir.path().to_str().unwrap(),
|
||||
&clone1_dir.path().to_str().unwrap().into(),
|
||||
"master",
|
||||
None,
|
||||
None,
|
||||
@ -131,7 +131,7 @@ pub mod test {
|
||||
assert_eq!(bytes, 0);
|
||||
|
||||
branch_merge_upstream_fastforward(
|
||||
clone1_dir.path().to_str().unwrap(),
|
||||
&clone1_dir.path().to_str().unwrap().into(),
|
||||
"master",
|
||||
)
|
||||
.unwrap();
|
||||
|
@ -2,19 +2,22 @@
|
||||
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
sync::{rebase::conflict_free_rebase, utils, CommitId},
|
||||
sync::{
|
||||
rebase::conflict_free_rebase, repository::repo, CommitId,
|
||||
RepoPath,
|
||||
},
|
||||
};
|
||||
use git2::BranchType;
|
||||
use scopetime::scope_time;
|
||||
|
||||
/// trys merging current branch with its upstrema using rebase
|
||||
pub fn merge_upstream_rebase(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
branch_name: &str,
|
||||
) -> Result<CommitId> {
|
||||
scope_time!("merge_upstream_rebase");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
if super::get_branch_name_repo(&repo)? != branch_name {
|
||||
return Err(Error::Generic(String::from(
|
||||
"can only rebase in head branch",
|
||||
@ -47,7 +50,7 @@ mod test {
|
||||
fn get_commit_msgs(r: &Repository) -> Vec<String> {
|
||||
let commits = get_commit_ids(r, 10);
|
||||
get_commits_info(
|
||||
r.workdir().unwrap().to_str().unwrap(),
|
||||
&r.workdir().unwrap().to_str().unwrap().into(),
|
||||
&commits,
|
||||
10,
|
||||
)
|
||||
@ -79,7 +82,13 @@ mod test {
|
||||
assert_eq!(clone1.head_detached().unwrap(), false);
|
||||
|
||||
push(
|
||||
clone1_dir, "origin", "master", false, false, None, None,
|
||||
&clone1_dir.into(),
|
||||
"origin",
|
||||
"master",
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@ -103,7 +112,13 @@ mod test {
|
||||
assert_eq!(clone2.head_detached().unwrap(), false);
|
||||
|
||||
push(
|
||||
clone2_dir, "origin", "master", false, false, None, None,
|
||||
&clone2_dir.into(),
|
||||
"origin",
|
||||
"master",
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@ -122,12 +137,13 @@ mod test {
|
||||
assert_eq!(clone1.head_detached().unwrap(), false);
|
||||
|
||||
//lets fetch from origin
|
||||
let bytes = fetch(clone1_dir, "master", None, None).unwrap();
|
||||
let bytes =
|
||||
fetch(&clone1_dir.into(), "master", None, None).unwrap();
|
||||
assert!(bytes > 0);
|
||||
|
||||
//we should be one commit behind
|
||||
assert_eq!(
|
||||
branch_compare_upstream(clone1_dir, "master")
|
||||
branch_compare_upstream(&clone1_dir.into(), "master")
|
||||
.unwrap()
|
||||
.behind,
|
||||
1
|
||||
@ -137,11 +153,12 @@ mod test {
|
||||
|
||||
assert_eq!(clone1.head_detached().unwrap(), false);
|
||||
|
||||
merge_upstream_rebase(clone1_dir, "master").unwrap();
|
||||
merge_upstream_rebase(&clone1_dir.into(), "master").unwrap();
|
||||
|
||||
debug_cmd_print(clone1_dir, "git log");
|
||||
debug_cmd_print(&clone1_dir.into(), "git log");
|
||||
|
||||
let state = crate::sync::repo_state(clone1_dir).unwrap();
|
||||
let state =
|
||||
crate::sync::repo_state(&clone1_dir.into()).unwrap();
|
||||
assert_eq!(state, RepoState::Clean);
|
||||
|
||||
let commits = get_commit_msgs(&clone1);
|
||||
@ -177,7 +194,13 @@ mod test {
|
||||
);
|
||||
|
||||
push(
|
||||
clone1_dir, "origin", "master", false, false, None, None,
|
||||
&clone1_dir.into(),
|
||||
"origin",
|
||||
"master",
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@ -197,7 +220,13 @@ mod test {
|
||||
);
|
||||
|
||||
push(
|
||||
clone2_dir, "origin", "master", false, false, None, None,
|
||||
&clone2_dir.into(),
|
||||
"origin",
|
||||
"master",
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@ -220,13 +249,14 @@ mod test {
|
||||
|
||||
//lets fetch from origin
|
||||
|
||||
fetch(clone1_dir, "master", None, None).unwrap();
|
||||
fetch(&clone1_dir.into(), "master", None, None).unwrap();
|
||||
|
||||
merge_upstream_rebase(clone1_dir, "master").unwrap();
|
||||
merge_upstream_rebase(&clone1_dir.into(), "master").unwrap();
|
||||
|
||||
debug_cmd_print(clone1_dir, "git log");
|
||||
debug_cmd_print(&clone1_dir.into(), "git log");
|
||||
|
||||
let state = crate::sync::repo_state(clone1_dir).unwrap();
|
||||
let state =
|
||||
crate::sync::repo_state(&clone1_dir.into()).unwrap();
|
||||
assert_eq!(state, RepoState::Clean);
|
||||
|
||||
let commits = get_commit_msgs(&clone1);
|
||||
@ -258,7 +288,13 @@ mod test {
|
||||
write_commit_file(&clone1, "test.txt", "test", "commit1");
|
||||
|
||||
push(
|
||||
clone1_dir, "origin", "master", false, false, None, None,
|
||||
&clone1_dir.into(),
|
||||
"origin",
|
||||
"master",
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@ -277,7 +313,13 @@ mod test {
|
||||
);
|
||||
|
||||
push(
|
||||
clone2_dir, "origin", "master", false, false, None, None,
|
||||
&clone2_dir.into(),
|
||||
"origin",
|
||||
"master",
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@ -286,20 +328,22 @@ mod test {
|
||||
let _commit3 =
|
||||
write_commit_file(&clone1, "test2.txt", "foo", "commit3");
|
||||
|
||||
let bytes = fetch(clone1_dir, "master", None, None).unwrap();
|
||||
let bytes =
|
||||
fetch(&clone1_dir.into(), "master", None, None).unwrap();
|
||||
assert!(bytes > 0);
|
||||
|
||||
assert_eq!(
|
||||
branch_compare_upstream(clone1_dir, "master")
|
||||
branch_compare_upstream(&clone1_dir.into(), "master")
|
||||
.unwrap()
|
||||
.behind,
|
||||
1
|
||||
);
|
||||
|
||||
let res = merge_upstream_rebase(clone1_dir, "master");
|
||||
let res = merge_upstream_rebase(&clone1_dir.into(), "master");
|
||||
assert!(res.is_err());
|
||||
|
||||
let state = crate::sync::repo_state(clone1_dir).unwrap();
|
||||
let state =
|
||||
crate::sync::repo_state(&clone1_dir.into()).unwrap();
|
||||
|
||||
assert_eq!(state, RepoState::Clean);
|
||||
|
||||
|
@ -5,23 +5,24 @@ pub mod merge_ff;
|
||||
pub mod merge_rebase;
|
||||
pub mod rename;
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use super::{
|
||||
remotes::get_default_remote_in_repo, utils::bytes2string,
|
||||
RepoPath,
|
||||
};
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
sync::{utils, CommitId},
|
||||
sync::{repository::repo, utils::get_head_repo, CommitId},
|
||||
};
|
||||
use git2::{Branch, BranchType, Repository};
|
||||
use scopetime::scope_time;
|
||||
use utils::get_head_repo;
|
||||
use std::collections::HashSet;
|
||||
|
||||
/// returns the branch-name head is currently pointing to
|
||||
/// this might be expensive, see `cached::BranchName`
|
||||
pub(crate) fn get_branch_name(repo_path: &str) -> Result<String> {
|
||||
let repo = utils::repo(repo_path)?;
|
||||
pub(crate) fn get_branch_name(
|
||||
repo_path: &RepoPath,
|
||||
) -> Result<String> {
|
||||
let repo = repo(repo_path)?;
|
||||
|
||||
get_branch_name_repo(&repo)
|
||||
}
|
||||
@ -111,12 +112,12 @@ pub fn validate_branch_name(name: &str) -> Result<bool> {
|
||||
/// returns a list of `BranchInfo` with a simple summary on each branch
|
||||
/// `local` filters for local branches otherwise remote branches will be returned
|
||||
pub fn get_branches_info(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
local: bool,
|
||||
) -> Result<Vec<BranchInfo>> {
|
||||
scope_time!("get_branches_info");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
|
||||
let (filter, remotes_with_tracking) = if local {
|
||||
(BranchType::Local, HashSet::default())
|
||||
@ -214,10 +215,10 @@ pub(crate) fn branch_set_upstream(
|
||||
|
||||
/// returns remote of the upstream tracking branch for `branch`
|
||||
pub fn get_branch_remote(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
branch: &str,
|
||||
) -> Result<Option<String>> {
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
let branch = repo.find_branch(branch, BranchType::Local)?;
|
||||
let reference = bytes2string(branch.get().name_bytes())?;
|
||||
let remote_name = repo.branch_upstream_remote(&reference).ok();
|
||||
@ -229,8 +230,8 @@ pub fn get_branch_remote(
|
||||
}
|
||||
|
||||
/// returns whether the pull merge strategy is set to rebase
|
||||
pub fn config_is_pull_rebase(repo_path: &str) -> Result<bool> {
|
||||
let repo = utils::repo(repo_path)?;
|
||||
pub fn config_is_pull_rebase(repo_path: &RepoPath) -> Result<bool> {
|
||||
let repo = repo(repo_path)?;
|
||||
let config = repo.config()?;
|
||||
|
||||
if let Ok(rebase) = config.get_entry("pull.rebase") {
|
||||
@ -244,12 +245,12 @@ pub fn config_is_pull_rebase(repo_path: &str) -> Result<bool> {
|
||||
|
||||
///
|
||||
pub fn branch_compare_upstream(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
branch: &str,
|
||||
) -> Result<BranchCompare> {
|
||||
scope_time!("branch_compare_upstream");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
|
||||
let branch = repo.find_branch(branch, BranchType::Local)?;
|
||||
|
||||
@ -269,14 +270,14 @@ pub fn branch_compare_upstream(
|
||||
|
||||
/// Modify HEAD to point to a branch then checkout head, does not work if there are uncommitted changes
|
||||
pub fn checkout_branch(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
branch_ref: &str,
|
||||
) -> Result<()> {
|
||||
scope_time!("checkout_branch");
|
||||
|
||||
// This defaults to a safe checkout, so don't delete anything that
|
||||
// hasn't been committed or stashed, in this case it will Err
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
let cur_ref = repo.head()?;
|
||||
let statuses = repo.statuses(Some(
|
||||
git2::StatusOptions::new().include_ignored(false),
|
||||
@ -302,12 +303,12 @@ pub fn checkout_branch(
|
||||
|
||||
///
|
||||
pub fn checkout_remote_branch(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
branch: &BranchInfo,
|
||||
) -> Result<()> {
|
||||
scope_time!("checkout_remote_branch");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
let cur_ref = repo.head()?;
|
||||
|
||||
if !repo
|
||||
@ -345,12 +346,12 @@ pub fn checkout_remote_branch(
|
||||
|
||||
/// The user must not be on the branch for the branch to be deleted
|
||||
pub fn delete_branch(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
branch_ref: &str,
|
||||
) -> Result<()> {
|
||||
scope_time!("delete_branch");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
let branch_as_ref = repo.find_reference(branch_ref)?;
|
||||
let mut branch = git2::Branch::wrap(branch_as_ref);
|
||||
if branch.is_head() {
|
||||
@ -361,10 +362,13 @@ pub fn delete_branch(
|
||||
}
|
||||
|
||||
/// creates a new branch pointing to current HEAD commit and updating HEAD to new branch
|
||||
pub fn create_branch(repo_path: &str, name: &str) -> Result<String> {
|
||||
pub fn create_branch(
|
||||
repo_path: &RepoPath,
|
||||
name: &str,
|
||||
) -> Result<String> {
|
||||
scope_time!("create_branch");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
|
||||
let head_id = get_head_repo(&repo)?;
|
||||
let head_commit = repo.find_commit(head_id.into())?;
|
||||
@ -386,7 +390,8 @@ mod tests_branch_name {
|
||||
fn test_smoke() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
assert_eq!(
|
||||
get_branch_name(repo_path).unwrap().as_str(),
|
||||
@ -398,7 +403,8 @@ mod tests_branch_name {
|
||||
fn test_empty_repo() {
|
||||
let (_td, repo) = repo_init_empty().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
assert!(matches!(
|
||||
get_branch_name(repo_path),
|
||||
@ -416,7 +422,8 @@ mod tests_create_branch {
|
||||
fn test_smoke() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
create_branch(repo_path, "branch1").unwrap();
|
||||
|
||||
@ -436,7 +443,8 @@ mod tests_branch_compare {
|
||||
fn test_smoke() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
create_branch(repo_path, "test").unwrap();
|
||||
|
||||
@ -462,7 +470,8 @@ mod tests_branches {
|
||||
fn test_smoke() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
assert_eq!(
|
||||
get_branches_info(repo_path, true)
|
||||
@ -478,7 +487,8 @@ mod tests_branches {
|
||||
fn test_multiple() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
create_branch(repo_path, "test").unwrap();
|
||||
|
||||
@ -497,9 +507,18 @@ mod tests_branches {
|
||||
let dir = dir.path().to_str().unwrap();
|
||||
|
||||
write_commit_file(&repo, "f1.txt", "foo", "c1");
|
||||
rename_branch(dir, "refs/heads/master", branch_name).unwrap();
|
||||
push(dir, "origin", branch_name, false, false, None, None)
|
||||
rename_branch(&dir.into(), "refs/heads/master", branch_name)
|
||||
.unwrap();
|
||||
push(
|
||||
&dir.into(),
|
||||
"origin",
|
||||
branch_name,
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -516,7 +535,8 @@ mod tests_branches {
|
||||
clone_branch_commit_push(r2_path, "r2branch");
|
||||
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
//add the remotes
|
||||
repo.remote("r1", r1_path).unwrap();
|
||||
@ -588,7 +608,8 @@ mod tests_branches {
|
||||
fn test_branch_remote_no_upstream() {
|
||||
let (_r, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
assert_eq!(
|
||||
get_branch_remote(repo_path, "master").unwrap(),
|
||||
@ -600,7 +621,8 @@ mod tests_branches {
|
||||
fn test_branch_remote_no_branch() {
|
||||
let (_r, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
assert!(get_branch_remote(repo_path, "foo").is_err());
|
||||
}
|
||||
@ -615,7 +637,8 @@ mod tests_checkout {
|
||||
fn test_smoke() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
assert!(
|
||||
checkout_branch(repo_path, "refs/heads/master").is_ok()
|
||||
@ -629,7 +652,8 @@ mod tests_checkout {
|
||||
fn test_multiple() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
create_branch(repo_path, "test").unwrap();
|
||||
|
||||
@ -650,7 +674,8 @@ mod test_delete_branch {
|
||||
fn test_delete_branch() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
create_branch(repo_path, "branch1").unwrap();
|
||||
create_branch(repo_path, "branch2").unwrap();
|
||||
@ -720,16 +745,30 @@ mod test_remote_branches {
|
||||
write_commit_file(&clone1, "test.txt", "test", "commit1");
|
||||
|
||||
push(
|
||||
clone1_dir, "origin", "master", false, false, None, None,
|
||||
&clone1_dir.into(),
|
||||
"origin",
|
||||
"master",
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
create_branch(clone1_dir, "foo").unwrap();
|
||||
create_branch(&clone1_dir.into(), "foo").unwrap();
|
||||
|
||||
write_commit_file(&clone1, "test.txt", "test2", "commit2");
|
||||
|
||||
push(clone1_dir, "origin", "foo", false, false, None, None)
|
||||
.unwrap();
|
||||
push(
|
||||
&clone1_dir.into(),
|
||||
"origin",
|
||||
"foo",
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// clone2
|
||||
|
||||
@ -739,11 +778,12 @@ mod test_remote_branches {
|
||||
let clone2_dir = clone2_dir.path().to_str().unwrap();
|
||||
|
||||
let local_branches =
|
||||
get_branches_info(clone2_dir, true).unwrap();
|
||||
get_branches_info(&clone2_dir.into(), true).unwrap();
|
||||
|
||||
assert_eq!(local_branches.len(), 1);
|
||||
|
||||
let branches = get_branches_info(clone2_dir, false).unwrap();
|
||||
let branches =
|
||||
get_branches_info(&clone2_dir.into(), false).unwrap();
|
||||
assert_eq!(dbg!(&branches).len(), 3);
|
||||
assert_eq!(&branches[0].name, "origin/HEAD");
|
||||
assert_eq!(&branches[1].name, "origin/foo");
|
||||
@ -762,13 +802,27 @@ mod test_remote_branches {
|
||||
|
||||
write_commit_file(&clone1, "test.txt", "test", "commit1");
|
||||
push(
|
||||
clone1_dir, "origin", "master", false, false, None, None,
|
||||
&clone1_dir.into(),
|
||||
"origin",
|
||||
"master",
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
create_branch(clone1_dir, "foo").unwrap();
|
||||
create_branch(&clone1_dir.into(), "foo").unwrap();
|
||||
write_commit_file(&clone1, "test.txt", "test2", "commit2");
|
||||
push(clone1_dir, "origin", "foo", false, false, None, None)
|
||||
.unwrap();
|
||||
push(
|
||||
&clone1_dir.into(),
|
||||
"origin",
|
||||
"foo",
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// clone2
|
||||
|
||||
@ -778,21 +832,28 @@ mod test_remote_branches {
|
||||
let clone2_dir = clone2_dir.path().to_str().unwrap();
|
||||
|
||||
let local_branches =
|
||||
get_branches_info(clone2_dir, true).unwrap();
|
||||
get_branches_info(&clone2_dir.into(), true).unwrap();
|
||||
|
||||
assert_eq!(local_branches.len(), 1);
|
||||
|
||||
let branches = get_branches_info(clone2_dir, false).unwrap();
|
||||
let branches =
|
||||
get_branches_info(&clone2_dir.into(), false).unwrap();
|
||||
|
||||
// checkout origin/foo
|
||||
checkout_remote_branch(clone2_dir, &branches[1]).unwrap();
|
||||
checkout_remote_branch(&clone2_dir.into(), &branches[1])
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
get_branches_info(clone2_dir, true).unwrap().len(),
|
||||
get_branches_info(&clone2_dir.into(), true)
|
||||
.unwrap()
|
||||
.len(),
|
||||
2
|
||||
);
|
||||
|
||||
assert_eq!(&get_branch_name(clone2_dir).unwrap(), "foo");
|
||||
assert_eq!(
|
||||
&get_branch_name(&clone2_dir.into()).unwrap(),
|
||||
"foo"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -809,13 +870,19 @@ mod test_remote_branches {
|
||||
|
||||
write_commit_file(&clone1, "test.txt", "test", "commit1");
|
||||
push(
|
||||
clone1_dir, "origin", "master", false, false, None, None,
|
||||
&clone1_dir.into(),
|
||||
"origin",
|
||||
"master",
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
create_branch(clone1_dir, branch_name).unwrap();
|
||||
create_branch(&clone1_dir.into(), branch_name).unwrap();
|
||||
write_commit_file(&clone1, "test.txt", "test2", "commit2");
|
||||
push(
|
||||
clone1_dir,
|
||||
&clone1_dir.into(),
|
||||
"origin",
|
||||
branch_name,
|
||||
false,
|
||||
@ -831,12 +898,14 @@ mod test_remote_branches {
|
||||
repo_clone(r1_dir.path().to_str().unwrap()).unwrap();
|
||||
let clone2_dir = clone2_dir.path().to_str().unwrap();
|
||||
|
||||
let branches = get_branches_info(clone2_dir, false).unwrap();
|
||||
let branches =
|
||||
get_branches_info(&clone2_dir.into(), false).unwrap();
|
||||
|
||||
checkout_remote_branch(clone2_dir, &branches[1]).unwrap();
|
||||
checkout_remote_branch(&clone2_dir.into(), &branches[1])
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
&get_branch_name(clone2_dir).unwrap(),
|
||||
&get_branch_name(&clone2_dir.into()).unwrap(),
|
||||
branch_name
|
||||
);
|
||||
}
|
||||
@ -853,16 +922,30 @@ mod test_remote_branches {
|
||||
|
||||
write_commit_file(&clone1, "test.txt", "test", "commit1");
|
||||
push(
|
||||
clone1_dir, "origin", "master", false, false, None, None,
|
||||
&clone1_dir.into(),
|
||||
"origin",
|
||||
"master",
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
create_branch(clone1_dir, "foo").unwrap();
|
||||
create_branch(&clone1_dir.into(), "foo").unwrap();
|
||||
write_commit_file(&clone1, "test.txt", "test2", "commit2");
|
||||
push(clone1_dir, "origin", "foo", false, false, None, None)
|
||||
.unwrap();
|
||||
push(
|
||||
&clone1_dir.into(),
|
||||
"origin",
|
||||
"foo",
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let branches_1 =
|
||||
get_branches_info(clone1_dir, false).unwrap();
|
||||
get_branches_info(&clone1_dir.into(), false).unwrap();
|
||||
|
||||
assert!(branches_1[0].remote_details().unwrap().has_tracking);
|
||||
assert!(branches_1[1].remote_details().unwrap().has_tracking);
|
||||
@ -875,7 +958,7 @@ mod test_remote_branches {
|
||||
let clone2_dir = clone2_dir.path().to_str().unwrap();
|
||||
|
||||
let branches_2 =
|
||||
get_branches_info(clone2_dir, false).unwrap();
|
||||
get_branches_info(&clone2_dir.into(), false).unwrap();
|
||||
|
||||
assert!(
|
||||
!branches_2[0].remote_details().unwrap().has_tracking
|
||||
|
@ -1,17 +1,20 @@
|
||||
//! renaming of branches
|
||||
|
||||
use crate::{error::Result, sync::utils};
|
||||
use crate::{
|
||||
error::Result,
|
||||
sync::{repository::repo, RepoPath},
|
||||
};
|
||||
use scopetime::scope_time;
|
||||
|
||||
/// Rename the branch reference
|
||||
pub fn rename_branch(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
branch_ref: &str,
|
||||
new_name: &str,
|
||||
) -> Result<()> {
|
||||
scope_time!("delete_branch");
|
||||
scope_time!("rename_branch");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
let branch_as_ref = repo.find_reference(branch_ref)?;
|
||||
let mut branch = git2::Branch::wrap(branch_as_ref);
|
||||
branch.rename(new_name, true)?;
|
||||
@ -29,7 +32,8 @@ mod test {
|
||||
fn test_rename_branch() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
create_branch(repo_path, "branch1").unwrap();
|
||||
|
||||
|
@ -1,11 +1,14 @@
|
||||
use super::{utils::repo, CommitId};
|
||||
use crate::{error::Result, sync::utils::get_head_repo};
|
||||
use super::{CommitId, RepoPath};
|
||||
use crate::{
|
||||
error::Result,
|
||||
sync::{repository::repo, utils::get_head_repo},
|
||||
};
|
||||
use git2::{ErrorCode, ObjectType, Repository, Signature};
|
||||
use scopetime::scope_time;
|
||||
|
||||
///
|
||||
pub fn amend(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
id: CommitId,
|
||||
msg: &str,
|
||||
) -> Result<CommitId> {
|
||||
@ -58,7 +61,7 @@ pub(crate) fn signature_allow_undefined_name(
|
||||
}
|
||||
|
||||
/// this does not run any git hooks
|
||||
pub fn commit(repo_path: &str, msg: &str) -> Result<CommitId> {
|
||||
pub fn commit(repo_path: &RepoPath, msg: &str) -> Result<CommitId> {
|
||||
scope_time!("commit");
|
||||
|
||||
let repo = repo(repo_path)?;
|
||||
@ -93,7 +96,7 @@ pub fn commit(repo_path: &str, msg: &str) -> Result<CommitId> {
|
||||
/// This function will return an `Err(…)` variant if the tag’s name is refused
|
||||
/// by git or if the tag already exists.
|
||||
pub fn tag(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
commit_id: &CommitId,
|
||||
tag: &str,
|
||||
) -> Result<CommitId> {
|
||||
@ -113,6 +116,7 @@ pub fn tag(
|
||||
mod tests {
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::sync::RepoPath;
|
||||
use crate::sync::{
|
||||
commit, get_commit_details, get_commit_files, stage_add_file,
|
||||
tags::get_tags,
|
||||
@ -136,7 +140,8 @@ mod tests {
|
||||
let file_path = Path::new("foo");
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path))
|
||||
.unwrap()
|
||||
@ -159,7 +164,8 @@ mod tests {
|
||||
let file_path = Path::new("foo");
|
||||
let (_td, repo) = repo_init_empty().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
assert_eq!(get_statuses(repo_path), (0, 0));
|
||||
|
||||
@ -185,7 +191,8 @@ mod tests {
|
||||
let file_path2 = Path::new("foo2");
|
||||
let (_td, repo) = repo_init_empty()?;
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path1))?.write_all(b"test1")?;
|
||||
|
||||
@ -221,7 +228,8 @@ mod tests {
|
||||
let file_path = Path::new("foo");
|
||||
let (_td, repo) = repo_init_empty().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path))?
|
||||
.write_all(b"test\nfoo")?;
|
||||
@ -265,7 +273,8 @@ mod tests {
|
||||
let file_path = Path::new("foo");
|
||||
let (_td, repo) = repo_init_empty().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path))?
|
||||
.write_all(b"test\nfoo")?;
|
||||
@ -300,7 +309,8 @@ mod tests {
|
||||
let file_path = Path::new("foo");
|
||||
let (_td, repo) = repo_init_empty().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path))?
|
||||
.write_all(b"test\nfoo")?;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::{commits_info::get_message, utils::repo, CommitId};
|
||||
use crate::error::Result;
|
||||
use super::{commits_info::get_message, CommitId, RepoPath};
|
||||
use crate::{error::Result, sync::repository::repo};
|
||||
use git2::Signature;
|
||||
use scopetime::scope_time;
|
||||
|
||||
@ -89,7 +89,7 @@ impl CommitDetails {
|
||||
|
||||
///
|
||||
pub fn get_commit_details(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
id: CommitId,
|
||||
) -> Result<CommitDetails> {
|
||||
scope_time!("get_commit_details");
|
||||
@ -121,11 +121,12 @@ pub fn get_commit_details(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::{get_commit_details, CommitMessage};
|
||||
use crate::error::Result;
|
||||
use crate::sync::{
|
||||
commit, stage_add_file, tests::repo_init_empty,
|
||||
use crate::{
|
||||
error::Result,
|
||||
sync::{
|
||||
commit, stage_add_file, tests::repo_init_empty, RepoPath,
|
||||
},
|
||||
};
|
||||
use std::{fs::File, io::Write, path::Path};
|
||||
|
||||
@ -134,7 +135,8 @@ mod tests {
|
||||
let file_path = Path::new("foo");
|
||||
let (_td, repo) = repo_init_empty().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path))?.write_all(b"a")?;
|
||||
stage_add_file(repo_path, file_path).unwrap();
|
||||
@ -144,7 +146,6 @@ mod tests {
|
||||
|
||||
let res = get_commit_details(repo_path, id).unwrap();
|
||||
|
||||
dbg!(&res.message.as_ref().unwrap().subject);
|
||||
assert_eq!(
|
||||
res.message
|
||||
.as_ref()
|
||||
|
@ -1,15 +1,15 @@
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use super::{stash::is_stash_commit, utils::repo, CommitId};
|
||||
use super::{stash::is_stash_commit, CommitId, RepoPath};
|
||||
use crate::{
|
||||
error::Error, error::Result, StatusItem, StatusItemType,
|
||||
error::Result, sync::repository::repo, StatusItem, StatusItemType,
|
||||
};
|
||||
use git2::{Diff, DiffOptions, Repository};
|
||||
use scopetime::scope_time;
|
||||
|
||||
/// get all files that are part of a commit
|
||||
pub fn get_commit_files(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
id: CommitId,
|
||||
other: Option<CommitId>,
|
||||
) -> Result<Vec<StatusItem>> {
|
||||
@ -20,7 +20,7 @@ pub fn get_commit_files(
|
||||
let diff = if let Some(other) = other {
|
||||
get_compare_commits_diff(&repo, (id, other), None)?
|
||||
} else {
|
||||
get_commit_diff(&repo, id, None)?
|
||||
get_commit_diff(repo_path, &repo, id, None)?
|
||||
};
|
||||
|
||||
let res = diff
|
||||
@ -81,11 +81,12 @@ pub fn get_compare_commits_diff(
|
||||
}
|
||||
|
||||
#[allow(clippy::redundant_pub_crate)]
|
||||
pub(crate) fn get_commit_diff(
|
||||
repo: &Repository,
|
||||
pub(crate) fn get_commit_diff<'a>(
|
||||
repo_path: &RepoPath,
|
||||
repo: &'a Repository,
|
||||
id: CommitId,
|
||||
pathspec: Option<String>,
|
||||
) -> Result<Diff<'_>> {
|
||||
) -> Result<Diff<'a>> {
|
||||
// scope_time!("get_commit_diff");
|
||||
|
||||
let commit = repo.find_commit(id.into())?;
|
||||
@ -111,15 +112,10 @@ pub(crate) fn get_commit_diff(
|
||||
Some(&mut opts),
|
||||
)?;
|
||||
|
||||
if is_stash_commit(
|
||||
repo.path().to_str().map_or_else(
|
||||
|| Err(Error::Generic("repo path utf8 err".to_owned())),
|
||||
Ok,
|
||||
)?,
|
||||
&id,
|
||||
)? {
|
||||
if is_stash_commit(repo_path, &id)? {
|
||||
if let Ok(untracked_commit) = commit.parent_id(2) {
|
||||
let untracked_diff = get_commit_diff(
|
||||
repo_path,
|
||||
repo,
|
||||
CommitId::new(untracked_commit),
|
||||
pathspec,
|
||||
@ -140,6 +136,7 @@ mod tests {
|
||||
sync::{
|
||||
commit, stage_add_file, stash_save,
|
||||
tests::{get_statuses, repo_init},
|
||||
RepoPath,
|
||||
},
|
||||
StatusItemType,
|
||||
};
|
||||
@ -150,7 +147,8 @@ mod tests {
|
||||
let file_path = Path::new("file1.txt");
|
||||
let (_td, repo) = repo_init()?;
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path))?
|
||||
.write_all(b"test file1 content")?;
|
||||
@ -172,7 +170,8 @@ mod tests {
|
||||
let file_path = Path::new("file1.txt");
|
||||
let (_td, repo) = repo_init()?;
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path))?
|
||||
.write_all(b"test file1 content")?;
|
||||
@ -193,7 +192,8 @@ mod tests {
|
||||
let file_path2 = Path::new("file2.txt");
|
||||
let (_td, repo) = repo_init()?;
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path1))?.write_all(b"test")?;
|
||||
stage_add_file(repo_path, file_path1)?;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::utils::repo;
|
||||
use crate::error::Result;
|
||||
use super::RepoPath;
|
||||
use crate::{error::Result, sync::repository::repo};
|
||||
use git2::{Commit, Error, Oid};
|
||||
use scopetime::scope_time;
|
||||
use unicode_truncate::UnicodeTruncateStr;
|
||||
@ -62,7 +62,7 @@ pub struct CommitInfo {
|
||||
|
||||
///
|
||||
pub fn get_commits_info(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
ids: &[CommitId],
|
||||
message_length_limit: usize,
|
||||
) -> Result<Vec<CommitInfo>> {
|
||||
@ -97,7 +97,7 @@ pub fn get_commits_info(
|
||||
|
||||
///
|
||||
pub fn get_commit_info(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
commit_id: &CommitId,
|
||||
) -> Result<CommitInfo> {
|
||||
scope_time!("get_commit_info");
|
||||
@ -136,10 +136,12 @@ pub fn get_message(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::get_commits_info;
|
||||
use crate::error::Result;
|
||||
use crate::sync::{
|
||||
commit, stage_add_file, tests::repo_init_empty,
|
||||
utils::get_head_repo,
|
||||
use crate::{
|
||||
error::Result,
|
||||
sync::{
|
||||
commit, stage_add_file, tests::repo_init_empty,
|
||||
utils::get_head_repo, RepoPath,
|
||||
},
|
||||
};
|
||||
use std::{fs::File, io::Write, path::Path};
|
||||
|
||||
@ -148,7 +150,8 @@ mod tests {
|
||||
let file_path = Path::new("foo");
|
||||
let (_td, repo) = repo_init_empty().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path))?.write_all(b"a")?;
|
||||
stage_add_file(repo_path, file_path).unwrap();
|
||||
@ -173,7 +176,8 @@ mod tests {
|
||||
let file_path = Path::new("foo");
|
||||
let (_td, repo) = repo_init_empty().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path))?.write_all(b"a")?;
|
||||
stage_add_file(repo_path, file_path).unwrap();
|
||||
@ -192,7 +196,8 @@ mod tests {
|
||||
let file_path = Path::new("foo");
|
||||
let (_td, repo) = repo_init_empty().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path))?.write_all(b"a")?;
|
||||
stage_add_file(repo_path, file_path).unwrap();
|
||||
|
@ -1,8 +1,9 @@
|
||||
use super::utils::repo;
|
||||
use crate::error::Result;
|
||||
use git2::Repository;
|
||||
use scopetime::scope_time;
|
||||
|
||||
use super::{repository::repo, RepoPath};
|
||||
|
||||
// see https://git-scm.com/docs/git-config#Documentation/git-config.txt-statusshowUntrackedFiles
|
||||
/// represents the `status.showUntrackedFiles` git config state
|
||||
#[derive(Hash, Copy, Clone, PartialEq)]
|
||||
@ -57,7 +58,7 @@ pub fn untracked_files_config_repo(
|
||||
|
||||
///
|
||||
pub fn untracked_files_config(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
) -> Result<ShowUntrackedFilesConfig> {
|
||||
let repo = repo(repo_path)?;
|
||||
untracked_files_config_repo(&repo)
|
||||
@ -65,7 +66,7 @@ pub fn untracked_files_config(
|
||||
|
||||
/// get string from config
|
||||
pub fn get_config_string(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
key: &str,
|
||||
) -> Result<Option<String>> {
|
||||
let repo = repo(repo_path)?;
|
||||
@ -103,18 +104,21 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_get_config() {
|
||||
let bad_dir_cfg =
|
||||
get_config_string("oodly_noodly", "this.doesnt.exist");
|
||||
let bad_dir_cfg = get_config_string(
|
||||
&"oodly_noodly".into(),
|
||||
"this.doesnt.exist",
|
||||
);
|
||||
assert!(bad_dir_cfg.is_err());
|
||||
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let path = repo.path();
|
||||
let rpath = path.as_os_str().to_str().unwrap();
|
||||
let bad_cfg = get_config_string(rpath, "this.doesnt.exist");
|
||||
let bad_cfg =
|
||||
get_config_string(&rpath.into(), "this.doesnt.exist");
|
||||
assert!(bad_cfg.is_ok());
|
||||
assert!(bad_cfg.unwrap().is_none());
|
||||
// repo init sets user.name
|
||||
let good_cfg = get_config_string(rpath, "user.name");
|
||||
let good_cfg = get_config_string(&rpath.into(), "user.name");
|
||||
assert!(good_cfg.is_ok());
|
||||
assert!(good_cfg.unwrap().is_some());
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
//! credentials git helper
|
||||
|
||||
use super::remotes::get_default_remote_in_repo;
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
CWD,
|
||||
use super::{
|
||||
remotes::get_default_remote_in_repo, repository::repo, RepoPath,
|
||||
};
|
||||
use crate::error::{Error, Result};
|
||||
use git2::{Config, CredentialHelper};
|
||||
|
||||
/// basic Authentication Credentials
|
||||
@ -31,8 +30,8 @@ impl BasicAuthCredential {
|
||||
}
|
||||
|
||||
/// know if username and password are needed for this url
|
||||
pub fn need_username_password() -> Result<bool> {
|
||||
let repo = crate::sync::utils::repo(CWD)?;
|
||||
pub fn need_username_password(repo_path: &RepoPath) -> Result<bool> {
|
||||
let repo = repo(repo_path)?;
|
||||
let url = repo
|
||||
.find_remote(&get_default_remote_in_repo(&repo)?)?
|
||||
.url()
|
||||
@ -43,8 +42,10 @@ pub fn need_username_password() -> Result<bool> {
|
||||
}
|
||||
|
||||
/// extract username and password
|
||||
pub fn extract_username_password() -> Result<BasicAuthCredential> {
|
||||
let repo = crate::sync::utils::repo(CWD)?;
|
||||
pub fn extract_username_password(
|
||||
repo_path: &RepoPath,
|
||||
) -> Result<BasicAuthCredential> {
|
||||
let repo = repo(repo_path)?;
|
||||
let url = repo
|
||||
.find_remote(&get_default_remote_in_repo(&repo)?)?
|
||||
.url()
|
||||
@ -88,9 +89,9 @@ mod tests {
|
||||
},
|
||||
remotes::DEFAULT_REMOTE_NAME,
|
||||
tests::repo_init,
|
||||
RepoPath,
|
||||
};
|
||||
use serial_test::serial;
|
||||
use std::env;
|
||||
|
||||
#[test]
|
||||
fn test_credential_complete() {
|
||||
@ -160,13 +161,15 @@ mod tests {
|
||||
fn test_need_username_password_if_https() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
env::set_current_dir(repo_path).unwrap();
|
||||
//TODO:
|
||||
// env::set_current_dir(repo_path).unwrap();
|
||||
repo.remote(DEFAULT_REMOTE_NAME, "http://user@github.com")
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(need_username_password().unwrap(), true);
|
||||
assert_eq!(need_username_password(repo_path).unwrap(), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -174,13 +177,15 @@ mod tests {
|
||||
fn test_dont_need_username_password_if_ssh() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
env::set_current_dir(repo_path).unwrap();
|
||||
//TODO:
|
||||
// env::set_current_dir(repo_path).unwrap();
|
||||
repo.remote(DEFAULT_REMOTE_NAME, "git@github.com:user/repo")
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(need_username_password().unwrap(), false);
|
||||
assert_eq!(need_username_password(repo_path).unwrap(), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -190,11 +195,13 @@ mod tests {
|
||||
) {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
env::set_current_dir(repo_path).unwrap();
|
||||
//TODO:
|
||||
// env::set_current_dir(repo_path).unwrap();
|
||||
|
||||
need_username_password().unwrap();
|
||||
need_username_password(repo_path).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -202,9 +209,11 @@ mod tests {
|
||||
fn test_extract_username_password_from_repo() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
env::set_current_dir(repo_path).unwrap();
|
||||
//TODO:
|
||||
// env::set_current_dir(repo_path).unwrap();
|
||||
repo.remote(
|
||||
DEFAULT_REMOTE_NAME,
|
||||
"http://user:pass@github.com",
|
||||
@ -212,7 +221,7 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
extract_username_password().unwrap(),
|
||||
extract_username_password(repo_path).unwrap(),
|
||||
BasicAuthCredential::new(
|
||||
Some("user".to_owned()),
|
||||
Some("pass".to_owned())
|
||||
@ -225,14 +234,16 @@ mod tests {
|
||||
fn test_extract_username_from_repo() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
env::set_current_dir(repo_path).unwrap();
|
||||
//TODO:
|
||||
// env::set_current_dir(repo_path).unwrap();
|
||||
repo.remote(DEFAULT_REMOTE_NAME, "http://user@github.com")
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
extract_username_password().unwrap(),
|
||||
extract_username_password(repo_path).unwrap(),
|
||||
BasicAuthCredential::new(Some("user".to_owned()), None)
|
||||
);
|
||||
}
|
||||
@ -244,10 +255,12 @@ mod tests {
|
||||
) {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
env::set_current_dir(repo_path).unwrap();
|
||||
//TODO: not needed anymore?
|
||||
// env::set_current_dir(repo_path).unwrap();
|
||||
|
||||
extract_username_password().unwrap();
|
||||
extract_username_password(repo_path).unwrap();
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,12 @@
|
||||
|
||||
use super::{
|
||||
commit_files::{get_commit_diff, get_compare_commits_diff},
|
||||
utils::{self, get_head_repo, work_dir},
|
||||
CommitId,
|
||||
utils::{get_head_repo, work_dir},
|
||||
CommitId, RepoPath,
|
||||
};
|
||||
use crate::{
|
||||
error::Error, error::Result, hash, sync::repository::repo,
|
||||
};
|
||||
use crate::{error::Error, error::Result, hash};
|
||||
use easy_cast::Conv;
|
||||
use git2::{
|
||||
Delta, Diff, DiffDelta, DiffFormat, DiffHunk, Patch, Repository,
|
||||
@ -192,14 +194,14 @@ pub(crate) fn get_diff_raw<'a>(
|
||||
|
||||
/// returns diff of a specific file either in `stage` or workdir
|
||||
pub fn get_diff(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
p: &str,
|
||||
stage: bool,
|
||||
options: Option<DiffOptions>,
|
||||
) -> Result<FileDiff> {
|
||||
scope_time!("get_diff");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
let work_dir = work_dir(&repo)?;
|
||||
let diff = get_diff_raw(&repo, p, stage, false, options)?;
|
||||
|
||||
@ -209,28 +211,28 @@ pub fn get_diff(
|
||||
/// returns diff of a specific file inside a commit
|
||||
/// see `get_commit_diff`
|
||||
pub fn get_diff_commit(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
id: CommitId,
|
||||
p: String,
|
||||
) -> Result<FileDiff> {
|
||||
scope_time!("get_diff_commit");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
let work_dir = work_dir(&repo)?;
|
||||
let diff = get_commit_diff(&repo, id, Some(p))?;
|
||||
let diff = get_commit_diff(repo_path, &repo, id, Some(p))?;
|
||||
|
||||
raw_diff_to_file_diff(&diff, work_dir)
|
||||
}
|
||||
|
||||
/// get file changes of a diff between two commits
|
||||
pub fn get_diff_commits(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
ids: (CommitId, CommitId),
|
||||
p: String,
|
||||
) -> Result<FileDiff> {
|
||||
scope_time!("get_diff_commits");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
let work_dir = work_dir(&repo)?;
|
||||
let diff =
|
||||
get_compare_commits_diff(&repo, (ids.0, ids.1), Some(p))?;
|
||||
@ -403,11 +405,14 @@ fn new_file_content(path: &Path) -> Option<Vec<u8>> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{get_diff, get_diff_commit};
|
||||
use crate::error::Result;
|
||||
use crate::sync::{
|
||||
commit, stage_add_file,
|
||||
status::{get_status, StatusType},
|
||||
tests::{get_statuses, repo_init, repo_init_empty},
|
||||
use crate::{
|
||||
error::Result,
|
||||
sync::{
|
||||
commit, stage_add_file,
|
||||
status::{get_status, StatusType},
|
||||
tests::{get_statuses, repo_init, repo_init_empty},
|
||||
RepoPath,
|
||||
},
|
||||
};
|
||||
use std::{
|
||||
fs::{self, File},
|
||||
@ -419,7 +424,8 @@ mod tests {
|
||||
fn test_untracked_subfolder() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
assert_eq!(get_statuses(repo_path), (0, 0));
|
||||
|
||||
@ -443,7 +449,8 @@ mod tests {
|
||||
let file_path = Path::new("foo.txt");
|
||||
let (_td, repo) = repo_init_empty().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
assert_eq!(get_statuses(repo_path), (0, 0));
|
||||
|
||||
@ -499,7 +506,8 @@ mod tests {
|
||||
fn test_hunks() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
assert_eq!(get_statuses(repo_path), (0, 0));
|
||||
|
||||
@ -551,7 +559,7 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
let diff = get_diff(
|
||||
sub_path.to_str().unwrap(),
|
||||
&sub_path.to_str().unwrap().into(),
|
||||
file_path.to_str().unwrap(),
|
||||
false,
|
||||
None,
|
||||
@ -566,7 +574,8 @@ mod tests {
|
||||
let file_path = Path::new("bar");
|
||||
let (_td, repo) = repo_init_empty().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path))?.write_all(b"\x00")?;
|
||||
|
||||
@ -597,7 +606,8 @@ mod tests {
|
||||
let file_path = Path::new("bar");
|
||||
let (_td, repo) = repo_init_empty().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path))?
|
||||
.write_all(b"\x00\xc7")?;
|
||||
@ -622,7 +632,8 @@ mod tests {
|
||||
let file_path = Path::new("bar");
|
||||
let (_td, repo) = repo_init_empty().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path))?.write_all(b"\x00")?;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::utils::{repo, work_dir};
|
||||
use super::{repository::repo, utils::work_dir, RepoPath};
|
||||
use crate::error::{Error, Result};
|
||||
use scopetime::scope_time;
|
||||
use std::{
|
||||
@ -18,7 +18,7 @@ const HOOK_COMMIT_MSG_TEMP_FILE: &str = ".git/COMMIT_EDITMSG";
|
||||
/// the commit message at `.git/COMMIT_EDITMSG` and pass it's relative path as the only
|
||||
/// parameter to the hook script.
|
||||
pub fn hooks_commit_msg(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
msg: &mut String,
|
||||
) -> Result<HookResult> {
|
||||
scope_time!("hooks_commit_msg");
|
||||
@ -48,7 +48,7 @@ pub fn hooks_commit_msg(
|
||||
|
||||
/// this hook is documented here <https://git-scm.com/docs/githooks#_pre_commit>
|
||||
///
|
||||
pub fn hooks_pre_commit(repo_path: &str) -> Result<HookResult> {
|
||||
pub fn hooks_pre_commit(repo_path: &RepoPath) -> Result<HookResult> {
|
||||
scope_time!("hooks_pre_commit");
|
||||
|
||||
let work_dir = work_dir_as_string(repo_path)?;
|
||||
@ -60,7 +60,7 @@ pub fn hooks_pre_commit(repo_path: &str) -> Result<HookResult> {
|
||||
}
|
||||
}
|
||||
///
|
||||
pub fn hooks_post_commit(repo_path: &str) -> Result<HookResult> {
|
||||
pub fn hooks_post_commit(repo_path: &RepoPath) -> Result<HookResult> {
|
||||
scope_time!("hooks_post_commit");
|
||||
|
||||
let work_dir = work_dir_as_string(repo_path)?;
|
||||
@ -73,7 +73,7 @@ pub fn hooks_post_commit(repo_path: &str) -> Result<HookResult> {
|
||||
}
|
||||
}
|
||||
|
||||
fn work_dir_as_string(repo_path: &str) -> Result<String> {
|
||||
fn work_dir_as_string(repo_path: &RepoPath) -> Result<String> {
|
||||
let repo = repo(repo_path)?;
|
||||
work_dir(&repo)?
|
||||
.to_str()
|
||||
@ -163,7 +163,8 @@ mod tests {
|
||||
fn test_smoke() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
let mut msg = String::from("test");
|
||||
let res = hooks_commit_msg(repo_path, &mut msg).unwrap();
|
||||
@ -195,7 +196,8 @@ mod tests {
|
||||
fn test_hooks_commit_msg_ok() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
let hook = b"#!/bin/sh
|
||||
exit 0
|
||||
@ -215,7 +217,8 @@ exit 0
|
||||
fn test_pre_commit_sh() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
let hook = b"#!/bin/sh
|
||||
exit 0
|
||||
@ -230,7 +233,8 @@ exit 0
|
||||
fn test_pre_commit_fail_sh() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
let hook = b"#!/bin/sh
|
||||
echo 'rejected'
|
||||
@ -246,7 +250,8 @@ exit 1
|
||||
fn test_pre_commit_py() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
// mirror how python pre-commmit sets itself up
|
||||
#[cfg(not(windows))]
|
||||
@ -269,7 +274,8 @@ sys.exit(0)
|
||||
fn test_pre_commit_fail_py() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
// mirror how python pre-commmit sets itself up
|
||||
#[cfg(not(windows))]
|
||||
@ -292,7 +298,8 @@ sys.exit(1)
|
||||
fn test_hooks_commit_msg_reject() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
let hook = b"#!/bin/sh
|
||||
echo 'msg' > $1
|
||||
@ -331,9 +338,11 @@ exit 1
|
||||
fs::create_dir_all(&subfolder).unwrap();
|
||||
|
||||
let mut msg = String::from("test");
|
||||
let res =
|
||||
hooks_commit_msg(subfolder.to_str().unwrap(), &mut msg)
|
||||
.unwrap();
|
||||
let res = hooks_commit_msg(
|
||||
&subfolder.to_str().unwrap().into(),
|
||||
&mut msg,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
res,
|
||||
@ -347,7 +356,8 @@ exit 1
|
||||
fn test_commit_msg_no_block_but_alter() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
let hook = b"#!/bin/sh
|
||||
echo 'msg' > $1
|
||||
@ -379,7 +389,8 @@ exit 1
|
||||
fs::create_dir_all(&subfolder).unwrap();
|
||||
|
||||
let res =
|
||||
hooks_post_commit(subfolder.to_str().unwrap()).unwrap();
|
||||
hooks_post_commit(&subfolder.to_str().unwrap().into())
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
res,
|
||||
|
@ -1,17 +1,18 @@
|
||||
use super::{
|
||||
diff::{get_diff_raw, HunkHeader},
|
||||
utils::repo,
|
||||
RepoPath,
|
||||
};
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
hash,
|
||||
sync::repository::repo,
|
||||
};
|
||||
use git2::{ApplyLocation, ApplyOptions, Diff};
|
||||
use scopetime::scope_time;
|
||||
|
||||
///
|
||||
pub fn stage_hunk(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
file_path: &str,
|
||||
hunk_hash: u64,
|
||||
) -> Result<()> {
|
||||
@ -36,7 +37,7 @@ pub fn stage_hunk(
|
||||
|
||||
/// this will fail for an all untracked file
|
||||
pub fn reset_hunk(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
file_path: &str,
|
||||
hunk_hash: u64,
|
||||
) -> Result<()> {
|
||||
@ -94,7 +95,7 @@ fn find_hunk_index(diff: &Diff, hunk_hash: u64) -> Option<usize> {
|
||||
|
||||
///
|
||||
pub fn unstage_hunk(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
file_path: &str,
|
||||
hunk_hash: u64,
|
||||
) -> Result<bool> {
|
||||
@ -162,15 +163,16 @@ mod tests {
|
||||
let file_path = Path::new("foo/foo.txt");
|
||||
let (_td, repo) = repo_init_empty()?;
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
let sub_path = root.join("foo/");
|
||||
|
||||
fs::create_dir_all(&sub_path)?;
|
||||
File::create(&root.join(file_path))?.write_all(b"test")?;
|
||||
|
||||
let sub_path: &RepoPath = &sub_path.to_str().unwrap().into();
|
||||
let diff = get_diff(
|
||||
sub_path.to_str().unwrap(),
|
||||
sub_path,
|
||||
file_path.to_str().unwrap(),
|
||||
false,
|
||||
None,
|
||||
|
@ -1,5 +1,8 @@
|
||||
use super::utils::{repo, work_dir};
|
||||
use crate::error::{Error, Result};
|
||||
use super::{utils::work_dir, RepoPath};
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
sync::repository::repo,
|
||||
};
|
||||
use scopetime::scope_time;
|
||||
use std::{
|
||||
fs::{File, OpenOptions},
|
||||
@ -11,7 +14,7 @@ static GITIGNORE: &str = ".gitignore";
|
||||
|
||||
/// add file or path to root ignore file
|
||||
pub fn add_to_ignore(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
path_to_ignore: &str,
|
||||
) -> Result<()> {
|
||||
scope_time!("add_to_ignore");
|
||||
@ -71,7 +74,8 @@ mod tests {
|
||||
let file_path = Path::new("foo.txt");
|
||||
let (_td, repo) = repo_init()?;
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path))?.write_all(b"test")?;
|
||||
|
||||
@ -98,7 +102,8 @@ mod tests {
|
||||
let file_path = Path::new("foo.txt");
|
||||
let (_td, repo) = repo_init()?;
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path))?.write_all(b"test")?;
|
||||
File::create(&root.join(ignore_file_path))?
|
||||
@ -119,7 +124,8 @@ mod tests {
|
||||
let file_path = Path::new("foo.txt");
|
||||
let (_td, repo) = repo_init()?;
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path))?.write_all(b"test")?;
|
||||
File::create(&root.join(ignore_file_path))?
|
||||
@ -139,7 +145,8 @@ mod tests {
|
||||
let ignore_file_path = Path::new(".gitignore");
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
repo_write_file(&repo, ".gitignore", "#foo").unwrap();
|
||||
|
||||
|
@ -108,6 +108,7 @@ impl<'a> LogWalker<'a> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::error::Result;
|
||||
use crate::sync::RepoPath;
|
||||
use crate::sync::{
|
||||
commit, commit_files::get_commit_diff, get_commits_info,
|
||||
stage_add_file, tests::repo_init_empty,
|
||||
@ -120,7 +121,8 @@ mod tests {
|
||||
let file_path = Path::new("foo");
|
||||
let (_td, repo) = repo_init_empty().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path))?.write_all(b"a")?;
|
||||
stage_add_file(repo_path, file_path).unwrap();
|
||||
@ -144,7 +146,8 @@ mod tests {
|
||||
let file_path = Path::new("foo");
|
||||
let (_td, repo) = repo_init_empty().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path))?.write_all(b"a")?;
|
||||
stage_add_file(repo_path, file_path).unwrap();
|
||||
@ -177,28 +180,31 @@ mod tests {
|
||||
let second_file_path = Path::new("baz");
|
||||
let (_td, repo) = repo_init_empty().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: RepoPath =
|
||||
root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path))?.write_all(b"a")?;
|
||||
stage_add_file(repo_path, file_path).unwrap();
|
||||
stage_add_file(&repo_path, file_path).unwrap();
|
||||
|
||||
let _first_commit_id = commit(repo_path, "commit1").unwrap();
|
||||
let _first_commit_id = commit(&repo_path, "commit1").unwrap();
|
||||
|
||||
File::create(&root.join(second_file_path))?
|
||||
.write_all(b"a")?;
|
||||
stage_add_file(repo_path, second_file_path).unwrap();
|
||||
stage_add_file(&repo_path, second_file_path).unwrap();
|
||||
|
||||
let second_commit_id = commit(repo_path, "commit2").unwrap();
|
||||
let second_commit_id = commit(&repo_path, "commit2").unwrap();
|
||||
|
||||
File::create(&root.join(file_path))?.write_all(b"b")?;
|
||||
stage_add_file(repo_path, file_path).unwrap();
|
||||
stage_add_file(&repo_path, file_path).unwrap();
|
||||
|
||||
let _third_commit_id = commit(repo_path, "commit3").unwrap();
|
||||
let _third_commit_id = commit(&repo_path, "commit3").unwrap();
|
||||
|
||||
let diff_contains_baz = |repo: &Repository,
|
||||
commit_id: &CommitId|
|
||||
-> Result<bool> {
|
||||
let repo_path_clone = repo_path.clone();
|
||||
let diff_contains_baz = move |repo: &Repository,
|
||||
commit_id: &CommitId|
|
||||
-> Result<bool> {
|
||||
let diff = get_commit_diff(
|
||||
&repo_path_clone,
|
||||
&repo,
|
||||
*commit_id,
|
||||
Some("baz".into()),
|
||||
@ -222,10 +228,12 @@ mod tests {
|
||||
|
||||
assert_eq!(items.len(), 0);
|
||||
|
||||
let diff_contains_bar = |repo: &Repository,
|
||||
commit_id: &CommitId|
|
||||
-> Result<bool> {
|
||||
let repo_path_clone = repo_path.clone();
|
||||
let diff_contains_bar = move |repo: &Repository,
|
||||
commit_id: &CommitId|
|
||||
-> Result<bool> {
|
||||
let diff = get_commit_diff(
|
||||
&repo_path_clone,
|
||||
&repo,
|
||||
*commit_id,
|
||||
Some("bar".into()),
|
||||
|
@ -5,19 +5,23 @@ use crate::{
|
||||
rebase::{
|
||||
abort_rebase, continue_rebase, get_rebase_progress,
|
||||
},
|
||||
reset_stage, reset_workdir, utils, CommitId,
|
||||
repository::repo,
|
||||
reset_stage, reset_workdir, CommitId,
|
||||
},
|
||||
};
|
||||
use git2::{BranchType, Commit, MergeOptions, Repository};
|
||||
use scopetime::scope_time;
|
||||
|
||||
use super::rebase::{RebaseProgress, RebaseState};
|
||||
use super::{
|
||||
rebase::{RebaseProgress, RebaseState},
|
||||
RepoPath,
|
||||
};
|
||||
|
||||
///
|
||||
pub fn mergehead_ids(repo_path: &str) -> Result<Vec<CommitId>> {
|
||||
pub fn mergehead_ids(repo_path: &RepoPath) -> Result<Vec<CommitId>> {
|
||||
scope_time!("mergehead_ids");
|
||||
|
||||
let mut repo = utils::repo(repo_path)?;
|
||||
let mut repo = repo(repo_path)?;
|
||||
|
||||
let mut ids: Vec<CommitId> = Vec::new();
|
||||
repo.mergehead_foreach(|id| {
|
||||
@ -32,10 +36,10 @@ pub fn mergehead_ids(repo_path: &str) -> Result<Vec<CommitId>> {
|
||||
/// * reset all staged changes,
|
||||
/// * revert all changes in workdir
|
||||
/// * cleanup repo merge state
|
||||
pub fn abort_merge(repo_path: &str) -> Result<()> {
|
||||
pub fn abort_merge(repo_path: &RepoPath) -> Result<()> {
|
||||
scope_time!("cleanup_state");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
|
||||
reset_stage(repo_path, "*")?;
|
||||
reset_workdir(repo_path, "*")?;
|
||||
@ -47,13 +51,13 @@ pub fn abort_merge(repo_path: &str) -> Result<()> {
|
||||
|
||||
///
|
||||
pub fn merge_branch(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
branch: &str,
|
||||
branch_type: BranchType,
|
||||
) -> Result<()> {
|
||||
scope_time!("merge_branch");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
|
||||
merge_branch_repo(&repo, branch, branch_type)?;
|
||||
|
||||
@ -61,30 +65,32 @@ pub fn merge_branch(
|
||||
}
|
||||
|
||||
///
|
||||
pub fn rebase_progress(repo_path: &str) -> Result<RebaseProgress> {
|
||||
pub fn rebase_progress(
|
||||
repo_path: &RepoPath,
|
||||
) -> Result<RebaseProgress> {
|
||||
scope_time!("rebase_progress");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
|
||||
get_rebase_progress(&repo)
|
||||
}
|
||||
|
||||
///
|
||||
pub fn continue_pending_rebase(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
) -> Result<RebaseState> {
|
||||
scope_time!("continue_pending_rebase");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
|
||||
continue_rebase(&repo)
|
||||
}
|
||||
|
||||
///
|
||||
pub fn abort_pending_rebase(repo_path: &str) -> Result<()> {
|
||||
pub fn abort_pending_rebase(repo_path: &RepoPath) -> Result<()> {
|
||||
scope_time!("abort_pending_rebase");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
|
||||
abort_rebase(&repo)
|
||||
}
|
||||
@ -115,10 +121,10 @@ pub fn merge_branch_repo(
|
||||
}
|
||||
|
||||
///
|
||||
pub fn merge_msg(repo_path: &str) -> Result<String> {
|
||||
pub fn merge_msg(repo_path: &RepoPath) -> Result<String> {
|
||||
scope_time!("merge_msg");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
let content = repo.message()?;
|
||||
|
||||
Ok(content)
|
||||
@ -126,13 +132,13 @@ pub fn merge_msg(repo_path: &str) -> Result<String> {
|
||||
|
||||
///
|
||||
pub fn merge_commit(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
msg: &str,
|
||||
ids: &[CommitId],
|
||||
) -> Result<CommitId> {
|
||||
scope_time!("merge_commit");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
|
||||
let mut commits: Vec<Commit> = Vec::new();
|
||||
|
||||
@ -151,6 +157,7 @@ mod tests {
|
||||
use crate::sync::{
|
||||
create_branch,
|
||||
tests::{repo_init, write_commit_file},
|
||||
RepoPath,
|
||||
};
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
@ -158,7 +165,8 @@ mod tests {
|
||||
fn test_smoke() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
let c1 =
|
||||
write_commit_file(&repo, "test.txt", "test", "commit1");
|
||||
|
@ -20,6 +20,7 @@ mod merge;
|
||||
mod patches;
|
||||
mod rebase;
|
||||
pub mod remotes;
|
||||
mod repository;
|
||||
mod reset;
|
||||
mod staging;
|
||||
mod stash;
|
||||
@ -68,6 +69,8 @@ pub use remotes::{
|
||||
get_default_remote, get_remotes, push::AsyncProgress,
|
||||
tags::PushTagsProgress,
|
||||
};
|
||||
pub(crate) use repository::repo;
|
||||
pub use repository::{RepoPath, RepoPathRef};
|
||||
pub use reset::{reset_stage, reset_workdir};
|
||||
pub use staging::{discard_lines, stage_lines};
|
||||
pub use stash::{
|
||||
@ -80,17 +83,19 @@ pub use tags::{
|
||||
};
|
||||
pub use tree::{tree_file_content, tree_files, TreeFile};
|
||||
pub use utils::{
|
||||
get_head, get_head_tuple, is_bare_repo, is_repo, repo_dir,
|
||||
stage_add_all, stage_add_file, stage_addremoved, Head,
|
||||
get_head, get_head_tuple, is_repo, repo_dir, stage_add_all,
|
||||
stage_add_file, stage_addremoved, Head,
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{
|
||||
commit, stage_add_file,
|
||||
commit,
|
||||
repository::repo,
|
||||
stage_add_file,
|
||||
status::{get_status, StatusType},
|
||||
utils::{get_head_repo, repo, repo_write_file},
|
||||
CommitId, LogWalker,
|
||||
utils::{get_head_repo, repo_write_file},
|
||||
CommitId, LogWalker, RepoPath,
|
||||
};
|
||||
use crate::error::Result;
|
||||
use git2::Repository;
|
||||
@ -129,13 +134,16 @@ mod tests {
|
||||
repo_write_file(repo, file, content).unwrap();
|
||||
|
||||
stage_add_file(
|
||||
repo.workdir().unwrap().to_str().unwrap(),
|
||||
&repo.workdir().unwrap().to_str().unwrap().into(),
|
||||
Path::new(file),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
commit(repo.workdir().unwrap().to_str().unwrap(), commit_name)
|
||||
.unwrap()
|
||||
commit(
|
||||
&repo.workdir().unwrap().to_str().unwrap().into(),
|
||||
commit_name,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// write, stage and commit a file giving the commit a specific timestamp
|
||||
@ -148,7 +156,8 @@ mod tests {
|
||||
) -> CommitId {
|
||||
repo_write_file(repo, file, content).unwrap();
|
||||
|
||||
let path = repo.workdir().unwrap().to_str().unwrap();
|
||||
let path: &RepoPath =
|
||||
&repo.workdir().unwrap().to_str().unwrap().into();
|
||||
|
||||
stage_add_file(path, Path::new(file)).unwrap();
|
||||
|
||||
@ -156,7 +165,7 @@ mod tests {
|
||||
}
|
||||
|
||||
fn commit_at(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
msg: &str,
|
||||
time: git2::Time,
|
||||
) -> CommitId {
|
||||
@ -258,7 +267,7 @@ mod tests {
|
||||
}
|
||||
|
||||
/// helper returning amount of files with changes in the (wd,stage)
|
||||
pub fn get_statuses(repo_path: &str) -> (usize, usize) {
|
||||
pub fn get_statuses(repo_path: &RepoPath) -> (usize, usize) {
|
||||
(
|
||||
get_status(repo_path, StatusType::WorkingDir, None)
|
||||
.unwrap()
|
||||
@ -270,7 +279,7 @@ mod tests {
|
||||
}
|
||||
|
||||
///
|
||||
pub fn debug_cmd_print(path: &str, cmd: &str) {
|
||||
pub fn debug_cmd_print(path: &RepoPath, cmd: &str) {
|
||||
let cmd = debug_cmd(path, cmd);
|
||||
eprintln!("\n----\n{}", cmd);
|
||||
}
|
||||
@ -289,18 +298,18 @@ mod tests {
|
||||
commit_ids
|
||||
}
|
||||
|
||||
fn debug_cmd(path: &str, cmd: &str) -> String {
|
||||
fn debug_cmd(path: &RepoPath, cmd: &str) -> String {
|
||||
let output = if cfg!(target_os = "windows") {
|
||||
Command::new("cmd")
|
||||
.args(&["/C", cmd])
|
||||
.current_dir(path)
|
||||
.current_dir(path.gitpath())
|
||||
.output()
|
||||
.unwrap()
|
||||
} else {
|
||||
Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(cmd)
|
||||
.current_dir(path)
|
||||
.current_dir(path.gitpath())
|
||||
.output()
|
||||
.unwrap()
|
||||
};
|
||||
|
@ -3,20 +3,20 @@ use scopetime::scope_time;
|
||||
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
sync::utils,
|
||||
sync::repository::repo,
|
||||
};
|
||||
|
||||
use super::CommitId;
|
||||
use super::{CommitId, RepoPath};
|
||||
|
||||
/// rebase current HEAD on `branch`
|
||||
pub fn rebase_branch(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
branch: &str,
|
||||
branch_type: BranchType,
|
||||
) -> Result<RebaseState> {
|
||||
scope_time!("rebase_branch");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
|
||||
rebase_branch_repo(&repo, branch, branch_type)
|
||||
}
|
||||
@ -189,8 +189,9 @@ mod test_conflict_free_rebase {
|
||||
checkout_branch, create_branch,
|
||||
rebase::{rebase_branch, RebaseState},
|
||||
repo_state,
|
||||
repository::repo,
|
||||
tests::{repo_init, write_commit_file},
|
||||
utils, CommitId, RepoState,
|
||||
CommitId, RepoPath, RepoState,
|
||||
};
|
||||
use git2::{BranchType, Repository};
|
||||
|
||||
@ -209,10 +210,10 @@ mod test_conflict_free_rebase {
|
||||
|
||||
///
|
||||
fn test_rebase_branch_repo(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
branch_name: &str,
|
||||
) -> CommitId {
|
||||
let repo = utils::repo(repo_path).unwrap();
|
||||
let repo = repo(repo_path).unwrap();
|
||||
|
||||
let branch =
|
||||
repo.find_branch(branch_name, BranchType::Local).unwrap();
|
||||
@ -228,7 +229,8 @@ mod test_conflict_free_rebase {
|
||||
fn test_smoke() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
let c1 =
|
||||
write_commit_file(&repo, "test1.txt", "test", "commit1");
|
||||
@ -256,7 +258,8 @@ mod test_conflict_free_rebase {
|
||||
fn test_conflict() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
write_commit_file(&repo, "test.txt", "test1", "commit1");
|
||||
|
||||
@ -289,7 +292,7 @@ mod test_rebase {
|
||||
},
|
||||
rebase_branch, repo_state,
|
||||
tests::{repo_init, write_commit_file},
|
||||
RepoState,
|
||||
RepoPath, RepoState,
|
||||
};
|
||||
use git2::BranchType;
|
||||
|
||||
@ -297,7 +300,8 @@ mod test_rebase {
|
||||
fn test_conflicted_abort() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
write_commit_file(&repo, "test.txt", "test1", "commit1");
|
||||
|
||||
|
@ -8,7 +8,7 @@ use crate::{
|
||||
error::{Error, Result},
|
||||
sync::{
|
||||
cred::BasicAuthCredential,
|
||||
remotes::push::ProgressNotification, utils,
|
||||
remotes::push::ProgressNotification, repository::repo, utils,
|
||||
},
|
||||
ProgressPercent,
|
||||
};
|
||||
@ -20,14 +20,16 @@ use utils::bytes2string;
|
||||
pub use callbacks::Callbacks;
|
||||
pub use tags::tags_missing_remote;
|
||||
|
||||
use super::RepoPath;
|
||||
|
||||
/// origin
|
||||
pub const DEFAULT_REMOTE_NAME: &str = "origin";
|
||||
|
||||
///
|
||||
pub fn get_remotes(repo_path: &str) -> Result<Vec<String>> {
|
||||
pub fn get_remotes(repo_path: &RepoPath) -> Result<Vec<String>> {
|
||||
scope_time!("get_remotes");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
let remotes = repo.remotes()?;
|
||||
let remotes: Vec<String> =
|
||||
remotes.iter().flatten().map(String::from).collect();
|
||||
@ -37,8 +39,8 @@ pub fn get_remotes(repo_path: &str) -> Result<Vec<String>> {
|
||||
|
||||
/// tries to find origin or the only remote that is defined if any
|
||||
/// in case of multiple remotes and none named *origin* we fail
|
||||
pub fn get_default_remote(repo_path: &str) -> Result<String> {
|
||||
let repo = utils::repo(repo_path)?;
|
||||
pub fn get_default_remote(repo_path: &RepoPath) -> Result<String> {
|
||||
let repo = repo(repo_path)?;
|
||||
get_default_remote_in_repo(&repo)
|
||||
}
|
||||
|
||||
@ -78,12 +80,12 @@ pub(crate) fn get_default_remote_in_repo(
|
||||
|
||||
///
|
||||
fn fetch_from_remote(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
remote: &str,
|
||||
basic_credential: Option<BasicAuthCredential>,
|
||||
progress_sender: Option<Sender<ProgressNotification>>,
|
||||
) -> Result<()> {
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
|
||||
let mut remote = repo.find_remote(remote)?;
|
||||
|
||||
@ -99,13 +101,13 @@ fn fetch_from_remote(
|
||||
|
||||
/// updates/prunes all branches from all remotes
|
||||
pub fn fetch_all(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
basic_credential: &Option<BasicAuthCredential>,
|
||||
progress_sender: &Option<Sender<ProgressPercent>>,
|
||||
) -> Result<()> {
|
||||
scope_time!("fetch_all");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
let remotes = repo
|
||||
.remotes()?
|
||||
.iter()
|
||||
@ -133,14 +135,14 @@ pub fn fetch_all(
|
||||
|
||||
/// fetches from upstream/remote for local `branch`
|
||||
pub(crate) fn fetch(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
branch: &str,
|
||||
basic_credential: Option<BasicAuthCredential>,
|
||||
progress_sender: Option<Sender<ProgressNotification>>,
|
||||
) -> Result<usize> {
|
||||
scope_time!("fetch");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
let branch_ref = repo
|
||||
.find_branch(branch, BranchType::Local)?
|
||||
.into_reference();
|
||||
@ -171,7 +173,12 @@ mod tests {
|
||||
let (remote_dir, _remote) = repo_init().unwrap();
|
||||
let remote_path = remote_dir.path().to_str().unwrap();
|
||||
let (repo_dir, _repo) = repo_clone(remote_path).unwrap();
|
||||
let repo_path = repo_dir.path().as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath = &repo_dir
|
||||
.into_path()
|
||||
.as_os_str()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.into();
|
||||
|
||||
let remotes = get_remotes(repo_path).unwrap();
|
||||
|
||||
@ -185,7 +192,12 @@ mod tests {
|
||||
let (remote_dir, _remote) = repo_init().unwrap();
|
||||
let remote_path = remote_dir.path().to_str().unwrap();
|
||||
let (repo_dir, _repo) = repo_clone(remote_path).unwrap();
|
||||
let repo_path = repo_dir.path().as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath = &repo_dir
|
||||
.into_path()
|
||||
.as_os_str()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.into();
|
||||
|
||||
debug_cmd_print(
|
||||
repo_path,
|
||||
@ -199,10 +211,9 @@ mod tests {
|
||||
vec![String::from("origin"), String::from("second")]
|
||||
);
|
||||
|
||||
let first = get_default_remote_in_repo(
|
||||
&utils::repo(repo_path).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
let first =
|
||||
get_default_remote_in_repo(&repo(repo_path).unwrap())
|
||||
.unwrap();
|
||||
assert_eq!(first, String::from("origin"));
|
||||
}
|
||||
|
||||
@ -211,7 +222,12 @@ mod tests {
|
||||
let (remote_dir, _remote) = repo_init().unwrap();
|
||||
let remote_path = remote_dir.path().to_str().unwrap();
|
||||
let (repo_dir, _repo) = repo_clone(remote_path).unwrap();
|
||||
let repo_path = repo_dir.path().as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath = &repo_dir
|
||||
.into_path()
|
||||
.as_os_str()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.into();
|
||||
|
||||
debug_cmd_print(
|
||||
repo_path,
|
||||
@ -231,10 +247,9 @@ mod tests {
|
||||
vec![String::from("alternate"), String::from("origin")]
|
||||
);
|
||||
|
||||
let first = get_default_remote_in_repo(
|
||||
&utils::repo(repo_path).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
let first =
|
||||
get_default_remote_in_repo(&repo(repo_path).unwrap())
|
||||
.unwrap();
|
||||
assert_eq!(first, String::from("origin"));
|
||||
}
|
||||
|
||||
@ -243,7 +258,12 @@ mod tests {
|
||||
let (remote_dir, _remote) = repo_init().unwrap();
|
||||
let remote_path = remote_dir.path().to_str().unwrap();
|
||||
let (repo_dir, _repo) = repo_clone(remote_path).unwrap();
|
||||
let repo_path = repo_dir.path().as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath = &repo_dir
|
||||
.into_path()
|
||||
.as_os_str()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.into();
|
||||
|
||||
debug_cmd_print(
|
||||
repo_path,
|
||||
@ -264,9 +284,8 @@ mod tests {
|
||||
]
|
||||
);
|
||||
|
||||
let res = get_default_remote_in_repo(
|
||||
&utils::repo(repo_path).unwrap(),
|
||||
);
|
||||
let res =
|
||||
get_default_remote_in_repo(&repo(repo_path).unwrap());
|
||||
assert_eq!(res.is_err(), true);
|
||||
assert!(matches!(res, Err(Error::NoDefaultRemoteFound)));
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
use super::utils;
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
progress::ProgressPercent,
|
||||
sync::{
|
||||
branch::branch_set_upstream, cred::BasicAuthCredential,
|
||||
remotes::Callbacks, CommitId,
|
||||
remotes::Callbacks, repository::repo, CommitId, RepoPath,
|
||||
},
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
@ -91,7 +90,7 @@ impl AsyncProgress for ProgressNotification {
|
||||
|
||||
#[allow(clippy::redundant_pub_crate)]
|
||||
pub(crate) fn push(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
remote: &str,
|
||||
branch: &str,
|
||||
force: bool,
|
||||
@ -101,7 +100,7 @@ pub(crate) fn push(
|
||||
) -> Result<()> {
|
||||
scope_time!("push");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
let mut remote = repo.find_remote(remote)?;
|
||||
|
||||
let mut options = PushOptions::new();
|
||||
@ -178,13 +177,13 @@ mod tests {
|
||||
writeln!(tmp_repo_file, "TempSomething").unwrap();
|
||||
|
||||
sync::commit(
|
||||
tmp_repo_dir.path().to_str().unwrap(),
|
||||
&tmp_repo_dir.path().to_str().unwrap().into(),
|
||||
"repo_1_commit",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
push(
|
||||
tmp_repo_dir.path().to_str().unwrap(),
|
||||
&tmp_repo_dir.path().to_str().unwrap().into(),
|
||||
"origin",
|
||||
"master",
|
||||
false,
|
||||
@ -201,7 +200,7 @@ mod tests {
|
||||
writeln!(tmp_other_repo_file, "TempElse").unwrap();
|
||||
|
||||
sync::commit(
|
||||
tmp_other_repo_dir.path().to_str().unwrap(),
|
||||
&tmp_other_repo_dir.path().to_str().unwrap().into(),
|
||||
"repo_2_commit",
|
||||
)
|
||||
.unwrap();
|
||||
@ -210,7 +209,7 @@ mod tests {
|
||||
// should fail as branches diverged
|
||||
assert_eq!(
|
||||
push(
|
||||
tmp_other_repo_dir.path().to_str().unwrap(),
|
||||
&tmp_other_repo_dir.path().to_str().unwrap().into(),
|
||||
"origin",
|
||||
"master",
|
||||
false,
|
||||
@ -226,7 +225,7 @@ mod tests {
|
||||
// should work as it forces the push through
|
||||
assert_eq!(
|
||||
push(
|
||||
tmp_other_repo_dir.path().to_str().unwrap(),
|
||||
&tmp_other_repo_dir.path().to_str().unwrap().into(),
|
||||
"origin",
|
||||
"master",
|
||||
true,
|
||||
@ -269,13 +268,13 @@ mod tests {
|
||||
writeln!(tmp_repo_file, "TempSomething").unwrap();
|
||||
|
||||
sync::stage_add_file(
|
||||
tmp_repo_dir.path().to_str().unwrap(),
|
||||
&tmp_repo_dir.path().to_str().unwrap().into(),
|
||||
Path::new("temp_file.txt"),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let repo_1_commit = sync::commit(
|
||||
tmp_repo_dir.path().to_str().unwrap(),
|
||||
&tmp_repo_dir.path().to_str().unwrap().into(),
|
||||
"repo_1_commit",
|
||||
)
|
||||
.unwrap();
|
||||
@ -283,7 +282,7 @@ mod tests {
|
||||
//NOTE: make sure the commit actually contains that file
|
||||
assert_eq!(
|
||||
sync::get_commit_files(
|
||||
tmp_repo_dir.path().to_str().unwrap(),
|
||||
&tmp_repo_dir.path().to_str().unwrap().into(),
|
||||
repo_1_commit,
|
||||
None
|
||||
)
|
||||
@ -296,7 +295,7 @@ mod tests {
|
||||
assert!(commits.contains(&repo_1_commit));
|
||||
|
||||
push(
|
||||
tmp_repo_dir.path().to_str().unwrap(),
|
||||
&tmp_repo_dir.path().to_str().unwrap().into(),
|
||||
"origin",
|
||||
"master",
|
||||
false,
|
||||
@ -313,13 +312,13 @@ mod tests {
|
||||
writeln!(tmp_other_repo_file, "TempElse").unwrap();
|
||||
|
||||
sync::stage_add_file(
|
||||
tmp_other_repo_dir.path().to_str().unwrap(),
|
||||
&tmp_other_repo_dir.path().to_str().unwrap().into(),
|
||||
Path::new("temp_file.txt"),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let repo_2_commit = sync::commit(
|
||||
tmp_other_repo_dir.path().to_str().unwrap(),
|
||||
&tmp_other_repo_dir.path().to_str().unwrap().into(),
|
||||
"repo_2_commit",
|
||||
)
|
||||
.unwrap();
|
||||
@ -339,7 +338,7 @@ mod tests {
|
||||
// should fail as branches diverged
|
||||
assert_eq!(
|
||||
push(
|
||||
tmp_other_repo_dir.path().to_str().unwrap(),
|
||||
&tmp_other_repo_dir.path().to_str().unwrap().into(),
|
||||
"origin",
|
||||
"master",
|
||||
false,
|
||||
@ -360,7 +359,7 @@ mod tests {
|
||||
// should work as it forces the push through
|
||||
|
||||
push(
|
||||
tmp_other_repo_dir.path().to_str().unwrap(),
|
||||
&tmp_other_repo_dir.path().to_str().unwrap().into(),
|
||||
"origin",
|
||||
"master",
|
||||
true,
|
||||
@ -407,7 +406,7 @@ mod tests {
|
||||
assert!(commits.contains(&commit_1));
|
||||
|
||||
push(
|
||||
tmp_repo_dir.path().to_str().unwrap(),
|
||||
&tmp_repo_dir.path().to_str().unwrap().into(),
|
||||
"origin",
|
||||
"master",
|
||||
false,
|
||||
@ -419,14 +418,14 @@ mod tests {
|
||||
|
||||
// Create the local branch
|
||||
sync::create_branch(
|
||||
tmp_repo_dir.path().to_str().unwrap(),
|
||||
&tmp_repo_dir.path().to_str().unwrap().into(),
|
||||
"test_branch",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Push the local branch
|
||||
push(
|
||||
tmp_repo_dir.path().to_str().unwrap(),
|
||||
&tmp_repo_dir.path().to_str().unwrap().into(),
|
||||
"origin",
|
||||
"test_branch",
|
||||
false,
|
||||
@ -452,7 +451,7 @@ mod tests {
|
||||
// Delete the remote branch
|
||||
assert_eq!(
|
||||
push(
|
||||
tmp_repo_dir.path().to_str().unwrap(),
|
||||
&tmp_repo_dir.path().to_str().unwrap().into(),
|
||||
"origin",
|
||||
"test_branch",
|
||||
false,
|
||||
|
@ -1,10 +1,13 @@
|
||||
//!
|
||||
|
||||
use super::{push::AsyncProgress, utils};
|
||||
use super::push::AsyncProgress;
|
||||
use crate::{
|
||||
error::Result,
|
||||
progress::ProgressPercent,
|
||||
sync::{cred::BasicAuthCredential, remotes::Callbacks},
|
||||
sync::{
|
||||
cred::BasicAuthCredential, remotes::Callbacks,
|
||||
repository::repo, RepoPath,
|
||||
},
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
use git2::{Direction, PushOptions};
|
||||
@ -44,13 +47,13 @@ impl AsyncProgress for PushTagsProgress {
|
||||
|
||||
/// lists the remotes tags
|
||||
fn remote_tag_refs(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
remote: &str,
|
||||
basic_credential: Option<BasicAuthCredential>,
|
||||
) -> Result<Vec<String>> {
|
||||
scope_time!("remote_tags");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
let mut remote = repo.find_remote(remote)?;
|
||||
let callbacks = Callbacks::new(None, basic_credential);
|
||||
let conn = remote.connect_auth(
|
||||
@ -73,13 +76,13 @@ fn remote_tag_refs(
|
||||
|
||||
/// lists the remotes tags missing
|
||||
pub fn tags_missing_remote(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
remote: &str,
|
||||
basic_credential: Option<BasicAuthCredential>,
|
||||
) -> Result<Vec<String>> {
|
||||
scope_time!("tags_missing_remote");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
let tags = repo.tag_names(None)?;
|
||||
|
||||
let mut local_tags = tags
|
||||
@ -98,7 +101,7 @@ pub fn tags_missing_remote(
|
||||
|
||||
///
|
||||
pub fn push_tags(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
remote: &str,
|
||||
basic_credential: Option<BasicAuthCredential>,
|
||||
progress_sender: Option<Sender<PushTagsProgress>>,
|
||||
@ -115,7 +118,7 @@ pub fn push_tags(
|
||||
basic_credential.clone(),
|
||||
)?;
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
let mut remote = repo.find_remote(remote)?;
|
||||
|
||||
let total = tags_missing.len();
|
||||
@ -165,11 +168,13 @@ mod tests {
|
||||
|
||||
let (clone1_dir, clone1) = repo_clone(r1_dir).unwrap();
|
||||
|
||||
let clone1_dir = clone1_dir.path().to_str().unwrap();
|
||||
let clone1_dir: &RepoPath =
|
||||
&clone1_dir.path().to_str().unwrap().into();
|
||||
|
||||
let (clone2_dir, clone2) = repo_clone(r1_dir).unwrap();
|
||||
|
||||
let clone2_dir = clone2_dir.path().to_str().unwrap();
|
||||
let clone2_dir: &RepoPath =
|
||||
&clone2_dir.path().to_str().unwrap().into();
|
||||
|
||||
// clone1
|
||||
|
||||
@ -211,11 +216,13 @@ mod tests {
|
||||
|
||||
let (clone1_dir, clone1) = repo_clone(r1_dir).unwrap();
|
||||
|
||||
let clone1_dir = clone1_dir.path().to_str().unwrap();
|
||||
let clone1_dir: &RepoPath =
|
||||
&clone1_dir.path().to_str().unwrap().into();
|
||||
|
||||
let (clone2_dir, _clone2) = repo_clone(r1_dir).unwrap();
|
||||
|
||||
let clone2_dir = clone2_dir.path().to_str().unwrap();
|
||||
let clone2_dir: &RepoPath =
|
||||
&clone2_dir.path().to_str().unwrap().into();
|
||||
|
||||
// clone1
|
||||
|
||||
@ -248,7 +255,8 @@ mod tests {
|
||||
|
||||
let (clone1_dir, clone1) = repo_clone(r1_dir).unwrap();
|
||||
|
||||
let clone1_dir = clone1_dir.path().to_str().unwrap();
|
||||
let clone1_dir: &RepoPath =
|
||||
&clone1_dir.path().to_str().unwrap().into();
|
||||
|
||||
// clone1
|
||||
|
||||
@ -281,7 +289,8 @@ mod tests {
|
||||
let r1_dir = r1_dir.path().to_str().unwrap();
|
||||
|
||||
let (clone1_dir, clone1) = repo_clone(r1_dir).unwrap();
|
||||
let clone1_dir = clone1_dir.path().to_str().unwrap();
|
||||
let clone1_dir: &RepoPath =
|
||||
&clone1_dir.path().to_str().unwrap().into();
|
||||
|
||||
let commit1 =
|
||||
write_commit_file(&clone1, "test.txt", "test", "commit1");
|
||||
@ -291,7 +300,8 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
let (clone2_dir, _clone2) = repo_clone(r1_dir).unwrap();
|
||||
let clone2_dir = clone2_dir.path().to_str().unwrap();
|
||||
let clone2_dir: &RepoPath =
|
||||
&clone2_dir.path().to_str().unwrap().into();
|
||||
|
||||
// clone1 - creates tag
|
||||
|
||||
@ -319,7 +329,8 @@ mod tests {
|
||||
let r1_dir = r1_dir.path().to_str().unwrap();
|
||||
|
||||
let (clone1_dir, clone1) = repo_clone(r1_dir).unwrap();
|
||||
let clone1_dir = clone1_dir.path().to_str().unwrap();
|
||||
let clone1_dir: &RepoPath =
|
||||
&clone1_dir.path().to_str().unwrap().into();
|
||||
|
||||
let commit1 =
|
||||
write_commit_file(&clone1, "test.txt", "test", "commit1");
|
||||
@ -329,7 +340,8 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
let (clone2_dir, _clone2) = repo_clone(r1_dir).unwrap();
|
||||
let clone2_dir = clone2_dir.path().to_str().unwrap();
|
||||
let clone2_dir: &RepoPath =
|
||||
&clone2_dir.path().to_str().unwrap().into();
|
||||
|
||||
// clone1 - creates tag
|
||||
|
||||
|
63
asyncgit/src/sync/repository.rs
Normal file
63
asyncgit/src/sync/repository.rs
Normal file
@ -0,0 +1,63 @@
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use git2::{Repository, RepositoryOpenFlags};
|
||||
|
||||
use crate::error::Result;
|
||||
|
||||
///
|
||||
pub type RepoPathRef = RefCell<RepoPath>;
|
||||
|
||||
///
|
||||
#[derive(Clone)]
|
||||
pub enum RepoPath {
|
||||
///
|
||||
Path(PathBuf),
|
||||
///
|
||||
Workdir {
|
||||
///
|
||||
gitdir: PathBuf,
|
||||
///
|
||||
workdir: PathBuf,
|
||||
},
|
||||
}
|
||||
|
||||
impl RepoPath {
|
||||
///
|
||||
pub fn gitpath(&self) -> &Path {
|
||||
match self {
|
||||
Self::Path(p) => p.as_path(),
|
||||
Self::Workdir { gitdir, .. } => gitdir.as_path(),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
pub fn workdir(&self) -> Option<&Path> {
|
||||
match self {
|
||||
Self::Path(_) => None,
|
||||
Self::Workdir { workdir, .. } => Some(workdir.as_path()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for RepoPath {
|
||||
fn from(p: &str) -> Self {
|
||||
Self::Path(PathBuf::from(p))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn repo(repo_path: &RepoPath) -> Result<Repository> {
|
||||
let repo = Repository::open_ext(
|
||||
repo_path.gitpath(),
|
||||
RepositoryOpenFlags::empty(),
|
||||
Vec::<&Path>::new(),
|
||||
)?;
|
||||
|
||||
if let Some(workdir) = repo_path.workdir() {
|
||||
repo.set_workdir(workdir, false)?;
|
||||
}
|
||||
|
||||
Ok(repo)
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
use super::utils::{get_head_repo, repo};
|
||||
use crate::error::Result;
|
||||
use super::{utils::get_head_repo, RepoPath};
|
||||
use crate::{error::Result, sync::repository::repo};
|
||||
use git2::{build::CheckoutBuilder, ObjectType};
|
||||
use scopetime::scope_time;
|
||||
|
||||
///
|
||||
pub fn reset_stage(repo_path: &str, path: &str) -> Result<()> {
|
||||
pub fn reset_stage(repo_path: &RepoPath, path: &str) -> Result<()> {
|
||||
scope_time!("reset_stage");
|
||||
|
||||
let repo = repo(repo_path)?;
|
||||
@ -22,7 +22,7 @@ pub fn reset_stage(repo_path: &str, path: &str) -> Result<()> {
|
||||
}
|
||||
|
||||
///
|
||||
pub fn reset_workdir(repo_path: &str, path: &str) -> Result<()> {
|
||||
pub fn reset_workdir(repo_path: &RepoPath, path: &str) -> Result<()> {
|
||||
scope_time!("reset_workdir");
|
||||
|
||||
let repo = repo(repo_path)?;
|
||||
@ -49,6 +49,7 @@ mod tests {
|
||||
debug_cmd_print, get_statuses, repo_init, repo_init_empty,
|
||||
},
|
||||
utils::{stage_add_all, stage_add_file},
|
||||
RepoPath,
|
||||
};
|
||||
use std::{
|
||||
fs::{self, File},
|
||||
@ -86,7 +87,8 @@ mod tests {
|
||||
fn test_reset_only_unstaged() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
let res = get_status(repo_path, StatusType::WorkingDir, None)
|
||||
.unwrap();
|
||||
@ -130,7 +132,8 @@ mod tests {
|
||||
fn test_reset_untracked_in_subdir() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
{
|
||||
fs::create_dir(&root.join("foo")).unwrap();
|
||||
@ -155,7 +158,8 @@ mod tests {
|
||||
fn test_reset_folder() -> Result<()> {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
{
|
||||
fs::create_dir(&root.join("foo"))?;
|
||||
@ -200,7 +204,8 @@ mod tests {
|
||||
fn test_reset_untracked_in_subdir_and_index() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
let file = "foo/bar.txt";
|
||||
|
||||
{
|
||||
@ -240,7 +245,8 @@ mod tests {
|
||||
let file_path = Path::new("foo.txt");
|
||||
let (_td, repo) = repo_init_empty().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path))
|
||||
.unwrap()
|
||||
@ -262,7 +268,8 @@ mod tests {
|
||||
fn test_reset_untracked_in_subdir_with_cwd_in_subdir() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
{
|
||||
fs::create_dir(&root.join("foo")).unwrap();
|
||||
@ -277,7 +284,7 @@ mod tests {
|
||||
assert_eq!(get_statuses(repo_path), (1, 0));
|
||||
|
||||
reset_workdir(
|
||||
&root.join("foo").as_os_str().to_str().unwrap(),
|
||||
&root.join("foo").as_os_str().to_str().unwrap().into(),
|
||||
"foo/bar.txt",
|
||||
)
|
||||
.unwrap();
|
||||
@ -291,7 +298,8 @@ mod tests {
|
||||
fn test_reset_untracked_subdir() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
{
|
||||
fs::create_dir_all(&root.join("foo/bar")).unwrap();
|
||||
|
@ -1,15 +1,17 @@
|
||||
use super::{apply_selection, load_file};
|
||||
use crate::error::Result;
|
||||
use crate::sync::{
|
||||
diff::DiffLinePosition,
|
||||
patches::get_file_diff_patch_and_hunklines,
|
||||
utils::{repo, repo_write_file},
|
||||
use crate::{
|
||||
error::Result,
|
||||
sync::{
|
||||
diff::DiffLinePosition,
|
||||
patches::get_file_diff_patch_and_hunklines, repository::repo,
|
||||
utils::repo_write_file, RepoPath,
|
||||
},
|
||||
};
|
||||
use scopetime::scope_time;
|
||||
|
||||
/// discards specific lines in an unstaged hunk of a diff
|
||||
pub fn discard_lines(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
file_path: &str,
|
||||
lines: &[DiffLinePosition],
|
||||
) -> Result<()> {
|
||||
@ -69,7 +71,7 @@ mod test {
|
||||
";
|
||||
|
||||
let (path, repo) = repo_init().unwrap();
|
||||
let path = path.path().to_str().unwrap();
|
||||
let path: &RepoPath = &path.path().to_str().unwrap().into();
|
||||
|
||||
write_commit_file(&repo, "test.txt", FILE_1, "c1");
|
||||
|
||||
@ -114,7 +116,7 @@ end
|
||||
";
|
||||
|
||||
let (path, repo) = repo_init().unwrap();
|
||||
let path = path.path().to_str().unwrap();
|
||||
let path: &RepoPath = &path.path().to_str().unwrap().into();
|
||||
|
||||
write_commit_file(&repo, "test.txt", FILE_1, "c1");
|
||||
|
||||
@ -153,7 +155,7 @@ end
|
||||
";
|
||||
|
||||
let (path, repo) = repo_init().unwrap();
|
||||
let path = path.path().to_str().unwrap();
|
||||
let path: &RepoPath = &path.path().to_str().unwrap().into();
|
||||
|
||||
write_commit_file(&repo, "test.txt", FILE_1, "c1");
|
||||
|
||||
@ -200,7 +202,7 @@ end
|
||||
";
|
||||
|
||||
let (path, repo) = repo_init().unwrap();
|
||||
let path = path.path().to_str().unwrap();
|
||||
let path: &RepoPath = &path.path().to_str().unwrap().into();
|
||||
|
||||
write_commit_file(&repo, "test.txt", FILE_1, "c1");
|
||||
|
||||
@ -243,7 +245,7 @@ end
|
||||
";
|
||||
|
||||
let (path, repo) = repo_init().unwrap();
|
||||
let path = path.path().to_str().unwrap();
|
||||
let path: &RepoPath = &path.path().to_str().unwrap().into();
|
||||
|
||||
write_commit_file(&repo, "test.txt", FILE_1, "c1");
|
||||
|
||||
@ -288,7 +290,7 @@ end
|
||||
";
|
||||
|
||||
let (path, repo) = repo_init().unwrap();
|
||||
let path = path.path().to_str().unwrap();
|
||||
let path: &RepoPath = &path.path().to_str().unwrap().into();
|
||||
|
||||
write_commit_file(&repo, "test.txt", FILE_1, "c1");
|
||||
|
||||
@ -321,7 +323,7 @@ end
|
||||
";
|
||||
|
||||
let (path, repo) = repo_init().unwrap();
|
||||
let path = path.path().to_str().unwrap();
|
||||
let path: &RepoPath = &path.path().to_str().unwrap().into();
|
||||
|
||||
write_commit_file(&repo, "test.txt", FILE_1, "c1");
|
||||
|
||||
|
@ -3,7 +3,8 @@ use crate::{
|
||||
error::{Error, Result},
|
||||
sync::{
|
||||
diff::DiffLinePosition,
|
||||
patches::get_file_diff_patch_and_hunklines, utils::repo,
|
||||
patches::get_file_diff_patch_and_hunklines, repository::repo,
|
||||
RepoPath,
|
||||
},
|
||||
};
|
||||
use easy_cast::Conv;
|
||||
@ -12,7 +13,7 @@ use std::path::Path;
|
||||
|
||||
///
|
||||
pub fn stage_lines(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
file_path: &str,
|
||||
is_stage: bool,
|
||||
lines: &[DiffLinePosition],
|
||||
@ -80,7 +81,7 @@ mod test {
|
||||
";
|
||||
|
||||
let (path, repo) = repo_init().unwrap();
|
||||
let path = path.path().to_str().unwrap();
|
||||
let path: &RepoPath = &path.path().to_str().unwrap().into();
|
||||
|
||||
write_commit_file(&repo, "test.txt", FILE_1, "c1");
|
||||
|
||||
@ -113,7 +114,7 @@ b = 3
|
||||
c = 4";
|
||||
|
||||
let (path, repo) = repo_init().unwrap();
|
||||
let path = path.path().to_str().unwrap();
|
||||
let path: &RepoPath = &path.path().to_str().unwrap().into();
|
||||
|
||||
write_commit_file(&repo, "test.txt", FILE_1, "c1");
|
||||
|
||||
@ -154,7 +155,7 @@ c = 4";
|
||||
";
|
||||
|
||||
let (path, repo) = repo_init().unwrap();
|
||||
let path = path.path().to_str().unwrap();
|
||||
let path: &RepoPath = &path.path().to_str().unwrap().into();
|
||||
|
||||
write_commit_file(&repo, "test.txt", FILE_1, "c1");
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
use super::{utils::repo, CommitId};
|
||||
use crate::error::{Error, Result};
|
||||
use super::{CommitId, RepoPath};
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
sync::repository::repo,
|
||||
};
|
||||
use git2::{
|
||||
build::CheckoutBuilder, Oid, Repository, StashApplyOptions,
|
||||
StashFlags,
|
||||
@ -7,7 +10,7 @@ use git2::{
|
||||
use scopetime::scope_time;
|
||||
|
||||
///
|
||||
pub fn get_stashes(repo_path: &str) -> Result<Vec<CommitId>> {
|
||||
pub fn get_stashes(repo_path: &RepoPath) -> Result<Vec<CommitId>> {
|
||||
scope_time!("get_stashes");
|
||||
|
||||
let mut repo = repo(repo_path)?;
|
||||
@ -24,7 +27,7 @@ pub fn get_stashes(repo_path: &str) -> Result<Vec<CommitId>> {
|
||||
|
||||
/// checks whether a given commit is a stash commit.
|
||||
pub fn is_stash_commit(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
id: &CommitId,
|
||||
) -> Result<bool> {
|
||||
let stashes = get_stashes(repo_path)?;
|
||||
@ -32,7 +35,10 @@ pub fn is_stash_commit(
|
||||
}
|
||||
|
||||
///
|
||||
pub fn stash_drop(repo_path: &str, stash_id: CommitId) -> Result<()> {
|
||||
pub fn stash_drop(
|
||||
repo_path: &RepoPath,
|
||||
stash_id: CommitId,
|
||||
) -> Result<()> {
|
||||
scope_time!("stash_drop");
|
||||
|
||||
let mut repo = repo(repo_path)?;
|
||||
@ -45,7 +51,10 @@ pub fn stash_drop(repo_path: &str, stash_id: CommitId) -> Result<()> {
|
||||
}
|
||||
|
||||
///
|
||||
pub fn stash_pop(repo_path: &str, stash_id: CommitId) -> Result<()> {
|
||||
pub fn stash_pop(
|
||||
repo_path: &RepoPath,
|
||||
stash_id: CommitId,
|
||||
) -> Result<()> {
|
||||
scope_time!("stash_pop");
|
||||
|
||||
let mut repo = repo(repo_path)?;
|
||||
@ -59,7 +68,7 @@ pub fn stash_pop(repo_path: &str, stash_id: CommitId) -> Result<()> {
|
||||
|
||||
///
|
||||
pub fn stash_apply(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
stash_id: CommitId,
|
||||
allow_conflicts: bool,
|
||||
) -> Result<()> {
|
||||
@ -101,7 +110,7 @@ fn get_stash_index(
|
||||
|
||||
///
|
||||
pub fn stash_save(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
message: Option<&str>,
|
||||
include_untracked: bool,
|
||||
keep_index: bool,
|
||||
@ -143,7 +152,8 @@ mod tests {
|
||||
fn test_smoke() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
assert_eq!(
|
||||
stash_save(repo_path, None, true, false).is_ok(),
|
||||
@ -157,7 +167,8 @@ mod tests {
|
||||
fn test_stashing() -> Result<()> {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join("foo.txt"))?
|
||||
.write_all(b"test\nfoo")?;
|
||||
@ -175,7 +186,8 @@ mod tests {
|
||||
fn test_stashes() -> Result<()> {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join("foo.txt"))?
|
||||
.write_all(b"test\nfoo")?;
|
||||
@ -198,7 +210,8 @@ mod tests {
|
||||
fn test_stash_nothing_untracked() -> Result<()> {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join("foo.txt"))?
|
||||
.write_all(b"test\nfoo")?;
|
||||
@ -215,7 +228,8 @@ mod tests {
|
||||
let file_path1 = Path::new("file1.txt");
|
||||
let (_td, repo) = repo_init()?;
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path1))?.write_all(b"test")?;
|
||||
stage_add_file(repo_path, file_path1)?;
|
||||
@ -242,7 +256,8 @@ mod tests {
|
||||
fn test_stash_apply_conflict() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
repo_write_file(&repo, "test.txt", "test").unwrap();
|
||||
|
||||
@ -260,7 +275,8 @@ mod tests {
|
||||
fn test_stash_apply_conflict2() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
write_commit_file(&repo, "test.txt", "test", "c1");
|
||||
|
||||
@ -280,7 +296,8 @@ mod tests {
|
||||
fn test_stash_apply_creating_conflict() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
write_commit_file(&repo, "test.txt", "test", "c1");
|
||||
|
||||
@ -304,7 +321,8 @@ mod tests {
|
||||
fn test_stash_pop_no_conflict() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
write_commit_file(&repo, "test.txt", "test", "c1");
|
||||
|
||||
@ -326,7 +344,8 @@ mod tests {
|
||||
fn test_stash_pop_conflict() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
repo_write_file(&repo, "test.txt", "test").unwrap();
|
||||
|
||||
@ -348,7 +367,8 @@ mod tests {
|
||||
fn test_stash_pop_conflict_after_commit() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
write_commit_file(&repo, "test.txt", "test", "c1");
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::{error::Result, sync::utils};
|
||||
use super::RepoPath;
|
||||
use crate::{error::Result, sync::repository::repo};
|
||||
use git2::RepositoryState;
|
||||
use scopetime::scope_time;
|
||||
|
||||
@ -22,7 +23,7 @@ impl From<RepositoryState> for RepoState {
|
||||
RepositoryState::Merge => Self::Merge,
|
||||
RepositoryState::RebaseMerge => Self::Rebase,
|
||||
_ => {
|
||||
log::debug!("state not supported yet: {:?}", state);
|
||||
log::warn!("state not supported yet: {:?}", state);
|
||||
Self::Other
|
||||
}
|
||||
}
|
||||
@ -30,10 +31,10 @@ impl From<RepositoryState> for RepoState {
|
||||
}
|
||||
|
||||
///
|
||||
pub fn repo_state(repo_path: &str) -> Result<RepoState> {
|
||||
pub fn repo_state(repo_path: &RepoPath) -> Result<RepoState> {
|
||||
scope_time!("repo_state");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
|
||||
let state = repo.state();
|
||||
|
||||
|
@ -3,13 +3,13 @@
|
||||
use crate::{
|
||||
error::Error,
|
||||
error::Result,
|
||||
sync::{config::untracked_files_config_repo, utils},
|
||||
sync::{config::untracked_files_config_repo, repository::repo},
|
||||
};
|
||||
use git2::{Delta, Status, StatusOptions, StatusShow};
|
||||
use scopetime::scope_time;
|
||||
use std::path::Path;
|
||||
|
||||
use super::ShowUntrackedFilesConfig;
|
||||
use super::{RepoPath, ShowUntrackedFilesConfig};
|
||||
|
||||
///
|
||||
#[derive(Copy, Clone, Hash, PartialEq, Debug)]
|
||||
@ -96,13 +96,13 @@ impl From<StatusType> for StatusShow {
|
||||
|
||||
/// gurantees sorting
|
||||
pub fn get_status(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
status_type: StatusType,
|
||||
show_untracked: Option<ShowUntrackedFilesConfig>,
|
||||
) -> Result<Vec<StatusItem>> {
|
||||
scope_time!("get_status");
|
||||
|
||||
let repo = utils::repo(repo_path)?;
|
||||
let repo = repo(repo_path)?;
|
||||
|
||||
let show_untracked = if let Some(config) = show_untracked {
|
||||
config
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::{get_commits_info, utils::repo, CommitId};
|
||||
use crate::error::Result;
|
||||
use super::{get_commits_info, CommitId, RepoPath};
|
||||
use crate::{error::Result, sync::repository::repo};
|
||||
use scopetime::scope_time;
|
||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
|
||||
@ -25,7 +25,7 @@ pub struct TagWithMetadata {
|
||||
static MAX_MESSAGE_WIDTH: usize = 100;
|
||||
|
||||
/// returns `Tags` type filled with all tags found in repo
|
||||
pub fn get_tags(repo_path: &str) -> Result<Tags> {
|
||||
pub fn get_tags(repo_path: &RepoPath) -> Result<Tags> {
|
||||
scope_time!("get_tags");
|
||||
|
||||
let mut res = Tags::new();
|
||||
@ -67,7 +67,7 @@ pub fn get_tags(repo_path: &str) -> Result<Tags> {
|
||||
|
||||
///
|
||||
pub fn get_tags_with_metadata(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
) -> Result<Vec<TagWithMetadata>> {
|
||||
scope_time!("get_tags_with_metadata");
|
||||
|
||||
@ -119,7 +119,10 @@ pub fn get_tags_with_metadata(
|
||||
}
|
||||
|
||||
///
|
||||
pub fn delete_tag(repo_path: &str, tag_name: &str) -> Result<()> {
|
||||
pub fn delete_tag(
|
||||
repo_path: &RepoPath,
|
||||
tag_name: &str,
|
||||
) -> Result<()> {
|
||||
scope_time!("delete_tag");
|
||||
|
||||
let repo = repo(repo_path)?;
|
||||
@ -138,7 +141,8 @@ mod tests {
|
||||
fn test_smoke() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
assert_eq!(get_tags(repo_path).unwrap().is_empty(), true);
|
||||
}
|
||||
@ -147,7 +151,8 @@ mod tests {
|
||||
fn test_multitags() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
let sig = repo.signature().unwrap();
|
||||
let head_id = repo.head().unwrap().target().unwrap();
|
||||
|
@ -1,7 +1,7 @@
|
||||
use super::CommitId;
|
||||
use super::{CommitId, RepoPath};
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
sync::utils::repo,
|
||||
sync::repository::repo,
|
||||
};
|
||||
use git2::{Oid, Repository, Tree};
|
||||
use scopetime::scope_time;
|
||||
@ -23,7 +23,7 @@ pub struct TreeFile {
|
||||
|
||||
/// guarantees sorting the result
|
||||
pub fn tree_files(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
commit: CommitId,
|
||||
) -> Result<Vec<TreeFile>> {
|
||||
scope_time!("tree_files");
|
||||
@ -73,7 +73,7 @@ fn path_cmp(a: &Path, b: &Path) -> Ordering {
|
||||
|
||||
/// will only work on utf8 content
|
||||
pub fn tree_file_content(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
file: &TreeFile,
|
||||
) -> Result<String> {
|
||||
scope_time!("tree_file_content");
|
||||
@ -130,7 +130,8 @@ mod tests {
|
||||
fn test_smoke() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
let c1 =
|
||||
write_commit_file(&repo, "test.txt", "content", "c1");
|
||||
|
@ -1,6 +1,8 @@
|
||||
//! sync git api (various methods)
|
||||
|
||||
use super::{CommitId, ShowUntrackedFilesConfig};
|
||||
use super::{
|
||||
repository::repo, CommitId, RepoPath, ShowUntrackedFilesConfig,
|
||||
};
|
||||
use crate::{
|
||||
error::{Error, Result},
|
||||
sync::config::untracked_files_config_repo,
|
||||
@ -23,54 +25,28 @@ pub struct Head {
|
||||
}
|
||||
|
||||
///
|
||||
pub fn is_repo(repo_path: &str) -> bool {
|
||||
pub fn is_repo(repo_path: &RepoPath) -> bool {
|
||||
Repository::open_ext(
|
||||
repo_path,
|
||||
repo_path.gitpath(),
|
||||
RepositoryOpenFlags::empty(),
|
||||
Vec::<&Path>::new(),
|
||||
)
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
/// checks if the git repo at path `repo_path` is a bare repo
|
||||
pub fn is_bare_repo(repo_path: &str) -> Result<bool> {
|
||||
let repo = Repository::open_ext(
|
||||
repo_path,
|
||||
RepositoryOpenFlags::empty(),
|
||||
Vec::<&Path>::new(),
|
||||
)?;
|
||||
|
||||
Ok(repo.is_bare())
|
||||
}
|
||||
|
||||
///
|
||||
pub(crate) fn repo(repo_path: &str) -> Result<Repository> {
|
||||
let repo = Repository::open_ext(
|
||||
repo_path,
|
||||
RepositoryOpenFlags::empty(),
|
||||
Vec::<&Path>::new(),
|
||||
)?;
|
||||
|
||||
if repo.is_bare() {
|
||||
return Err(Error::Generic("bare repo".to_string()));
|
||||
}
|
||||
|
||||
Ok(repo)
|
||||
}
|
||||
|
||||
///
|
||||
pub(crate) fn work_dir(repo: &Repository) -> Result<&Path> {
|
||||
repo.workdir().ok_or(Error::NoWorkDir)
|
||||
}
|
||||
|
||||
/// path to .git folder
|
||||
pub fn repo_dir(repo_path: &str) -> Result<PathBuf> {
|
||||
pub fn repo_dir(repo_path: &RepoPath) -> Result<PathBuf> {
|
||||
let repo = repo(repo_path)?;
|
||||
Ok(repo.path().to_owned())
|
||||
}
|
||||
|
||||
///
|
||||
pub fn repo_work_dir(repo_path: &str) -> Result<String> {
|
||||
pub fn repo_work_dir(repo_path: &RepoPath) -> Result<String> {
|
||||
let repo = repo(repo_path)?;
|
||||
work_dir(&repo)?.to_str().map_or_else(
|
||||
|| Err(Error::Generic("invalid workdir".to_string())),
|
||||
@ -79,13 +55,13 @@ pub fn repo_work_dir(repo_path: &str) -> Result<String> {
|
||||
}
|
||||
|
||||
///
|
||||
pub fn get_head(repo_path: &str) -> Result<CommitId> {
|
||||
pub fn get_head(repo_path: &RepoPath) -> Result<CommitId> {
|
||||
let repo = repo(repo_path)?;
|
||||
get_head_repo(&repo)
|
||||
}
|
||||
|
||||
///
|
||||
pub fn get_head_tuple(repo_path: &str) -> Result<Head> {
|
||||
pub fn get_head_tuple(repo_path: &RepoPath) -> Result<Head> {
|
||||
let repo = repo(repo_path)?;
|
||||
let id = get_head_repo(&repo)?;
|
||||
let name = get_head_refname(&repo)?;
|
||||
@ -111,7 +87,10 @@ pub fn get_head_repo(repo: &Repository) -> Result<CommitId> {
|
||||
}
|
||||
|
||||
/// add a file diff from workingdir to stage (will not add removed files see `stage_addremoved`)
|
||||
pub fn stage_add_file(repo_path: &str, path: &Path) -> Result<()> {
|
||||
pub fn stage_add_file(
|
||||
repo_path: &RepoPath,
|
||||
path: &Path,
|
||||
) -> Result<()> {
|
||||
scope_time!("stage_add_file");
|
||||
|
||||
let repo = repo(repo_path)?;
|
||||
@ -126,7 +105,7 @@ pub fn stage_add_file(repo_path: &str, path: &Path) -> Result<()> {
|
||||
|
||||
/// like `stage_add_file` but uses a pattern to match/glob multiple files/folders
|
||||
pub fn stage_add_all(
|
||||
repo_path: &str,
|
||||
repo_path: &RepoPath,
|
||||
pattern: &str,
|
||||
stage_untracked: Option<ShowUntrackedFilesConfig>,
|
||||
) -> Result<()> {
|
||||
@ -158,7 +137,7 @@ pub fn stage_add_all(
|
||||
}
|
||||
|
||||
/// Undo last commit in repo
|
||||
pub fn undo_last_commit(repo_path: &str) -> Result<()> {
|
||||
pub fn undo_last_commit(repo_path: &RepoPath) -> Result<()> {
|
||||
let repo = repo(repo_path)?;
|
||||
let previous_commit = repo.revparse_single("HEAD~")?;
|
||||
|
||||
@ -173,7 +152,10 @@ pub fn undo_last_commit(repo_path: &str) -> Result<()> {
|
||||
}
|
||||
|
||||
/// stage a removed file
|
||||
pub fn stage_addremoved(repo_path: &str, path: &Path) -> Result<()> {
|
||||
pub fn stage_addremoved(
|
||||
repo_path: &RepoPath,
|
||||
path: &Path,
|
||||
) -> Result<()> {
|
||||
scope_time!("stage_addremoved");
|
||||
|
||||
let repo = repo(repo_path)?;
|
||||
@ -250,7 +232,7 @@ mod tests {
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
|
||||
assert_eq!(
|
||||
stage_add_file(repo_path, file_path).is_ok(),
|
||||
stage_add_file(&repo_path.into(), file_path).is_ok(),
|
||||
false
|
||||
);
|
||||
}
|
||||
@ -260,7 +242,8 @@ mod tests {
|
||||
let file_path = Path::new("file1.txt");
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
File::create(&root.join(file_path))
|
||||
.unwrap()
|
||||
@ -283,7 +266,8 @@ mod tests {
|
||||
fn test_staging_folder() -> Result<()> {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
let status_count = |s: StatusType| -> usize {
|
||||
get_status(repo_path, s, None).unwrap().len()
|
||||
@ -311,7 +295,8 @@ mod tests {
|
||||
fn test_undo_commit_empty_repo() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
// expect to fail
|
||||
assert!(undo_last_commit(repo_path).is_err());
|
||||
@ -321,7 +306,8 @@ mod tests {
|
||||
fn test_undo_commit() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
// write commit file test.txt
|
||||
let c1 =
|
||||
@ -346,7 +332,8 @@ mod tests {
|
||||
fn test_not_staging_untracked_folder() -> Result<()> {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
fs::create_dir_all(&root.join("a/d"))?;
|
||||
File::create(&root.join(Path::new("a/d/f1.txt")))?
|
||||
@ -374,7 +361,8 @@ mod tests {
|
||||
let file_path = Path::new("file1.txt");
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
let status_count = |s: StatusType| -> usize {
|
||||
get_status(repo_path, s, None).unwrap().len()
|
||||
@ -408,7 +396,8 @@ mod tests {
|
||||
fn test_staging_sub_git_folder() -> Result<()> {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
let status_count = |s: StatusType| -> usize {
|
||||
get_status(repo_path, s, None).unwrap().len()
|
||||
@ -418,7 +407,10 @@ mod tests {
|
||||
|
||||
fs::create_dir_all(sub)?;
|
||||
|
||||
debug_cmd_print(sub.to_str().unwrap(), "git init subgit");
|
||||
debug_cmd_print(
|
||||
&sub.to_str().unwrap().into(),
|
||||
"git init subgit",
|
||||
);
|
||||
|
||||
File::create(sub.join("subgit/foo.txt"))
|
||||
.unwrap()
|
||||
@ -437,7 +429,8 @@ mod tests {
|
||||
fn test_head_empty() -> Result<()> {
|
||||
let (_td, repo) = repo_init_empty()?;
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
assert_eq!(get_head(repo_path).is_ok(), false);
|
||||
|
||||
@ -448,7 +441,8 @@ mod tests {
|
||||
fn test_head() -> Result<()> {
|
||||
let (_td, repo) = repo_init()?;
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
let repo_path: &RepoPath =
|
||||
&root.as_os_str().to_str().unwrap().into();
|
||||
|
||||
assert_eq!(get_head(repo_path).is_ok(), true);
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::{
|
||||
error::Result,
|
||||
hash,
|
||||
sync::{self},
|
||||
AsyncGitNotification, CWD,
|
||||
sync::{self, RepoPath},
|
||||
AsyncGitNotification,
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
use std::{
|
||||
@ -26,12 +26,17 @@ pub struct AsyncTags {
|
||||
last: Arc<Mutex<Option<(Instant, TagsResult)>>>,
|
||||
sender: Sender<AsyncGitNotification>,
|
||||
pending: Arc<AtomicUsize>,
|
||||
repo: RepoPath,
|
||||
}
|
||||
|
||||
impl AsyncTags {
|
||||
///
|
||||
pub fn new(sender: &Sender<AsyncGitNotification>) -> Self {
|
||||
pub fn new(
|
||||
repo: RepoPath,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
) -> Self {
|
||||
Self {
|
||||
repo,
|
||||
last: Arc::new(Mutex::new(None)),
|
||||
sender: sender.clone(),
|
||||
pending: Arc::new(AtomicUsize::new(0)),
|
||||
@ -81,9 +86,10 @@ impl AsyncTags {
|
||||
let arc_pending = Arc::clone(&self.pending);
|
||||
|
||||
self.pending.fetch_add(1, Ordering::Relaxed);
|
||||
let repo = self.repo.clone();
|
||||
|
||||
rayon_core::spawn(move || {
|
||||
let notify = Self::getter(&arc_last, outdated)
|
||||
let notify = Self::getter(&repo, &arc_last, outdated)
|
||||
.expect("error getting tags");
|
||||
|
||||
arc_pending.fetch_sub(1, Ordering::Relaxed);
|
||||
@ -101,10 +107,11 @@ impl AsyncTags {
|
||||
}
|
||||
|
||||
fn getter(
|
||||
repo: &RepoPath,
|
||||
arc_last: &Arc<Mutex<Option<(Instant, TagsResult)>>>,
|
||||
outdated: bool,
|
||||
) -> Result<bool> {
|
||||
let tags = sync::get_tags(CWD)?;
|
||||
let tags = sync::get_tags(repo)?;
|
||||
|
||||
let hash = hash(&tags);
|
||||
|
||||
|
52
src/app.rs
52
src/app.rs
@ -23,7 +23,10 @@ use crate::{
|
||||
AsyncAppNotification, AsyncNotification,
|
||||
};
|
||||
use anyhow::{bail, Result};
|
||||
use asyncgit::{sync, AsyncGitNotification, CWD};
|
||||
use asyncgit::{
|
||||
sync::{self, RepoPathRef},
|
||||
AsyncGitNotification,
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
use crossterm::event::{Event, KeyEvent};
|
||||
use std::{
|
||||
@ -41,6 +44,7 @@ use tui::{
|
||||
|
||||
/// the main app type
|
||||
pub struct App {
|
||||
repo: RepoPathRef,
|
||||
do_quit: bool,
|
||||
help: HelpComponent,
|
||||
msg: MsgComponent,
|
||||
@ -85,6 +89,7 @@ impl App {
|
||||
///
|
||||
#[allow(clippy::too_many_lines)]
|
||||
pub fn new(
|
||||
repo: RepoPathRef,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
sender_app: &Sender<AsyncAppNotification>,
|
||||
input: Input,
|
||||
@ -104,11 +109,13 @@ impl App {
|
||||
key_config.clone(),
|
||||
),
|
||||
commit: CommitComponent::new(
|
||||
repo.clone(),
|
||||
queue.clone(),
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
blame_file_popup: BlameFileComponent::new(
|
||||
&repo,
|
||||
&queue,
|
||||
sender,
|
||||
&strings::blame_title(&key_config),
|
||||
@ -116,23 +123,27 @@ impl App {
|
||||
key_config.clone(),
|
||||
),
|
||||
revision_files_popup: RevisionFilesPopup::new(
|
||||
repo.clone(),
|
||||
&queue,
|
||||
sender_app,
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
stashmsg_popup: StashMsgComponent::new(
|
||||
repo.clone(),
|
||||
queue.clone(),
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
inspect_commit_popup: InspectCommitComponent::new(
|
||||
&repo,
|
||||
&queue,
|
||||
sender,
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
compare_commits_popup: CompareCommitsComponent::new(
|
||||
&repo,
|
||||
&queue,
|
||||
sender,
|
||||
theme.clone(),
|
||||
@ -143,50 +154,59 @@ impl App {
|
||||
key_config.clone(),
|
||||
),
|
||||
push_popup: PushComponent::new(
|
||||
&repo,
|
||||
&queue,
|
||||
sender,
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
push_tags_popup: PushTagsComponent::new(
|
||||
&repo,
|
||||
&queue,
|
||||
sender,
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
pull_popup: PullComponent::new(
|
||||
&repo,
|
||||
&queue,
|
||||
sender,
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
fetch_popup: FetchComponent::new(
|
||||
repo.clone(),
|
||||
&queue,
|
||||
sender,
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
tag_commit_popup: TagCommitComponent::new(
|
||||
repo.clone(),
|
||||
queue.clone(),
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
create_branch_popup: CreateBranchComponent::new(
|
||||
repo.clone(),
|
||||
queue.clone(),
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
rename_branch_popup: RenameBranchComponent::new(
|
||||
repo.clone(),
|
||||
queue.clone(),
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
select_branch_popup: BranchListComponent::new(
|
||||
repo.clone(),
|
||||
queue.clone(),
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
tags_popup: TagListComponent::new(
|
||||
repo.clone(),
|
||||
&queue,
|
||||
sender,
|
||||
theme.clone(),
|
||||
@ -215,12 +235,14 @@ impl App {
|
||||
msg: MsgComponent::new(theme.clone(), key_config.clone()),
|
||||
tab: 0,
|
||||
revlog: Revlog::new(
|
||||
&repo,
|
||||
&queue,
|
||||
sender,
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
status_tab: Status::new(
|
||||
repo.clone(),
|
||||
&queue,
|
||||
sender,
|
||||
theme.clone(),
|
||||
@ -228,17 +250,20 @@ impl App {
|
||||
options,
|
||||
),
|
||||
stashing_tab: Stashing::new(
|
||||
&repo,
|
||||
sender,
|
||||
&queue,
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
stashlist_tab: StashList::new(
|
||||
repo.clone(),
|
||||
&queue,
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
files_tab: FilesTab::new(
|
||||
repo.clone(),
|
||||
sender_app,
|
||||
&queue,
|
||||
theme.clone(),
|
||||
@ -249,6 +274,7 @@ impl App {
|
||||
key_config,
|
||||
requires_redraw: Cell::new(false),
|
||||
file_to_open: None,
|
||||
repo,
|
||||
}
|
||||
}
|
||||
|
||||
@ -342,6 +368,7 @@ impl App {
|
||||
let result = match self.file_to_open.take() {
|
||||
Some(path) => {
|
||||
ExternalEditorComponent::open_file_in_editor(
|
||||
&self.repo.borrow(),
|
||||
Path::new(&path),
|
||||
)
|
||||
}
|
||||
@ -775,7 +802,10 @@ impl App {
|
||||
}
|
||||
}
|
||||
Action::StashDrop(_) | Action::StashPop(_) => {
|
||||
if let Err(e) = StashList::action_confirmed(&action) {
|
||||
if let Err(e) = StashList::action_confirmed(
|
||||
&self.repo.borrow(),
|
||||
&action,
|
||||
) {
|
||||
self.queue.push(InternalEvent::ShowErrorMsg(
|
||||
e.to_string(),
|
||||
));
|
||||
@ -784,16 +814,22 @@ impl App {
|
||||
flags.insert(NeedsUpdate::ALL);
|
||||
}
|
||||
Action::ResetHunk(path, hash) => {
|
||||
sync::reset_hunk(CWD, &path, hash)?;
|
||||
sync::reset_hunk(&self.repo.borrow(), &path, hash)?;
|
||||
flags.insert(NeedsUpdate::ALL);
|
||||
}
|
||||
Action::ResetLines(path, lines) => {
|
||||
sync::discard_lines(CWD, &path, &lines)?;
|
||||
sync::discard_lines(
|
||||
&self.repo.borrow(),
|
||||
&path,
|
||||
&lines,
|
||||
)?;
|
||||
flags.insert(NeedsUpdate::ALL);
|
||||
}
|
||||
Action::DeleteLocalBranch(branch_ref) => {
|
||||
if let Err(e) = sync::delete_branch(CWD, &branch_ref)
|
||||
{
|
||||
if let Err(e) = sync::delete_branch(
|
||||
&self.repo.borrow(),
|
||||
&branch_ref,
|
||||
) {
|
||||
self.queue.push(InternalEvent::ShowErrorMsg(
|
||||
e.to_string(),
|
||||
));
|
||||
@ -824,7 +860,9 @@ impl App {
|
||||
self.select_branch_popup.update_branches()?;
|
||||
}
|
||||
Action::DeleteTag(tag_name) => {
|
||||
if let Err(error) = sync::delete_tag(CWD, &tag_name) {
|
||||
if let Err(error) =
|
||||
sync::delete_tag(&self.repo.borrow(), &tag_name)
|
||||
{
|
||||
self.queue.push(InternalEvent::ShowErrorMsg(
|
||||
error.to_string(),
|
||||
));
|
||||
|
32
src/args.rs
32
src/args.rs
@ -1,5 +1,6 @@
|
||||
use crate::bug_report;
|
||||
use anyhow::{anyhow, Result};
|
||||
use asyncgit::sync::RepoPath;
|
||||
use clap::{
|
||||
crate_authors, crate_description, crate_name, crate_version,
|
||||
App as ClapApp, Arg,
|
||||
@ -13,6 +14,7 @@ use std::{
|
||||
|
||||
pub struct CliArgs {
|
||||
pub theme: PathBuf,
|
||||
pub repo_path: RepoPath,
|
||||
}
|
||||
|
||||
pub fn process_cmdline() -> Result<CliArgs> {
|
||||
@ -41,10 +43,17 @@ pub fn process_cmdline() -> Result<CliArgs> {
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("directory")
|
||||
.help("Set the working directory")
|
||||
.help("Set the git directory")
|
||||
.short("d")
|
||||
.long("directory")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("workdir")
|
||||
.help("Set the working directory")
|
||||
.short("w")
|
||||
.long("workdir")
|
||||
.takes_value(true),
|
||||
);
|
||||
|
||||
let arg_matches = app.get_matches();
|
||||
@ -55,20 +64,31 @@ pub fn process_cmdline() -> Result<CliArgs> {
|
||||
if arg_matches.is_present("logging") {
|
||||
setup_logging()?;
|
||||
}
|
||||
if arg_matches.is_present("directory") {
|
||||
let directory =
|
||||
arg_matches.value_of("directory").unwrap_or(".");
|
||||
env::set_current_dir(directory)?;
|
||||
}
|
||||
|
||||
let workdir = arg_matches.value_of("workdir").map(PathBuf::from);
|
||||
let gitdir = arg_matches
|
||||
.value_of("directory")
|
||||
.map_or_else(|| PathBuf::from("."), PathBuf::from);
|
||||
|
||||
#[allow(clippy::option_if_let_else)]
|
||||
let repo_path = if let Some(w) = workdir {
|
||||
RepoPath::Workdir { gitdir, workdir: w }
|
||||
} else {
|
||||
RepoPath::Path(gitdir)
|
||||
};
|
||||
|
||||
let arg_theme =
|
||||
arg_matches.value_of("theme").unwrap_or("theme.ron");
|
||||
|
||||
if get_app_config_path()?.join(arg_theme).is_file() {
|
||||
Ok(CliArgs {
|
||||
theme: get_app_config_path()?.join(arg_theme),
|
||||
repo_path,
|
||||
})
|
||||
} else {
|
||||
Ok(CliArgs {
|
||||
theme: get_app_config_path()?.join("theme.ron"),
|
||||
repo_path,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ use crate::{
|
||||
};
|
||||
use anyhow::Result;
|
||||
use asyncgit::{
|
||||
sync::{BlameHunk, CommitId, FileBlame},
|
||||
sync::{BlameHunk, CommitId, FileBlame, RepoPathRef},
|
||||
AsyncBlame, AsyncGitNotification, BlameParams,
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
@ -244,6 +244,7 @@ impl Component for BlameFileComponent {
|
||||
impl BlameFileComponent {
|
||||
///
|
||||
pub fn new(
|
||||
repo: &RepoPathRef,
|
||||
queue: &Queue,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
title: &str,
|
||||
@ -253,7 +254,10 @@ impl BlameFileComponent {
|
||||
Self {
|
||||
title: String::from(title),
|
||||
theme,
|
||||
async_blame: AsyncBlame::new(sender),
|
||||
async_blame: AsyncBlame::new(
|
||||
repo.borrow().clone(),
|
||||
sender,
|
||||
),
|
||||
queue: queue.clone(),
|
||||
visible: false,
|
||||
file_path: None,
|
||||
|
@ -19,9 +19,9 @@ use asyncgit::{
|
||||
RemoteBranch,
|
||||
},
|
||||
checkout_branch, get_branches_info, BranchInfo, BranchType,
|
||||
CommitId, RepoState,
|
||||
CommitId, RepoPathRef, RepoState,
|
||||
},
|
||||
AsyncGitNotification, CWD,
|
||||
AsyncGitNotification,
|
||||
};
|
||||
use crossterm::event::Event;
|
||||
use std::{cell::Cell, convert::TryInto};
|
||||
@ -39,6 +39,7 @@ use unicode_truncate::UnicodeTruncateStr;
|
||||
|
||||
///
|
||||
pub struct BranchListComponent {
|
||||
repo: RepoPathRef,
|
||||
branches: Vec<BranchInfo>,
|
||||
local: bool,
|
||||
visible: bool,
|
||||
@ -324,6 +325,7 @@ impl Component for BranchListComponent {
|
||||
|
||||
impl BranchListComponent {
|
||||
pub fn new(
|
||||
repo: RepoPathRef,
|
||||
queue: Queue,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
@ -338,6 +340,7 @@ impl BranchListComponent {
|
||||
theme,
|
||||
key_config,
|
||||
current_height: Cell::new(0),
|
||||
repo,
|
||||
}
|
||||
}
|
||||
|
||||
@ -352,7 +355,8 @@ impl BranchListComponent {
|
||||
/// fetch list of branches
|
||||
pub fn update_branches(&mut self) -> Result<()> {
|
||||
if self.is_visible() {
|
||||
self.branches = get_branches_info(CWD, self.local)?;
|
||||
self.branches =
|
||||
get_branches_info(&self.repo.borrow(), self.local)?;
|
||||
//remove remote branch called `HEAD`
|
||||
if !self.local {
|
||||
self.branches
|
||||
@ -386,7 +390,7 @@ impl BranchListComponent {
|
||||
self.branches.get(usize::from(self.selection))
|
||||
{
|
||||
sync::merge_branch(
|
||||
CWD,
|
||||
&self.repo.borrow(),
|
||||
&branch.name,
|
||||
self.get_branch_type(),
|
||||
)?;
|
||||
@ -402,7 +406,7 @@ impl BranchListComponent {
|
||||
self.branches.get(usize::from(self.selection))
|
||||
{
|
||||
sync::rebase_branch(
|
||||
CWD,
|
||||
&self.repo.borrow(),
|
||||
&branch.name,
|
||||
self.get_branch_type(),
|
||||
)?;
|
||||
@ -425,7 +429,8 @@ impl BranchListComponent {
|
||||
self.hide();
|
||||
self.queue.push(InternalEvent::Update(NeedsUpdate::ALL));
|
||||
|
||||
if sync::repo_state(CWD)? != RepoState::Clean {
|
||||
if sync::repo_state(&self.repo.borrow())? != RepoState::Clean
|
||||
{
|
||||
self.queue.push(InternalEvent::TabSwitch);
|
||||
}
|
||||
|
||||
@ -614,13 +619,13 @@ impl BranchListComponent {
|
||||
|
||||
if self.local {
|
||||
checkout_branch(
|
||||
asyncgit::CWD,
|
||||
&self.repo.borrow(),
|
||||
&self.branches[self.selection as usize].reference,
|
||||
)?;
|
||||
self.hide();
|
||||
} else {
|
||||
checkout_remote_branch(
|
||||
CWD,
|
||||
&self.repo.borrow(),
|
||||
&self.branches[self.selection as usize],
|
||||
)?;
|
||||
self.local = true;
|
||||
|
@ -11,13 +11,17 @@ use crate::{
|
||||
ui::style::SharedTheme,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use asyncgit::{sync, StatusItem, StatusItemType, CWD};
|
||||
use asyncgit::{
|
||||
sync::{self, RepoPathRef},
|
||||
StatusItem, StatusItemType,
|
||||
};
|
||||
use crossterm::event::Event;
|
||||
use std::path::Path;
|
||||
use tui::{backend::Backend, layout::Rect, Frame};
|
||||
|
||||
///
|
||||
pub struct ChangesComponent {
|
||||
repo: RepoPathRef,
|
||||
files: StatusTreeComponent,
|
||||
is_working_dir: bool,
|
||||
queue: Queue,
|
||||
@ -27,7 +31,10 @@ pub struct ChangesComponent {
|
||||
|
||||
impl ChangesComponent {
|
||||
///
|
||||
//TODO: fix
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
repo: RepoPathRef,
|
||||
title: &str,
|
||||
focus: bool,
|
||||
is_working_dir: bool,
|
||||
@ -48,6 +55,7 @@ impl ChangesComponent {
|
||||
queue,
|
||||
key_config,
|
||||
options,
|
||||
repo,
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,9 +93,15 @@ impl ChangesComponent {
|
||||
let path = Path::new(i.path.as_str());
|
||||
match i.status {
|
||||
StatusItemType::Deleted => {
|
||||
sync::stage_addremoved(CWD, path)?;
|
||||
sync::stage_addremoved(
|
||||
&self.repo.borrow(),
|
||||
path,
|
||||
)?;
|
||||
}
|
||||
_ => sync::stage_add_file(CWD, path)?,
|
||||
_ => sync::stage_add_file(
|
||||
&self.repo.borrow(),
|
||||
path,
|
||||
)?,
|
||||
};
|
||||
|
||||
if self.is_empty() {
|
||||
@ -103,7 +117,7 @@ impl ChangesComponent {
|
||||
|
||||
//TODO: check if we can handle the one file case with it aswell
|
||||
sync::stage_add_all(
|
||||
CWD,
|
||||
&self.repo.borrow(),
|
||||
tree_item.info.full_path.as_str(),
|
||||
config,
|
||||
)?;
|
||||
@ -112,7 +126,7 @@ impl ChangesComponent {
|
||||
}
|
||||
|
||||
let path = tree_item.info.full_path.as_str();
|
||||
sync::reset_stage(CWD, path)?;
|
||||
sync::reset_stage(&self.repo.borrow(), path)?;
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
@ -122,7 +136,7 @@ impl ChangesComponent {
|
||||
fn index_add_all(&mut self) -> Result<()> {
|
||||
let config = self.options.borrow().status_show_untracked;
|
||||
|
||||
sync::stage_add_all(CWD, "*", config)?;
|
||||
sync::stage_add_all(&self.repo.borrow(), "*", config)?;
|
||||
|
||||
self.queue.push(InternalEvent::Update(NeedsUpdate::ALL));
|
||||
|
||||
@ -130,7 +144,7 @@ impl ChangesComponent {
|
||||
}
|
||||
|
||||
fn stage_remove_all(&mut self) -> Result<()> {
|
||||
sync::reset_stage(CWD, "*")?;
|
||||
sync::reset_stage(&self.repo.borrow(), "*")?;
|
||||
|
||||
self.queue.push(InternalEvent::Update(NeedsUpdate::ALL));
|
||||
|
||||
@ -155,9 +169,10 @@ impl ChangesComponent {
|
||||
|
||||
fn add_to_ignore(&mut self) -> bool {
|
||||
if let Some(tree_item) = self.selection() {
|
||||
if let Err(e) =
|
||||
sync::add_to_ignore(CWD, &tree_item.info.full_path)
|
||||
{
|
||||
if let Err(e) = sync::add_to_ignore(
|
||||
&self.repo.borrow(),
|
||||
&tree_item.info.full_path,
|
||||
) {
|
||||
self.queue.push(InternalEvent::ShowErrorMsg(
|
||||
format!(
|
||||
"ignore error:\n{}\nfile:\n{:?}",
|
||||
|
@ -13,9 +13,9 @@ use anyhow::Result;
|
||||
use asyncgit::{
|
||||
cached, message_prettify,
|
||||
sync::{
|
||||
self, get_config_string, CommitId, HookResult, RepoState,
|
||||
self, get_config_string, CommitId, HookResult, RepoPathRef,
|
||||
RepoState,
|
||||
},
|
||||
CWD,
|
||||
};
|
||||
use crossterm::event::Event;
|
||||
use easy_cast::Cast;
|
||||
@ -37,6 +37,7 @@ enum Mode {
|
||||
}
|
||||
|
||||
pub struct CommitComponent {
|
||||
repo: RepoPathRef,
|
||||
input: TextInputComponent,
|
||||
mode: Mode,
|
||||
queue: Queue,
|
||||
@ -51,6 +52,7 @@ const FIRST_LINE_LIMIT: usize = 50;
|
||||
impl CommitComponent {
|
||||
///
|
||||
pub fn new(
|
||||
repo: RepoPathRef,
|
||||
queue: Queue,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
@ -58,7 +60,6 @@ impl CommitComponent {
|
||||
Self {
|
||||
queue,
|
||||
mode: Mode::Normal,
|
||||
|
||||
input: TextInputComponent::new(
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
@ -67,9 +68,10 @@ impl CommitComponent {
|
||||
true,
|
||||
),
|
||||
key_config,
|
||||
git_branch_name: cached::BranchName::new(CWD),
|
||||
git_branch_name: cached::BranchName::new(repo.clone()),
|
||||
commit_template: None,
|
||||
theme,
|
||||
repo,
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,7 +128,8 @@ impl CommitComponent {
|
||||
}
|
||||
|
||||
pub fn show_editor(&mut self) -> Result<()> {
|
||||
let file_path = sync::repo_dir(CWD)?.join("COMMIT_EDITMSG");
|
||||
let file_path = sync::repo_dir(&self.repo.borrow())?
|
||||
.join("COMMIT_EDITMSG");
|
||||
|
||||
{
|
||||
let mut file = File::create(&file_path)?;
|
||||
@ -140,7 +143,10 @@ impl CommitComponent {
|
||||
)?;
|
||||
}
|
||||
|
||||
ExternalEditorComponent::open_file_in_editor(&file_path)?;
|
||||
ExternalEditorComponent::open_file_in_editor(
|
||||
&self.repo.borrow(),
|
||||
&file_path,
|
||||
)?;
|
||||
|
||||
let mut message = String::new();
|
||||
|
||||
@ -157,11 +163,12 @@ impl CommitComponent {
|
||||
}
|
||||
|
||||
fn commit(&mut self) -> Result<()> {
|
||||
let gpgsign = get_config_string(CWD, "commit.gpgsign")
|
||||
.ok()
|
||||
.flatten()
|
||||
.and_then(|path| path.parse::<bool>().ok())
|
||||
.unwrap_or_default();
|
||||
let gpgsign =
|
||||
get_config_string(&self.repo.borrow(), "commit.gpgsign")
|
||||
.ok()
|
||||
.flatten()
|
||||
.and_then(|path| path.parse::<bool>().ok())
|
||||
.unwrap_or_default();
|
||||
|
||||
if gpgsign {
|
||||
anyhow::bail!("config commit.gpgsign=true detected.\ngpg signing not supported.\ndeactivate in your repo/gitconfig to be able to commit without signing.");
|
||||
@ -173,7 +180,9 @@ impl CommitComponent {
|
||||
}
|
||||
|
||||
fn commit_with_msg(&mut self, msg: String) -> Result<()> {
|
||||
if let HookResult::NotOk(e) = sync::hooks_pre_commit(CWD)? {
|
||||
if let HookResult::NotOk(e) =
|
||||
sync::hooks_pre_commit(&self.repo.borrow())?
|
||||
{
|
||||
log::error!("pre-commit hook error: {}", e);
|
||||
self.queue.push(InternalEvent::ShowErrorMsg(format!(
|
||||
"pre-commit hook error:\n{}",
|
||||
@ -183,7 +192,7 @@ impl CommitComponent {
|
||||
}
|
||||
let mut msg = message_prettify(msg, Some(b'#'))?;
|
||||
if let HookResult::NotOk(e) =
|
||||
sync::hooks_commit_msg(CWD, &mut msg)?
|
||||
sync::hooks_commit_msg(&self.repo.borrow(), &mut msg)?
|
||||
{
|
||||
log::error!("commit-msg hook error: {}", e);
|
||||
self.queue.push(InternalEvent::ShowErrorMsg(format!(
|
||||
@ -194,9 +203,13 @@ impl CommitComponent {
|
||||
}
|
||||
|
||||
let res = match &self.mode {
|
||||
Mode::Normal => sync::commit(CWD, &msg),
|
||||
Mode::Amend(amend) => sync::amend(CWD, *amend, &msg),
|
||||
Mode::Merge(ids) => sync::merge_commit(CWD, &msg, ids),
|
||||
Mode::Normal => sync::commit(&self.repo.borrow(), &msg),
|
||||
Mode::Amend(amend) => {
|
||||
sync::amend(&self.repo.borrow(), *amend, &msg)
|
||||
}
|
||||
Mode::Merge(ids) => {
|
||||
sync::merge_commit(&self.repo.borrow(), &msg, ids)
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(e) = res {
|
||||
@ -208,7 +221,9 @@ impl CommitComponent {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let HookResult::NotOk(e) = sync::hooks_post_commit(CWD)? {
|
||||
if let HookResult::NotOk(e) =
|
||||
sync::hooks_post_commit(&self.repo.borrow())?
|
||||
{
|
||||
log::error!("post-commit hook error: {}", e);
|
||||
self.queue.push(InternalEvent::ShowErrorMsg(format!(
|
||||
"post-commit hook error:\n{}",
|
||||
@ -229,7 +244,7 @@ impl CommitComponent {
|
||||
|
||||
fn can_amend(&self) -> bool {
|
||||
matches!(self.mode, Mode::Normal)
|
||||
&& sync::get_head(CWD).is_ok()
|
||||
&& sync::get_head(&self.repo.borrow()).is_ok()
|
||||
&& (self.is_empty() || !self.is_changed())
|
||||
}
|
||||
|
||||
@ -244,10 +259,11 @@ impl CommitComponent {
|
||||
|
||||
fn amend(&mut self) -> Result<()> {
|
||||
if self.can_amend() {
|
||||
let id = sync::get_head(CWD)?;
|
||||
let id = sync::get_head(&self.repo.borrow())?;
|
||||
self.mode = Mode::Amend(id);
|
||||
|
||||
let details = sync::get_commit_details(CWD, id)?;
|
||||
let details =
|
||||
sync::get_commit_details(&self.repo.borrow(), id)?;
|
||||
|
||||
self.input.set_title(strings::commit_title_amend());
|
||||
|
||||
@ -360,17 +376,22 @@ impl Component for CommitComponent {
|
||||
|
||||
self.mode = Mode::Normal;
|
||||
|
||||
self.mode = if sync::repo_state(CWD)? == RepoState::Merge {
|
||||
let ids = sync::mergehead_ids(CWD)?;
|
||||
self.mode = if sync::repo_state(&self.repo.borrow())?
|
||||
== RepoState::Merge
|
||||
{
|
||||
let ids = sync::mergehead_ids(&self.repo.borrow())?;
|
||||
self.input.set_title(strings::commit_title_merge());
|
||||
self.input.set_text(sync::merge_msg(CWD)?);
|
||||
self.input
|
||||
.set_text(sync::merge_msg(&self.repo.borrow())?);
|
||||
Mode::Merge(ids)
|
||||
} else {
|
||||
self.commit_template =
|
||||
get_config_string(CWD, "commit.template")
|
||||
.ok()
|
||||
.flatten()
|
||||
.and_then(|path| read_to_string(path).ok());
|
||||
self.commit_template = get_config_string(
|
||||
&self.repo.borrow(),
|
||||
"commit.template",
|
||||
)
|
||||
.ok()
|
||||
.flatten()
|
||||
.and_then(|path| read_to_string(path).ok());
|
||||
|
||||
if self.is_empty() {
|
||||
if let Some(s) = &self.commit_template {
|
||||
|
@ -12,10 +12,7 @@ use crate::{
|
||||
ui::style::SharedTheme,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use asyncgit::{
|
||||
sync::{self, CommitDetails, CommitId},
|
||||
CWD,
|
||||
};
|
||||
use asyncgit::sync::{self, CommitDetails, CommitId, RepoPathRef};
|
||||
use crossterm::event::Event;
|
||||
use tui::{
|
||||
backend::Backend,
|
||||
@ -25,6 +22,7 @@ use tui::{
|
||||
};
|
||||
|
||||
pub struct CompareDetailsComponent {
|
||||
repo: RepoPathRef,
|
||||
data: Option<(CommitDetails, CommitDetails)>,
|
||||
theme: SharedTheme,
|
||||
focused: bool,
|
||||
@ -32,18 +30,27 @@ pub struct CompareDetailsComponent {
|
||||
|
||||
impl CompareDetailsComponent {
|
||||
///
|
||||
pub const fn new(theme: SharedTheme, focused: bool) -> Self {
|
||||
pub const fn new(
|
||||
repo: RepoPathRef,
|
||||
theme: SharedTheme,
|
||||
focused: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
data: None,
|
||||
theme,
|
||||
focused,
|
||||
repo,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_commits(&mut self, ids: Option<(CommitId, CommitId)>) {
|
||||
self.data = ids.and_then(|ids| {
|
||||
let c1 = sync::get_commit_details(CWD, ids.0).ok();
|
||||
let c2 = sync::get_commit_details(CWD, ids.1).ok();
|
||||
let c1 =
|
||||
sync::get_commit_details(&self.repo.borrow(), ids.0)
|
||||
.ok();
|
||||
let c2 =
|
||||
sync::get_commit_details(&self.repo.borrow(), ids.1)
|
||||
.ok();
|
||||
|
||||
c1.and_then(|c1| {
|
||||
c2.map(|c2| {
|
||||
|
@ -11,9 +11,8 @@ use crate::{
|
||||
ui::style::SharedTheme,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use asyncgit::{
|
||||
sync::{self, CommitDetails, CommitId, CommitMessage},
|
||||
CWD,
|
||||
use asyncgit::sync::{
|
||||
self, CommitDetails, CommitId, CommitMessage, RepoPathRef,
|
||||
};
|
||||
use crossterm::event::Event;
|
||||
use std::clone::Clone;
|
||||
@ -30,6 +29,7 @@ use tui::{
|
||||
use super::style::Detail;
|
||||
|
||||
pub struct DetailsComponent {
|
||||
repo: RepoPathRef,
|
||||
data: Option<CommitDetails>,
|
||||
tags: Vec<String>,
|
||||
theme: SharedTheme,
|
||||
@ -46,11 +46,13 @@ type WrappedCommitMessage<'a> =
|
||||
impl DetailsComponent {
|
||||
///
|
||||
pub const fn new(
|
||||
repo: RepoPathRef,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
focused: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
repo,
|
||||
data: None,
|
||||
tags: Vec::new(),
|
||||
theme,
|
||||
@ -69,8 +71,9 @@ impl DetailsComponent {
|
||||
) {
|
||||
self.tags.clear();
|
||||
|
||||
self.data =
|
||||
id.and_then(|id| sync::get_commit_details(CWD, id).ok());
|
||||
self.data = id.and_then(|id| {
|
||||
sync::get_commit_details(&self.repo.borrow(), id).ok()
|
||||
});
|
||||
|
||||
self.scroll.reset();
|
||||
|
||||
|
@ -12,8 +12,8 @@ use crate::{
|
||||
};
|
||||
use anyhow::Result;
|
||||
use asyncgit::{
|
||||
sync::CommitTags, AsyncCommitFiles, AsyncGitNotification,
|
||||
CommitFilesParams,
|
||||
sync::{CommitTags, RepoPathRef},
|
||||
AsyncCommitFiles, AsyncGitNotification, CommitFilesParams,
|
||||
};
|
||||
use compare_details::CompareDetailsComponent;
|
||||
use crossbeam_channel::Sender;
|
||||
@ -40,6 +40,7 @@ impl CommitDetailsComponent {
|
||||
|
||||
///
|
||||
pub fn new(
|
||||
repo: &RepoPathRef,
|
||||
queue: &Queue,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
theme: SharedTheme,
|
||||
@ -47,15 +48,20 @@ impl CommitDetailsComponent {
|
||||
) -> Self {
|
||||
Self {
|
||||
single_details: DetailsComponent::new(
|
||||
repo.clone(),
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
false,
|
||||
),
|
||||
compare_details: CompareDetailsComponent::new(
|
||||
repo.clone(),
|
||||
theme.clone(),
|
||||
false,
|
||||
),
|
||||
git_commit_files: AsyncCommitFiles::new(sender),
|
||||
git_commit_files: AsyncCommitFiles::new(
|
||||
repo.borrow().clone(),
|
||||
sender,
|
||||
),
|
||||
file_tree: StatusTreeComponent::new(
|
||||
"",
|
||||
false,
|
||||
|
@ -9,9 +9,9 @@ use crate::{
|
||||
};
|
||||
use anyhow::Result;
|
||||
use asyncgit::{
|
||||
sync::{self, diff::DiffOptions, CommitId},
|
||||
sync::{self, diff::DiffOptions, CommitId, RepoPathRef},
|
||||
AsyncDiff, AsyncGitNotification, CommitFilesParams, DiffParams,
|
||||
DiffType, CWD,
|
||||
DiffType,
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
use crossterm::event::Event;
|
||||
@ -23,6 +23,7 @@ use tui::{
|
||||
};
|
||||
|
||||
pub struct CompareCommitsComponent {
|
||||
repo: RepoPathRef,
|
||||
commit_ids: Option<(CommitId, CommitId)>,
|
||||
diff: DiffComponent,
|
||||
details: CommitDetailsComponent,
|
||||
@ -156,26 +157,30 @@ impl CompareCommitsComponent {
|
||||
|
||||
///
|
||||
pub fn new(
|
||||
repo: &RepoPathRef,
|
||||
queue: &Queue,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
) -> Self {
|
||||
Self {
|
||||
repo: repo.clone(),
|
||||
details: CommitDetailsComponent::new(
|
||||
repo,
|
||||
queue,
|
||||
sender,
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
diff: DiffComponent::new(
|
||||
repo.clone(),
|
||||
queue.clone(),
|
||||
theme,
|
||||
key_config.clone(),
|
||||
true,
|
||||
),
|
||||
commit_ids: None,
|
||||
git_diff: AsyncDiff::new(sender),
|
||||
git_diff: AsyncDiff::new(repo.borrow().clone(), sender),
|
||||
visible: false,
|
||||
key_config,
|
||||
}
|
||||
@ -190,7 +195,7 @@ impl CompareCommitsComponent {
|
||||
let other = if let Some(other) = other {
|
||||
other
|
||||
} else {
|
||||
sync::get_head_tuple(CWD)?.id
|
||||
sync::get_head_tuple(&self.repo.borrow())?.id
|
||||
};
|
||||
self.commit_ids = Some((id, other));
|
||||
self.show()?;
|
||||
|
@ -10,7 +10,7 @@ use crate::{
|
||||
ui::style::SharedTheme,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use asyncgit::{sync, CWD};
|
||||
use asyncgit::sync::{self, RepoPathRef};
|
||||
use crossterm::event::Event;
|
||||
use easy_cast::Cast;
|
||||
use tui::{
|
||||
@ -18,6 +18,7 @@ use tui::{
|
||||
};
|
||||
|
||||
pub struct CreateBranchComponent {
|
||||
repo: RepoPathRef,
|
||||
input: TextInputComponent,
|
||||
queue: Queue,
|
||||
key_config: SharedKeyConfig,
|
||||
@ -95,6 +96,7 @@ impl Component for CreateBranchComponent {
|
||||
impl CreateBranchComponent {
|
||||
///
|
||||
pub fn new(
|
||||
repo: RepoPathRef,
|
||||
queue: Queue,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
@ -110,6 +112,7 @@ impl CreateBranchComponent {
|
||||
),
|
||||
theme,
|
||||
key_config,
|
||||
repo,
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,7 +125,10 @@ impl CreateBranchComponent {
|
||||
|
||||
///
|
||||
pub fn create_branch(&mut self) {
|
||||
let res = sync::create_branch(CWD, self.input.get_text());
|
||||
let res = sync::create_branch(
|
||||
&self.repo.borrow(),
|
||||
self.input.get_text(),
|
||||
);
|
||||
|
||||
self.input.clear();
|
||||
self.hide();
|
||||
|
@ -13,8 +13,8 @@ use crate::{
|
||||
use anyhow::Result;
|
||||
use asyncgit::{
|
||||
hash,
|
||||
sync::{self, diff::DiffLinePosition},
|
||||
DiffLine, DiffLineType, FileDiff, CWD,
|
||||
sync::{self, diff::DiffLinePosition, RepoPathRef},
|
||||
DiffLine, DiffLineType, FileDiff,
|
||||
};
|
||||
use bytesize::ByteSize;
|
||||
use crossterm::event::Event;
|
||||
@ -100,6 +100,7 @@ impl Selection {
|
||||
|
||||
///
|
||||
pub struct DiffComponent {
|
||||
repo: RepoPathRef,
|
||||
diff: Option<FileDiff>,
|
||||
pending: bool,
|
||||
selection: Selection,
|
||||
@ -117,6 +118,7 @@ pub struct DiffComponent {
|
||||
impl DiffComponent {
|
||||
///
|
||||
pub fn new(
|
||||
repo: RepoPathRef,
|
||||
queue: Queue,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
@ -135,6 +137,7 @@ impl DiffComponent {
|
||||
theme,
|
||||
key_config,
|
||||
is_immutable,
|
||||
repo,
|
||||
}
|
||||
}
|
||||
///
|
||||
@ -458,7 +461,11 @@ impl DiffComponent {
|
||||
if let Some(diff) = &self.diff {
|
||||
if let Some(hunk) = self.selected_hunk {
|
||||
let hash = diff.hunks[hunk].header_hash;
|
||||
sync::unstage_hunk(CWD, &self.current.path, hash)?;
|
||||
sync::unstage_hunk(
|
||||
&self.repo.borrow(),
|
||||
&self.current.path,
|
||||
hash,
|
||||
)?;
|
||||
self.queue_update();
|
||||
}
|
||||
}
|
||||
@ -471,12 +478,16 @@ impl DiffComponent {
|
||||
if let Some(hunk) = self.selected_hunk {
|
||||
if diff.untracked {
|
||||
sync::stage_add_file(
|
||||
CWD,
|
||||
&self.repo.borrow(),
|
||||
Path::new(&self.current.path),
|
||||
)?;
|
||||
} else {
|
||||
let hash = diff.hunks[hunk].header_hash;
|
||||
sync::stage_hunk(CWD, &self.current.path, hash)?;
|
||||
sync::stage_hunk(
|
||||
&self.repo.borrow(),
|
||||
&self.current.path,
|
||||
hash,
|
||||
)?;
|
||||
}
|
||||
|
||||
self.queue_update();
|
||||
@ -524,7 +535,7 @@ impl DiffComponent {
|
||||
self,
|
||||
"(un)stage lines:",
|
||||
sync::stage_lines(
|
||||
CWD,
|
||||
&self.repo.borrow(),
|
||||
&self.current.path,
|
||||
self.is_stage(),
|
||||
&selected_lines,
|
||||
|
@ -8,9 +8,8 @@ use crate::{
|
||||
ui::{self, style::SharedTheme},
|
||||
};
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use asyncgit::{
|
||||
sync::{get_config_string, utils::repo_work_dir},
|
||||
CWD,
|
||||
use asyncgit::sync::{
|
||||
get_config_string, utils::repo_work_dir, RepoPath,
|
||||
};
|
||||
use crossterm::{
|
||||
event::Event,
|
||||
@ -49,8 +48,11 @@ impl ExternalEditorComponent {
|
||||
}
|
||||
|
||||
/// opens file at given `path` in an available editor
|
||||
pub fn open_file_in_editor(path: &Path) -> Result<()> {
|
||||
let work_dir = repo_work_dir(CWD)?;
|
||||
pub fn open_file_in_editor(
|
||||
repo: &RepoPath,
|
||||
path: &Path,
|
||||
) -> Result<()> {
|
||||
let work_dir = repo_work_dir(repo)?;
|
||||
|
||||
let path = if path.is_relative() {
|
||||
Path::new(&work_dir).join(path)
|
||||
@ -71,7 +73,9 @@ impl ExternalEditorComponent {
|
||||
|
||||
let editor = env::var(environment_options[0])
|
||||
.ok()
|
||||
.or_else(|| get_config_string(CWD, "core.editor").ok()?)
|
||||
.or_else(|| {
|
||||
get_config_string(repo, "core.editor").ok()?
|
||||
})
|
||||
.or_else(|| env::var(environment_options[1]).ok())
|
||||
.or_else(|| env::var(environment_options[2]).ok())
|
||||
.unwrap_or_else(|| String::from("vi"));
|
||||
|
@ -11,9 +11,12 @@ use crate::{
|
||||
use anyhow::Result;
|
||||
use asyncgit::{
|
||||
asyncjob::AsyncSingleJob,
|
||||
sync::cred::{
|
||||
extract_username_password, need_username_password,
|
||||
BasicAuthCredential,
|
||||
sync::{
|
||||
cred::{
|
||||
extract_username_password, need_username_password,
|
||||
BasicAuthCredential,
|
||||
},
|
||||
RepoPathRef,
|
||||
},
|
||||
AsyncFetchJob, AsyncGitNotification, ProgressPercent,
|
||||
};
|
||||
@ -29,6 +32,7 @@ use tui::{
|
||||
|
||||
///
|
||||
pub struct FetchComponent {
|
||||
repo: RepoPathRef,
|
||||
visible: bool,
|
||||
async_fetch: AsyncSingleJob<AsyncFetchJob>,
|
||||
progress: Option<ProgressPercent>,
|
||||
@ -42,6 +46,7 @@ pub struct FetchComponent {
|
||||
impl FetchComponent {
|
||||
///
|
||||
pub fn new(
|
||||
repo: RepoPathRef,
|
||||
queue: &Queue,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
theme: SharedTheme,
|
||||
@ -59,15 +64,16 @@ impl FetchComponent {
|
||||
),
|
||||
theme,
|
||||
key_config,
|
||||
repo,
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
pub fn fetch(&mut self) -> Result<()> {
|
||||
self.show()?;
|
||||
if need_username_password()? {
|
||||
let cred =
|
||||
extract_username_password().unwrap_or_else(|_| {
|
||||
if need_username_password(&self.repo.borrow())? {
|
||||
let cred = extract_username_password(&self.repo.borrow())
|
||||
.unwrap_or_else(|_| {
|
||||
BasicAuthCredential::new(None, None)
|
||||
});
|
||||
if cred.is_complete() {
|
||||
@ -87,7 +93,10 @@ impl FetchComponent {
|
||||
self.pending = true;
|
||||
self.progress = None;
|
||||
self.progress = Some(ProgressPercent::empty());
|
||||
self.async_fetch.spawn(AsyncFetchJob::new(cred));
|
||||
self.async_fetch.spawn(AsyncFetchJob::new(
|
||||
self.repo.borrow().clone(),
|
||||
cred,
|
||||
));
|
||||
}
|
||||
|
||||
///
|
||||
|
@ -12,7 +12,7 @@ use crate::{
|
||||
};
|
||||
use anyhow::Result;
|
||||
use asyncgit::{
|
||||
sync::{diff::DiffOptions, CommitId, CommitTags},
|
||||
sync::{diff::DiffOptions, CommitId, CommitTags, RepoPathRef},
|
||||
AsyncDiff, AsyncGitNotification, CommitFilesParams, DiffParams,
|
||||
DiffType,
|
||||
};
|
||||
@ -176,6 +176,7 @@ impl InspectCommitComponent {
|
||||
|
||||
///
|
||||
pub fn new(
|
||||
repo: &RepoPathRef,
|
||||
queue: &Queue,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
theme: SharedTheme,
|
||||
@ -184,12 +185,14 @@ impl InspectCommitComponent {
|
||||
Self {
|
||||
queue: queue.clone(),
|
||||
details: CommitDetailsComponent::new(
|
||||
repo,
|
||||
queue,
|
||||
sender,
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
diff: DiffComponent::new(
|
||||
repo.clone(),
|
||||
queue.clone(),
|
||||
theme,
|
||||
key_config.clone(),
|
||||
@ -197,7 +200,7 @@ impl InspectCommitComponent {
|
||||
),
|
||||
commit_id: None,
|
||||
tags: None,
|
||||
git_diff: AsyncDiff::new(sender),
|
||||
git_diff: AsyncDiff::new(repo.borrow().clone(), sender),
|
||||
visible: false,
|
||||
key_config,
|
||||
}
|
||||
|
@ -17,10 +17,9 @@ use asyncgit::{
|
||||
extract_username_password, need_username_password,
|
||||
BasicAuthCredential,
|
||||
},
|
||||
get_default_remote,
|
||||
get_default_remote, RepoPathRef,
|
||||
},
|
||||
AsyncGitNotification, AsyncPull, FetchRequest, RemoteProgress,
|
||||
CWD,
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
use crossterm::event::Event;
|
||||
@ -34,6 +33,7 @@ use tui::{
|
||||
|
||||
///
|
||||
pub struct PullComponent {
|
||||
repo: RepoPathRef,
|
||||
visible: bool,
|
||||
git_fetch: AsyncPull,
|
||||
progress: Option<RemoteProgress>,
|
||||
@ -48,17 +48,19 @@ pub struct PullComponent {
|
||||
impl PullComponent {
|
||||
///
|
||||
pub fn new(
|
||||
repo: &RepoPathRef,
|
||||
queue: &Queue,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
) -> Self {
|
||||
Self {
|
||||
repo: repo.clone(),
|
||||
queue: queue.clone(),
|
||||
pending: false,
|
||||
visible: false,
|
||||
branch: String::new(),
|
||||
git_fetch: AsyncPull::new(sender),
|
||||
git_fetch: AsyncPull::new(repo.borrow().clone(), sender),
|
||||
progress: None,
|
||||
input_cred: CredComponent::new(
|
||||
theme.clone(),
|
||||
@ -73,9 +75,9 @@ impl PullComponent {
|
||||
pub fn fetch(&mut self, branch: String) -> Result<()> {
|
||||
self.branch = branch;
|
||||
self.show()?;
|
||||
if need_username_password()? {
|
||||
let cred =
|
||||
extract_username_password().unwrap_or_else(|_| {
|
||||
if need_username_password(&self.repo.borrow())? {
|
||||
let cred = extract_username_password(&self.repo.borrow())
|
||||
.unwrap_or_else(|_| {
|
||||
BasicAuthCredential::new(None, None)
|
||||
});
|
||||
if cred.is_complete() {
|
||||
@ -96,7 +98,7 @@ impl PullComponent {
|
||||
self.pending = true;
|
||||
self.progress = None;
|
||||
self.git_fetch.request(FetchRequest {
|
||||
remote: get_default_remote(CWD)?,
|
||||
remote: get_default_remote(&self.repo.borrow())?,
|
||||
branch: self.branch.clone(),
|
||||
basic_credential: cred,
|
||||
})?;
|
||||
@ -144,11 +146,13 @@ impl PullComponent {
|
||||
|
||||
// check if something is incoming and try a ff merge then
|
||||
fn try_ff_merge(&mut self) -> Result<()> {
|
||||
let branch_compare =
|
||||
sync::branch_compare_upstream(CWD, &self.branch)?;
|
||||
let branch_compare = sync::branch_compare_upstream(
|
||||
&self.repo.borrow(),
|
||||
&self.branch,
|
||||
)?;
|
||||
if branch_compare.behind > 0 {
|
||||
let ff_res = sync::branch_merge_upstream_fastforward(
|
||||
CWD,
|
||||
&self.repo.borrow(),
|
||||
&self.branch,
|
||||
);
|
||||
if let Err(err) = ff_res {
|
||||
@ -167,13 +171,19 @@ impl PullComponent {
|
||||
try_or_popup!(
|
||||
self,
|
||||
"rebase failed:",
|
||||
sync::merge_upstream_rebase(CWD, &self.branch)
|
||||
sync::merge_upstream_rebase(
|
||||
&self.repo.borrow(),
|
||||
&self.branch
|
||||
)
|
||||
);
|
||||
} else {
|
||||
try_or_popup!(
|
||||
self,
|
||||
"merge failed:",
|
||||
sync::merge_upstream_commit(CWD, &self.branch)
|
||||
sync::merge_upstream_commit(
|
||||
&self.repo.borrow(),
|
||||
&self.branch
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -182,8 +192,10 @@ impl PullComponent {
|
||||
self.queue.push(InternalEvent::ConfirmAction(
|
||||
Action::PullMerge {
|
||||
incoming,
|
||||
rebase: sync::config_is_pull_rebase(CWD)
|
||||
.unwrap_or_default(),
|
||||
rebase: sync::config_is_pull_rebase(
|
||||
&self.repo.borrow(),
|
||||
)
|
||||
.unwrap_or_default(),
|
||||
},
|
||||
));
|
||||
self.hide();
|
||||
|
@ -15,10 +15,10 @@ use asyncgit::{
|
||||
extract_username_password, need_username_password,
|
||||
BasicAuthCredential,
|
||||
},
|
||||
get_branch_remote, get_default_remote,
|
||||
get_branch_remote, get_default_remote, RepoPathRef,
|
||||
},
|
||||
AsyncGitNotification, AsyncPush, PushRequest, RemoteProgress,
|
||||
RemoteProgressState, CWD,
|
||||
RemoteProgressState,
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
use crossterm::event::Event;
|
||||
@ -50,6 +50,7 @@ impl PushComponentModifier {
|
||||
|
||||
///
|
||||
pub struct PushComponent {
|
||||
repo: RepoPathRef,
|
||||
modifier: PushComponentModifier,
|
||||
visible: bool,
|
||||
git_push: AsyncPush,
|
||||
@ -65,18 +66,20 @@ pub struct PushComponent {
|
||||
impl PushComponent {
|
||||
///
|
||||
pub fn new(
|
||||
repo: &RepoPathRef,
|
||||
queue: &Queue,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
) -> Self {
|
||||
Self {
|
||||
repo: repo.clone(),
|
||||
queue: queue.clone(),
|
||||
modifier: PushComponentModifier::None,
|
||||
pending: false,
|
||||
visible: false,
|
||||
branch: String::new(),
|
||||
git_push: AsyncPush::new(sender),
|
||||
git_push: AsyncPush::new(repo.borrow().clone(), sender),
|
||||
progress: None,
|
||||
input_cred: CredComponent::new(
|
||||
theme.clone(),
|
||||
@ -104,9 +107,9 @@ impl PushComponent {
|
||||
|
||||
self.show()?;
|
||||
|
||||
if need_username_password()? {
|
||||
let cred =
|
||||
extract_username_password().unwrap_or_else(|_| {
|
||||
if need_username_password(&self.repo.borrow())? {
|
||||
let cred = extract_username_password(&self.repo.borrow())
|
||||
.unwrap_or_else(|_| {
|
||||
BasicAuthCredential::new(None, None)
|
||||
});
|
||||
if cred.is_complete() {
|
||||
@ -126,13 +129,13 @@ impl PushComponent {
|
||||
force: bool,
|
||||
) -> Result<()> {
|
||||
let remote = if let Ok(Some(remote)) =
|
||||
get_branch_remote(CWD, &self.branch)
|
||||
get_branch_remote(&self.repo.borrow(), &self.branch)
|
||||
{
|
||||
log::info!("push: branch '{}' has upstream for remote '{}' - using that",self.branch,remote);
|
||||
remote
|
||||
} else {
|
||||
log::info!("push: branch '{}' has no upstream - looking up default remote",self.branch);
|
||||
let remote = get_default_remote(CWD)?;
|
||||
let remote = get_default_remote(&self.repo.borrow())?;
|
||||
log::info!(
|
||||
"push: branch '{}' to remote '{}'",
|
||||
self.branch,
|
||||
|
@ -16,8 +16,9 @@ use asyncgit::{
|
||||
BasicAuthCredential,
|
||||
},
|
||||
get_default_remote, AsyncProgress, PushTagsProgress,
|
||||
RepoPathRef,
|
||||
},
|
||||
AsyncGitNotification, AsyncPushTags, PushTagsRequest, CWD,
|
||||
AsyncGitNotification, AsyncPushTags, PushTagsRequest,
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
use crossterm::event::Event;
|
||||
@ -31,6 +32,7 @@ use tui::{
|
||||
|
||||
///
|
||||
pub struct PushTagsComponent {
|
||||
repo: RepoPathRef,
|
||||
visible: bool,
|
||||
git_push: AsyncPushTags,
|
||||
progress: Option<PushTagsProgress>,
|
||||
@ -44,16 +46,21 @@ pub struct PushTagsComponent {
|
||||
impl PushTagsComponent {
|
||||
///
|
||||
pub fn new(
|
||||
repo: &RepoPathRef,
|
||||
queue: &Queue,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
) -> Self {
|
||||
Self {
|
||||
repo: repo.clone(),
|
||||
queue: queue.clone(),
|
||||
pending: false,
|
||||
visible: false,
|
||||
git_push: AsyncPushTags::new(sender),
|
||||
git_push: AsyncPushTags::new(
|
||||
repo.borrow().clone(),
|
||||
sender,
|
||||
),
|
||||
progress: None,
|
||||
input_cred: CredComponent::new(
|
||||
theme.clone(),
|
||||
@ -67,9 +74,9 @@ impl PushTagsComponent {
|
||||
///
|
||||
pub fn push_tags(&mut self) -> Result<()> {
|
||||
self.show()?;
|
||||
if need_username_password()? {
|
||||
let cred =
|
||||
extract_username_password().unwrap_or_else(|_| {
|
||||
if need_username_password(&self.repo.borrow())? {
|
||||
let cred = extract_username_password(&self.repo.borrow())
|
||||
.unwrap_or_else(|_| {
|
||||
BasicAuthCredential::new(None, None)
|
||||
});
|
||||
if cred.is_complete() {
|
||||
@ -90,7 +97,7 @@ impl PushTagsComponent {
|
||||
self.pending = true;
|
||||
self.progress = None;
|
||||
self.git_push.request(PushTagsRequest {
|
||||
remote: get_default_remote(CWD)?,
|
||||
remote: get_default_remote(&self.repo.borrow())?,
|
||||
basic_credential: cred,
|
||||
})?;
|
||||
Ok(())
|
||||
|
@ -10,14 +10,12 @@ use crate::{
|
||||
ui::style::SharedTheme,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use asyncgit::{
|
||||
sync::{self},
|
||||
CWD,
|
||||
};
|
||||
use asyncgit::sync::{self, RepoPathRef};
|
||||
use crossterm::event::Event;
|
||||
use tui::{backend::Backend, layout::Rect, Frame};
|
||||
|
||||
pub struct RenameBranchComponent {
|
||||
repo: RepoPathRef,
|
||||
input: TextInputComponent,
|
||||
branch_ref: Option<String>,
|
||||
queue: Queue,
|
||||
@ -92,11 +90,13 @@ impl Component for RenameBranchComponent {
|
||||
impl RenameBranchComponent {
|
||||
///
|
||||
pub fn new(
|
||||
repo: RepoPathRef,
|
||||
queue: Queue,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
) -> Self {
|
||||
Self {
|
||||
repo,
|
||||
queue,
|
||||
input: TextInputComponent::new(
|
||||
theme,
|
||||
@ -127,8 +127,11 @@ impl RenameBranchComponent {
|
||||
///
|
||||
pub fn rename_branch(&mut self) {
|
||||
if let Some(br) = &self.branch_ref {
|
||||
let res =
|
||||
sync::rename_branch(CWD, br, self.input.get_text());
|
||||
let res = sync::rename_branch(
|
||||
&self.repo.borrow(),
|
||||
br,
|
||||
self.input.get_text(),
|
||||
);
|
||||
|
||||
match res {
|
||||
Ok(_) => {
|
||||
|
@ -11,10 +11,7 @@ use crate::{
|
||||
AsyncAppNotification, AsyncNotification,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use asyncgit::{
|
||||
sync::{self, CommitId, TreeFile},
|
||||
CWD,
|
||||
};
|
||||
use asyncgit::sync::{self, CommitId, RepoPathRef, TreeFile};
|
||||
use crossbeam_channel::Sender;
|
||||
use crossterm::event::Event;
|
||||
use filetreelist::{FileTree, FileTreeItem};
|
||||
@ -37,6 +34,7 @@ enum Focus {
|
||||
}
|
||||
|
||||
pub struct RevisionFilesComponent {
|
||||
repo: RepoPathRef,
|
||||
queue: Queue,
|
||||
theme: SharedTheme,
|
||||
//TODO: store TreeFiles in `tree`
|
||||
@ -52,6 +50,7 @@ pub struct RevisionFilesComponent {
|
||||
impl RevisionFilesComponent {
|
||||
///
|
||||
pub fn new(
|
||||
repo: RepoPathRef,
|
||||
queue: &Queue,
|
||||
sender: &Sender<AsyncAppNotification>,
|
||||
theme: SharedTheme,
|
||||
@ -62,6 +61,7 @@ impl RevisionFilesComponent {
|
||||
tree: FileTree::default(),
|
||||
scroll: VerticalScroll::new(),
|
||||
current_file: SyntaxTextComponent::new(
|
||||
repo.clone(),
|
||||
sender,
|
||||
key_config.clone(),
|
||||
theme.clone(),
|
||||
@ -71,6 +71,7 @@ impl RevisionFilesComponent {
|
||||
revision: None,
|
||||
focus: Focus::Tree,
|
||||
key_config,
|
||||
repo,
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,7 +80,8 @@ impl RevisionFilesComponent {
|
||||
let same_id =
|
||||
self.revision.map(|c| c == commit).unwrap_or_default();
|
||||
if !same_id {
|
||||
self.files = sync::tree_files(CWD, commit)?;
|
||||
self.files =
|
||||
sync::tree_files(&self.repo.borrow(), commit)?;
|
||||
let filenames: Vec<&Path> =
|
||||
self.files.iter().map(|f| f.path.as_path()).collect();
|
||||
self.tree = FileTree::new(&filenames, &BTreeSet::new())?;
|
||||
|
@ -13,7 +13,7 @@ use crate::{
|
||||
AsyncAppNotification, AsyncNotification,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use asyncgit::sync::CommitId;
|
||||
use asyncgit::sync::{CommitId, RepoPathRef};
|
||||
use crossbeam_channel::Sender;
|
||||
use crossterm::event::Event;
|
||||
use tui::{backend::Backend, layout::Rect, widgets::Clear, Frame};
|
||||
@ -27,6 +27,7 @@ pub struct RevisionFilesPopup {
|
||||
impl RevisionFilesPopup {
|
||||
///
|
||||
pub fn new(
|
||||
repo: RepoPathRef,
|
||||
queue: &Queue,
|
||||
sender: &Sender<AsyncAppNotification>,
|
||||
theme: SharedTheme,
|
||||
@ -34,6 +35,7 @@ impl RevisionFilesPopup {
|
||||
) -> Self {
|
||||
Self {
|
||||
files: RevisionFilesComponent::new(
|
||||
repo,
|
||||
queue,
|
||||
sender,
|
||||
theme,
|
||||
|
@ -11,11 +11,12 @@ use crate::{
|
||||
ui::style::SharedTheme,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use asyncgit::{sync, CWD};
|
||||
use asyncgit::sync::{self, RepoPathRef};
|
||||
use crossterm::event::Event;
|
||||
use tui::{backend::Backend, layout::Rect, Frame};
|
||||
|
||||
pub struct StashMsgComponent {
|
||||
repo: RepoPathRef,
|
||||
options: StashingOptions,
|
||||
input: TextInputComponent,
|
||||
queue: Queue,
|
||||
@ -63,8 +64,8 @@ impl Component for StashMsgComponent {
|
||||
|
||||
if let Event::Key(e) = ev {
|
||||
if e == self.key_config.keys.enter {
|
||||
match sync::stash_save(
|
||||
CWD,
|
||||
let result = sync::stash_save(
|
||||
&self.repo.borrow(),
|
||||
if self.input.get_text().is_empty() {
|
||||
None
|
||||
} else {
|
||||
@ -72,7 +73,8 @@ impl Component for StashMsgComponent {
|
||||
},
|
||||
self.options.stash_untracked,
|
||||
self.options.keep_index,
|
||||
) {
|
||||
);
|
||||
match result {
|
||||
Ok(_) => {
|
||||
self.input.clear();
|
||||
self.hide();
|
||||
@ -123,6 +125,7 @@ impl Component for StashMsgComponent {
|
||||
impl StashMsgComponent {
|
||||
///
|
||||
pub fn new(
|
||||
repo: RepoPathRef,
|
||||
queue: Queue,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
@ -138,6 +141,7 @@ impl StashMsgComponent {
|
||||
true,
|
||||
),
|
||||
key_config,
|
||||
repo,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,8 @@ use crate::{
|
||||
use anyhow::Result;
|
||||
use asyncgit::{
|
||||
asyncjob::AsyncSingleJob,
|
||||
sync::{self, TreeFile},
|
||||
ProgressPercent, CWD,
|
||||
sync::{self, RepoPathRef, TreeFile},
|
||||
ProgressPercent,
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
use crossterm::event::Event;
|
||||
@ -32,6 +32,7 @@ use tui::{
|
||||
};
|
||||
|
||||
pub struct SyntaxTextComponent {
|
||||
repo: RepoPathRef,
|
||||
current_file: Option<(String, Either<ui::SyntaxText, String>)>,
|
||||
async_highlighting: AsyncSingleJob<AsyncSyntaxJob>,
|
||||
syntax_progress: Option<ProgressPercent>,
|
||||
@ -44,6 +45,7 @@ pub struct SyntaxTextComponent {
|
||||
impl SyntaxTextComponent {
|
||||
///
|
||||
pub fn new(
|
||||
repo: RepoPathRef,
|
||||
sender: &Sender<AsyncAppNotification>,
|
||||
key_config: SharedKeyConfig,
|
||||
theme: SharedTheme,
|
||||
@ -56,6 +58,7 @@ impl SyntaxTextComponent {
|
||||
focused: false,
|
||||
key_config,
|
||||
theme,
|
||||
repo,
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,7 +113,7 @@ impl SyntaxTextComponent {
|
||||
|
||||
if !already_loaded {
|
||||
//TODO: fetch file content async aswell
|
||||
match sync::tree_file_content(CWD, item) {
|
||||
match sync::tree_file_content(&self.repo.borrow(), item) {
|
||||
Ok(content) => {
|
||||
let content = tabs_to_spaces(content);
|
||||
self.syntax_progress =
|
||||
|
@ -10,14 +10,12 @@ use crate::{
|
||||
ui::style::SharedTheme,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use asyncgit::{
|
||||
sync::{self, CommitId},
|
||||
CWD,
|
||||
};
|
||||
use asyncgit::sync::{self, CommitId, RepoPathRef};
|
||||
use crossterm::event::Event;
|
||||
use tui::{backend::Backend, layout::Rect, Frame};
|
||||
|
||||
pub struct TagCommitComponent {
|
||||
repo: RepoPathRef,
|
||||
input: TextInputComponent,
|
||||
commit_id: Option<CommitId>,
|
||||
queue: Queue,
|
||||
@ -92,6 +90,7 @@ impl Component for TagCommitComponent {
|
||||
impl TagCommitComponent {
|
||||
///
|
||||
pub fn new(
|
||||
repo: RepoPathRef,
|
||||
queue: Queue,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
@ -107,6 +106,7 @@ impl TagCommitComponent {
|
||||
),
|
||||
commit_id: None,
|
||||
key_config,
|
||||
repo,
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,7 +121,12 @@ impl TagCommitComponent {
|
||||
///
|
||||
pub fn tag(&mut self) {
|
||||
if let Some(commit_id) = self.commit_id {
|
||||
match sync::tag(CWD, &commit_id, self.input.get_text()) {
|
||||
let result = sync::tag(
|
||||
&self.repo.borrow(),
|
||||
&commit_id,
|
||||
self.input.get_text(),
|
||||
);
|
||||
match result {
|
||||
Ok(_) => {
|
||||
self.input.clear();
|
||||
self.hide();
|
||||
|
@ -18,8 +18,8 @@ use asyncgit::{
|
||||
extract_username_password, need_username_password,
|
||||
BasicAuthCredential,
|
||||
},
|
||||
sync::{get_tags_with_metadata, TagWithMetadata},
|
||||
AsyncGitNotification, CWD,
|
||||
sync::{get_tags_with_metadata, RepoPathRef, TagWithMetadata},
|
||||
AsyncGitNotification,
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
use crossterm::event::Event;
|
||||
@ -38,6 +38,7 @@ use ui::style::SharedTheme;
|
||||
|
||||
///
|
||||
pub struct TagListComponent {
|
||||
repo: RepoPathRef,
|
||||
theme: SharedTheme,
|
||||
queue: Queue,
|
||||
tags: Option<Vec<TagWithMetadata>>,
|
||||
@ -249,6 +250,7 @@ impl Component for TagListComponent {
|
||||
|
||||
impl TagListComponent {
|
||||
pub fn new(
|
||||
repo: RepoPathRef,
|
||||
queue: &Queue,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
theme: SharedTheme,
|
||||
@ -265,6 +267,7 @@ impl TagListComponent {
|
||||
missing_remote_tags: None,
|
||||
async_remote_tags: AsyncSingleJob::new(sender.clone()),
|
||||
key_config,
|
||||
repo,
|
||||
}
|
||||
}
|
||||
|
||||
@ -273,17 +276,19 @@ impl TagListComponent {
|
||||
self.table_state.get_mut().select(Some(0));
|
||||
self.show()?;
|
||||
|
||||
let basic_credential = if need_username_password()? {
|
||||
let credential = extract_username_password()?;
|
||||
let basic_credential =
|
||||
if need_username_password(&self.repo.borrow())? {
|
||||
let credential =
|
||||
extract_username_password(&self.repo.borrow())?;
|
||||
|
||||
if credential.is_complete() {
|
||||
Some(credential)
|
||||
if credential.is_complete() {
|
||||
Some(credential)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
};
|
||||
|
||||
self.basic_credential = basic_credential;
|
||||
|
||||
@ -320,7 +325,7 @@ impl TagListComponent {
|
||||
|
||||
/// fetch list of tags
|
||||
pub fn update_tags(&mut self) -> Result<()> {
|
||||
let tags = get_tags_with_metadata(CWD)?;
|
||||
let tags = get_tags_with_metadata(&self.repo.borrow())?;
|
||||
|
||||
self.tags = Some(tags);
|
||||
|
||||
@ -329,6 +334,7 @@ impl TagListComponent {
|
||||
|
||||
pub fn update_missing_remote_tags(&mut self) {
|
||||
self.async_remote_tags.spawn(AsyncRemoteTagsJob::new(
|
||||
self.repo.borrow().clone(),
|
||||
self.basic_credential.clone(),
|
||||
));
|
||||
}
|
||||
|
20
src/main.rs
20
src/main.rs
@ -38,7 +38,7 @@ mod version;
|
||||
|
||||
use crate::{app::App, args::process_cmdline};
|
||||
use anyhow::{bail, Result};
|
||||
use asyncgit::AsyncGitNotification;
|
||||
use asyncgit::{sync::RepoPath, AsyncGitNotification};
|
||||
use backtrace::Backtrace;
|
||||
use crossbeam_channel::{tick, unbounded, Receiver, Select};
|
||||
use crossterm::{
|
||||
@ -55,6 +55,7 @@ use scopeguard::defer;
|
||||
use scopetime::scope_time;
|
||||
use spinner::Spinner;
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
io::{self, Write},
|
||||
panic, process,
|
||||
time::{Duration, Instant},
|
||||
@ -104,7 +105,7 @@ fn main() -> Result<()> {
|
||||
|
||||
asyncgit::register_tracing_logging();
|
||||
|
||||
if !valid_path()? {
|
||||
if !valid_path(&cliargs.repo_path) {
|
||||
eprintln!("invalid path\nplease run gitui inside of a non-bare git repository");
|
||||
return Ok(());
|
||||
}
|
||||
@ -134,8 +135,14 @@ fn main() -> Result<()> {
|
||||
let ticker = tick(TICK_INTERVAL);
|
||||
let spinner_ticker = tick(SPINNER_INTERVAL);
|
||||
|
||||
let mut app =
|
||||
App::new(&tx_git, &tx_app, input, theme, key_config);
|
||||
let mut app = App::new(
|
||||
RefCell::new(cliargs.repo_path),
|
||||
&tx_git,
|
||||
&tx_app,
|
||||
input,
|
||||
theme,
|
||||
key_config,
|
||||
);
|
||||
|
||||
let mut spinner = Spinner::default();
|
||||
let mut first_update = true;
|
||||
@ -238,9 +245,8 @@ fn draw<B: Backend>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn valid_path() -> Result<bool> {
|
||||
Ok(asyncgit::sync::is_repo(asyncgit::CWD)
|
||||
&& !asyncgit::sync::is_bare_repo(asyncgit::CWD)?)
|
||||
fn valid_path(repo_path: &RepoPath) -> bool {
|
||||
asyncgit::sync::is_repo(repo_path)
|
||||
}
|
||||
|
||||
fn select_event(
|
||||
|
@ -17,10 +17,11 @@ use crate::{
|
||||
AsyncAppNotification, AsyncNotification,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use asyncgit::{sync, CWD};
|
||||
use asyncgit::sync::{self, RepoPathRef};
|
||||
use crossbeam_channel::Sender;
|
||||
|
||||
pub struct FilesTab {
|
||||
repo: RepoPathRef,
|
||||
visible: bool,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
@ -30,6 +31,7 @@ pub struct FilesTab {
|
||||
impl FilesTab {
|
||||
///
|
||||
pub fn new(
|
||||
repo: RepoPathRef,
|
||||
sender: &Sender<AsyncAppNotification>,
|
||||
queue: &Queue,
|
||||
theme: SharedTheme,
|
||||
@ -38,6 +40,7 @@ impl FilesTab {
|
||||
Self {
|
||||
visible: false,
|
||||
files: RevisionFilesComponent::new(
|
||||
repo.clone(),
|
||||
queue,
|
||||
sender,
|
||||
theme.clone(),
|
||||
@ -45,13 +48,14 @@ impl FilesTab {
|
||||
),
|
||||
theme,
|
||||
key_config,
|
||||
repo,
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
pub fn update(&mut self) -> Result<()> {
|
||||
if self.is_visible() {
|
||||
if let Ok(head) = sync::get_head(CWD) {
|
||||
if let Ok(head) = sync::get_head(&self.repo.borrow()) {
|
||||
self.files.set_commit(head)?;
|
||||
}
|
||||
}
|
||||
|
@ -12,9 +12,9 @@ use crate::{
|
||||
use anyhow::Result;
|
||||
use asyncgit::{
|
||||
cached,
|
||||
sync::{self, CommitId},
|
||||
sync::{self, CommitId, RepoPathRef},
|
||||
AsyncGitNotification, AsyncLog, AsyncTags, CommitFilesParams,
|
||||
FetchStatus, CWD,
|
||||
FetchStatus,
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
use crossterm::event::Event;
|
||||
@ -30,6 +30,7 @@ const SLICE_SIZE: usize = 1200;
|
||||
|
||||
///
|
||||
pub struct Revlog {
|
||||
repo: RepoPathRef,
|
||||
commit_details: CommitDetailsComponent,
|
||||
list: CommitList,
|
||||
git_log: AsyncLog,
|
||||
@ -43,14 +44,17 @@ pub struct Revlog {
|
||||
impl Revlog {
|
||||
///
|
||||
pub fn new(
|
||||
repo: &RepoPathRef,
|
||||
queue: &Queue,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
) -> Self {
|
||||
Self {
|
||||
repo: repo.clone(),
|
||||
queue: queue.clone(),
|
||||
commit_details: CommitDetailsComponent::new(
|
||||
repo,
|
||||
queue,
|
||||
sender,
|
||||
theme.clone(),
|
||||
@ -61,10 +65,14 @@ impl Revlog {
|
||||
theme,
|
||||
key_config.clone(),
|
||||
),
|
||||
git_log: AsyncLog::new(sender, None),
|
||||
git_tags: AsyncTags::new(sender),
|
||||
git_log: AsyncLog::new(
|
||||
repo.borrow().clone(),
|
||||
sender,
|
||||
None,
|
||||
),
|
||||
git_tags: AsyncTags::new(repo.borrow().clone(), sender),
|
||||
visible: false,
|
||||
branch_name: cached::BranchName::new(CWD),
|
||||
branch_name: cached::BranchName::new(repo.clone()),
|
||||
key_config,
|
||||
}
|
||||
}
|
||||
@ -139,7 +147,7 @@ impl Revlog {
|
||||
self.list.selection().saturating_sub(SLICE_SIZE / 2);
|
||||
|
||||
let commits = sync::get_commits_info(
|
||||
CWD,
|
||||
&self.repo.borrow(),
|
||||
&self.git_log.get_slice(want_min, SLICE_SIZE)?,
|
||||
self.list.current_size().0.into(),
|
||||
);
|
||||
|
@ -12,8 +12,8 @@ use crate::{
|
||||
};
|
||||
use anyhow::Result;
|
||||
use asyncgit::{
|
||||
sync::{self, status::StatusType},
|
||||
AsyncGitNotification, AsyncStatus, StatusParams, CWD,
|
||||
sync::{self, status::StatusType, RepoPathRef},
|
||||
AsyncGitNotification, AsyncStatus, StatusParams,
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
use crossterm::event::Event;
|
||||
@ -31,6 +31,7 @@ pub struct StashingOptions {
|
||||
}
|
||||
|
||||
pub struct Stashing {
|
||||
repo: RepoPathRef,
|
||||
index: StatusTreeComponent,
|
||||
visible: bool,
|
||||
options: StashingOptions,
|
||||
@ -45,12 +46,14 @@ impl Stashing {
|
||||
|
||||
///
|
||||
pub fn new(
|
||||
repo: &RepoPathRef,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
queue: &Queue,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
) -> Self {
|
||||
Self {
|
||||
repo: repo.clone(),
|
||||
index: StatusTreeComponent::new(
|
||||
&strings::stashing_files_title(&key_config),
|
||||
true,
|
||||
@ -64,7 +67,10 @@ impl Stashing {
|
||||
stash_untracked: true,
|
||||
},
|
||||
theme,
|
||||
git_status: AsyncStatus::new(sender.clone()),
|
||||
git_status: AsyncStatus::new(
|
||||
repo.borrow().clone(),
|
||||
sender.clone(),
|
||||
),
|
||||
queue: queue.clone(),
|
||||
key_config,
|
||||
}
|
||||
@ -258,7 +264,7 @@ impl Component for Stashing {
|
||||
|
||||
fn show(&mut self) -> Result<()> {
|
||||
let config_untracked_files =
|
||||
sync::untracked_files_config(CWD)?;
|
||||
sync::untracked_files_config(&self.repo.borrow())?;
|
||||
|
||||
self.options.stash_untracked =
|
||||
!config_untracked_files.include_none();
|
||||
|
@ -9,13 +9,11 @@ use crate::{
|
||||
ui::style::SharedTheme,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use asyncgit::{
|
||||
sync::{self, CommitId},
|
||||
CWD,
|
||||
};
|
||||
use asyncgit::sync::{self, CommitId, RepoPath, RepoPathRef};
|
||||
use crossterm::event::Event;
|
||||
|
||||
pub struct StashList {
|
||||
repo: RepoPathRef,
|
||||
list: CommitList,
|
||||
visible: bool,
|
||||
queue: Queue,
|
||||
@ -25,6 +23,7 @@ pub struct StashList {
|
||||
impl StashList {
|
||||
///
|
||||
pub fn new(
|
||||
repo: RepoPathRef,
|
||||
queue: &Queue,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
@ -38,15 +37,19 @@ impl StashList {
|
||||
),
|
||||
queue: queue.clone(),
|
||||
key_config,
|
||||
repo,
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
pub fn update(&mut self) -> Result<()> {
|
||||
if self.is_visible() {
|
||||
let stashes = sync::get_stashes(CWD)?;
|
||||
let commits =
|
||||
sync::get_commits_info(CWD, stashes.as_slice(), 100)?;
|
||||
let stashes = sync::get_stashes(&self.repo.borrow())?;
|
||||
let commits = sync::get_commits_info(
|
||||
&self.repo.borrow(),
|
||||
stashes.as_slice(),
|
||||
100,
|
||||
)?;
|
||||
|
||||
self.list.set_count_total(commits.len());
|
||||
self.list.items().set_items(0, commits);
|
||||
@ -57,7 +60,8 @@ impl StashList {
|
||||
|
||||
fn apply_stash(&mut self) {
|
||||
if let Some(e) = self.list.selected_entry() {
|
||||
match sync::stash_apply(CWD, e.id, false) {
|
||||
match sync::stash_apply(&self.repo.borrow(), e.id, false)
|
||||
{
|
||||
Ok(_) => {
|
||||
self.queue.push(InternalEvent::TabSwitch);
|
||||
}
|
||||
@ -97,26 +101,29 @@ impl StashList {
|
||||
}
|
||||
|
||||
/// Called when a pending stash action has been confirmed
|
||||
pub fn action_confirmed(action: &Action) -> Result<()> {
|
||||
pub fn action_confirmed(
|
||||
repo: &RepoPath,
|
||||
action: &Action,
|
||||
) -> Result<()> {
|
||||
match action {
|
||||
Action::StashDrop(ids) => Self::drop(ids)?,
|
||||
Action::StashPop(id) => Self::pop(*id)?,
|
||||
Action::StashDrop(ids) => Self::drop(repo, ids)?,
|
||||
Action::StashPop(id) => Self::pop(repo, *id)?,
|
||||
_ => (),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn drop(ids: &[CommitId]) -> Result<()> {
|
||||
fn drop(repo: &RepoPath, ids: &[CommitId]) -> Result<()> {
|
||||
for id in ids {
|
||||
sync::stash_drop(CWD, *id)?;
|
||||
sync::stash_drop(repo, *id)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn pop(id: CommitId) -> Result<()> {
|
||||
sync::stash_pop(CWD, id)?;
|
||||
fn pop(repo: &RepoPath, id: CommitId) -> Result<()> {
|
||||
sync::stash_pop(repo, id)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -14,10 +14,12 @@ use crate::{
|
||||
use anyhow::Result;
|
||||
use asyncgit::{
|
||||
cached,
|
||||
sync::{self, status::StatusType, RepoState},
|
||||
sync::{
|
||||
self, status::StatusType, RepoPath, RepoPathRef, RepoState,
|
||||
},
|
||||
sync::{BranchCompare, CommitId},
|
||||
AsyncDiff, AsyncGitNotification, AsyncStatus, DiffParams,
|
||||
DiffType, StatusParams, CWD,
|
||||
DiffType, StatusParams,
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
use crossterm::event::Event;
|
||||
@ -56,6 +58,7 @@ enum DiffTarget {
|
||||
}
|
||||
|
||||
pub struct Status {
|
||||
repo: RepoPathRef,
|
||||
visible: bool,
|
||||
focus: Focus,
|
||||
diff_target: DiffTarget,
|
||||
@ -79,7 +82,7 @@ impl DrawableComponent for Status {
|
||||
f: &mut tui::Frame<B>,
|
||||
rect: tui::layout::Rect,
|
||||
) -> Result<()> {
|
||||
let repo_unclean = Self::repo_state_unclean();
|
||||
let repo_unclean = self.repo_state_unclean();
|
||||
let rects = if repo_unclean {
|
||||
Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
@ -134,7 +137,7 @@ impl DrawableComponent for Status {
|
||||
self.draw_branch_state(f, &left_chunks);
|
||||
|
||||
if repo_unclean {
|
||||
Self::draw_repo_state(f, rects[1]);
|
||||
self.draw_repo_state(f, rects[1]);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -146,18 +149,21 @@ impl Status {
|
||||
|
||||
///
|
||||
pub fn new(
|
||||
repo: RepoPathRef,
|
||||
queue: &Queue,
|
||||
sender: &Sender<AsyncGitNotification>,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
options: SharedOptions,
|
||||
) -> Self {
|
||||
let repo_clone = repo.borrow().clone();
|
||||
Self {
|
||||
queue: queue.clone(),
|
||||
visible: true,
|
||||
focus: Focus::WorkDir,
|
||||
diff_target: DiffTarget::WorkingDir,
|
||||
index_wd: ChangesComponent::new(
|
||||
repo.clone(),
|
||||
&strings::title_status(&key_config),
|
||||
true,
|
||||
true,
|
||||
@ -167,6 +173,7 @@ impl Status {
|
||||
options.clone(),
|
||||
),
|
||||
index: ChangesComponent::new(
|
||||
repo.clone(),
|
||||
&strings::title_index(&key_config),
|
||||
false,
|
||||
false,
|
||||
@ -176,19 +183,27 @@ impl Status {
|
||||
options.clone(),
|
||||
),
|
||||
diff: DiffComponent::new(
|
||||
repo.clone(),
|
||||
queue.clone(),
|
||||
theme,
|
||||
key_config.clone(),
|
||||
false,
|
||||
),
|
||||
git_diff: AsyncDiff::new(sender),
|
||||
git_status_workdir: AsyncStatus::new(sender.clone()),
|
||||
git_status_stage: AsyncStatus::new(sender.clone()),
|
||||
git_diff: AsyncDiff::new(repo_clone.clone(), sender),
|
||||
git_status_workdir: AsyncStatus::new(
|
||||
repo_clone.clone(),
|
||||
sender.clone(),
|
||||
),
|
||||
git_status_stage: AsyncStatus::new(
|
||||
repo_clone,
|
||||
sender.clone(),
|
||||
),
|
||||
git_action_executed: false,
|
||||
git_branch_state: None,
|
||||
git_branch_name: cached::BranchName::new(CWD),
|
||||
git_branch_name: cached::BranchName::new(repo.clone()),
|
||||
key_config,
|
||||
options,
|
||||
repo,
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,11 +247,11 @@ impl Status {
|
||||
}
|
||||
}
|
||||
|
||||
fn repo_state_text(state: &RepoState) -> String {
|
||||
fn repo_state_text(repo: &RepoPath, state: &RepoState) -> String {
|
||||
match state {
|
||||
RepoState::Merge => {
|
||||
let ids =
|
||||
sync::mergehead_ids(CWD).unwrap_or_default();
|
||||
sync::mergehead_ids(repo).unwrap_or_default();
|
||||
|
||||
format!(
|
||||
"Commits: {}",
|
||||
@ -246,7 +261,7 @@ impl Status {
|
||||
)
|
||||
}
|
||||
RepoState::Rebase => {
|
||||
if let Ok(p) = sync::rebase_progress(CWD) {
|
||||
if let Ok(p) = sync::rebase_progress(repo) {
|
||||
format!(
|
||||
"Step: {}/{} Current Commit: {}",
|
||||
p.current + 1,
|
||||
@ -265,12 +280,16 @@ impl Status {
|
||||
}
|
||||
|
||||
fn draw_repo_state<B: tui::backend::Backend>(
|
||||
&self,
|
||||
f: &mut tui::Frame<B>,
|
||||
r: tui::layout::Rect,
|
||||
) {
|
||||
if let Ok(state) = sync::repo_state(CWD) {
|
||||
if let Ok(state) = sync::repo_state(&self.repo.borrow()) {
|
||||
if state != RepoState::Clean {
|
||||
let txt = Self::repo_state_text(&state);
|
||||
let txt = Self::repo_state_text(
|
||||
&self.repo.borrow(),
|
||||
&state,
|
||||
);
|
||||
|
||||
let w = Paragraph::new(txt)
|
||||
.block(
|
||||
@ -290,8 +309,8 @@ impl Status {
|
||||
}
|
||||
}
|
||||
|
||||
fn repo_state_unclean() -> bool {
|
||||
if let Ok(state) = sync::repo_state(CWD) {
|
||||
fn repo_state_unclean(&self) -> bool {
|
||||
if let Ok(state) = sync::repo_state(&self.repo.borrow()) {
|
||||
if state != RepoState::Clean {
|
||||
return true;
|
||||
}
|
||||
@ -497,7 +516,10 @@ impl Status {
|
||||
|
||||
/// called after confirmation
|
||||
pub fn reset(&mut self, item: &ResetItem) -> bool {
|
||||
if let Err(e) = sync::reset_workdir(CWD, item.path.as_str()) {
|
||||
if let Err(e) = sync::reset_workdir(
|
||||
&self.repo.borrow(),
|
||||
item.path.as_str(),
|
||||
) {
|
||||
self.queue.push(InternalEvent::ShowErrorMsg(format!(
|
||||
"reset failed:\n{}",
|
||||
e
|
||||
@ -542,15 +564,18 @@ impl Status {
|
||||
try_or_popup!(
|
||||
self,
|
||||
"undo commit failed:",
|
||||
sync::utils::undo_last_commit(CWD)
|
||||
sync::utils::undo_last_commit(&self.repo.borrow())
|
||||
);
|
||||
}
|
||||
|
||||
fn branch_compare(&mut self) {
|
||||
self.git_branch_state =
|
||||
self.git_branch_name.last().and_then(|branch| {
|
||||
sync::branch_compare_upstream(CWD, branch.as_str())
|
||||
.ok()
|
||||
sync::branch_compare_upstream(
|
||||
&self.repo.borrow(),
|
||||
branch.as_str(),
|
||||
)
|
||||
.ok()
|
||||
});
|
||||
}
|
||||
|
||||
@ -560,25 +585,31 @@ impl Status {
|
||||
.map_or(true, |state| state.ahead > 0)
|
||||
}
|
||||
|
||||
fn can_abort_merge() -> bool {
|
||||
sync::repo_state(CWD).unwrap_or(RepoState::Clean)
|
||||
fn can_abort_merge(&self) -> bool {
|
||||
sync::repo_state(&self.repo.borrow())
|
||||
.unwrap_or(RepoState::Clean)
|
||||
== RepoState::Merge
|
||||
}
|
||||
|
||||
fn pending_rebase() -> bool {
|
||||
sync::repo_state(CWD).unwrap_or(RepoState::Clean)
|
||||
fn pending_rebase(&self) -> bool {
|
||||
sync::repo_state(&self.repo.borrow())
|
||||
.unwrap_or(RepoState::Clean)
|
||||
== RepoState::Rebase
|
||||
}
|
||||
|
||||
pub fn abort_merge(&self) {
|
||||
try_or_popup!(self, "abort merge", sync::abort_merge(CWD));
|
||||
try_or_popup!(
|
||||
self,
|
||||
"abort merge",
|
||||
sync::abort_merge(&self.repo.borrow())
|
||||
);
|
||||
}
|
||||
|
||||
pub fn abort_rebase(&self) {
|
||||
try_or_popup!(
|
||||
self,
|
||||
"abort rebase",
|
||||
sync::abort_pending_rebase(CWD)
|
||||
sync::abort_pending_rebase(&self.repo.borrow())
|
||||
);
|
||||
}
|
||||
|
||||
@ -586,7 +617,7 @@ impl Status {
|
||||
try_or_popup!(
|
||||
self,
|
||||
"continue rebase",
|
||||
sync::continue_pending_rebase(CWD)
|
||||
sync::continue_pending_rebase(&self.repo.borrow())
|
||||
);
|
||||
}
|
||||
|
||||
@ -637,7 +668,7 @@ impl Status {
|
||||
fn can_commit(&self) -> bool {
|
||||
self.index.focused()
|
||||
&& !self.index.is_empty()
|
||||
&& !Self::pending_rebase()
|
||||
&& !self.pending_rebase()
|
||||
}
|
||||
}
|
||||
|
||||
@ -694,25 +725,25 @@ impl Component for Status {
|
||||
out.push(CommandInfo::new(
|
||||
strings::commands::undo_commit(&self.key_config),
|
||||
true,
|
||||
(!Self::pending_rebase() && !focus_on_diff)
|
||||
(!self.pending_rebase() && !focus_on_diff)
|
||||
|| force_all,
|
||||
));
|
||||
|
||||
out.push(CommandInfo::new(
|
||||
strings::commands::abort_merge(&self.key_config),
|
||||
true,
|
||||
Self::can_abort_merge() || force_all,
|
||||
self.can_abort_merge() || force_all,
|
||||
));
|
||||
|
||||
out.push(CommandInfo::new(
|
||||
strings::commands::continue_rebase(&self.key_config),
|
||||
true,
|
||||
Self::pending_rebase() || force_all,
|
||||
self.pending_rebase() || force_all,
|
||||
));
|
||||
out.push(CommandInfo::new(
|
||||
strings::commands::abort_rebase(&self.key_config),
|
||||
true,
|
||||
Self::pending_rebase() || force_all,
|
||||
self.pending_rebase() || force_all,
|
||||
));
|
||||
}
|
||||
|
||||
@ -819,7 +850,7 @@ impl Component for Status {
|
||||
));
|
||||
Ok(EventState::Consumed)
|
||||
} else if k == self.key_config.keys.abort_merge
|
||||
&& Self::can_abort_merge()
|
||||
&& self.can_abort_merge()
|
||||
{
|
||||
self.queue.push(InternalEvent::ConfirmAction(
|
||||
Action::AbortMerge,
|
||||
@ -827,7 +858,7 @@ impl Component for Status {
|
||||
|
||||
Ok(EventState::Consumed)
|
||||
} else if k == self.key_config.keys.abort_merge
|
||||
&& Self::pending_rebase()
|
||||
&& self.pending_rebase()
|
||||
{
|
||||
self.queue.push(InternalEvent::ConfirmAction(
|
||||
Action::AbortRebase,
|
||||
@ -835,7 +866,7 @@ impl Component for Status {
|
||||
|
||||
Ok(EventState::Consumed)
|
||||
} else if k == self.key_config.keys.rebase_branch
|
||||
&& Self::pending_rebase()
|
||||
&& self.pending_rebase()
|
||||
{
|
||||
self.continue_rebase();
|
||||
self.queue.push(InternalEvent::Update(
|
||||
|
Loading…
Reference in New Issue
Block a user