feat(git): make fetch command asynchronous for improved performance #11
+26
-22
@@ -718,34 +718,38 @@ pub fn pull(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn fetch(
|
pub async fn fetch(
|
||||||
path: String,
|
path: String,
|
||||||
username: Option<String>,
|
username: Option<String>,
|
||||||
password: Option<String>,
|
password: Option<String>,
|
||||||
) -> Result<GitStatus, String> {
|
) -> Result<GitStatus, String> {
|
||||||
let repo = resolve_repo(&path)?;
|
tauri::async_runtime::spawn_blocking(move || -> Result<GitStatus, String> {
|
||||||
let fetch_args = ["fetch"];
|
let repo = resolve_repo(&path)?;
|
||||||
let output = match (username.as_deref(), password.as_deref()) {
|
let fetch_args = ["fetch"];
|
||||||
(Some(u), Some(p)) if !u.is_empty() || !p.is_empty() => {
|
let output = match (username.as_deref(), password.as_deref()) {
|
||||||
run_git_authenticated_output(&repo, fetch_args, u, p)?
|
(Some(u), Some(p)) if !u.is_empty() || !p.is_empty() => {
|
||||||
|
run_git_authenticated_output(&repo, fetch_args, u, p)?
|
||||||
|
}
|
||||||
|
_ => git_command()
|
||||||
|
.arg("-C")
|
||||||
|
.arg(&repo)
|
||||||
|
.args(fetch_args)
|
||||||
|
.output()
|
||||||
|
.map_err(|err| format!("Could not start Git. Is Git installed? {err}"))?,
|
||||||
|
};
|
||||||
|
|
||||||
|
if output.status.success() {
|
||||||
|
return status_for_repo(&repo);
|
||||||
}
|
}
|
||||||
_ => git_command()
|
|
||||||
.arg("-C")
|
|
||||||
.arg(&repo)
|
|
||||||
.args(fetch_args)
|
|
||||||
.output()
|
|
||||||
.map_err(|err| format!("Could not start Git. Is Git installed? {err}"))?,
|
|
||||||
};
|
|
||||||
|
|
||||||
if output.status.success() {
|
let details = command_output_details(&output);
|
||||||
return status_for_repo(&repo);
|
if is_auth_error(&details) {
|
||||||
}
|
return Err(format!("AUTH_FAILED:{details}"));
|
||||||
|
}
|
||||||
let details = command_output_details(&output);
|
Err(format!("Git command failed: {details}"))
|
||||||
if is_auth_error(&details) {
|
})
|
||||||
return Err(format!("AUTH_FAILED:{details}"));
|
.await
|
||||||
}
|
.map_err(|err| format!("Could not fetch repository: {err}"))?
|
||||||
Err(format!("Git command failed: {details}"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
|||||||
+4
-4
@@ -189,8 +189,10 @@
|
|||||||
const AUTO_REFRESH_INTERVAL = 4000;
|
const AUTO_REFRESH_INTERVAL = 4000;
|
||||||
let autoRefreshTimer: ReturnType<typeof setInterval> | undefined;
|
let autoRefreshTimer: ReturnType<typeof setInterval> | undefined;
|
||||||
const BACKGROUND_FETCH_INTERVAL = 180_000;
|
const BACKGROUND_FETCH_INTERVAL = 180_000;
|
||||||
|
const BACKGROUND_FETCH_AFTER_SWITCH_GRACE_MS = 30_000;
|
||||||
let backgroundFetchTimer: ReturnType<typeof setInterval> | undefined;
|
let backgroundFetchTimer: ReturnType<typeof setInterval> | undefined;
|
||||||
let backgroundFetchInFlight = false;
|
let backgroundFetchInFlight = false;
|
||||||
|
let lastRepoSwitchAt = 0;
|
||||||
let updateToastOpen = false;
|
let updateToastOpen = false;
|
||||||
let updateToastState: UpdateToastState = "available";
|
let updateToastState: UpdateToastState = "available";
|
||||||
let pendingUpdate: Update | null = null;
|
let pendingUpdate: Update | null = null;
|
||||||
@@ -264,6 +266,7 @@
|
|||||||
// Push buttons instead, not as a background popup.
|
// Push buttons instead, not as a background popup.
|
||||||
async function backgroundFetchTick() {
|
async function backgroundFetchTick() {
|
||||||
if (!autoRefreshEnabled || activeView !== "repository" || !activeRepoPath || isBusy || backgroundFetchInFlight) return;
|
if (!autoRefreshEnabled || activeView !== "repository" || !activeRepoPath || isBusy || backgroundFetchInFlight) return;
|
||||||
|
if (Date.now() - lastRepoSwitchAt < BACKGROUND_FETCH_AFTER_SWITCH_GRACE_MS) return;
|
||||||
backgroundFetchInFlight = true;
|
backgroundFetchInFlight = true;
|
||||||
try {
|
try {
|
||||||
await fetchRemote(activeRepoPath);
|
await fetchRemote(activeRepoPath);
|
||||||
@@ -869,11 +872,8 @@
|
|||||||
await refreshBranchList(activeRepoPath, bundle.branches);
|
await refreshBranchList(activeRepoPath, bundle.branches);
|
||||||
await refreshCommitHistory(activeRepoPath, bundle.commits);
|
await refreshCommitHistory(activeRepoPath, bundle.commits);
|
||||||
await refreshExplorerFiles(activeRepoPath, bundle.files);
|
await refreshExplorerFiles(activeRepoPath, bundle.files);
|
||||||
|
lastRepoSwitchAt = Date.now();
|
||||||
});
|
});
|
||||||
// Silent background fetch on open, same as the periodic tick — no "Fetching" indicator,
|
|
||||||
// just brings ahead/behind (and the taskbar badge) up to date without blocking the
|
|
||||||
// repo-open flow.
|
|
||||||
void backgroundFetchTick();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function chooseRepositoryFolder() {
|
async function chooseRepositoryFolder() {
|
||||||
|
|||||||
Reference in New Issue
Block a user