Merge branch 'new_featrues'
This commit is contained in:
Generated
+1
@@ -2537,6 +2537,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"commit_ai",
|
||||
"keyring",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
|
||||
@@ -21,6 +21,7 @@ tauri-plugin-aptabase = "1.0"
|
||||
keyring = { version = "3", features = ["apple-native", "windows-native", "async-secret-service", "crypto-rust", "async-io"] }
|
||||
commit_ai = { path = "crates/commit_ai" }
|
||||
tokio = "1.52.3"
|
||||
log = "0.4"
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2", features = [] }
|
||||
|
||||
+344
-15
@@ -51,6 +51,14 @@ pub struct GitStatus {
|
||||
pub clean: bool,
|
||||
pub rebase_in_progress: bool,
|
||||
pub cherry_pick_in_progress: bool,
|
||||
pub merge_in_progress: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||||
pub struct GitRemote {
|
||||
pub name: String,
|
||||
pub fetch_url: String,
|
||||
pub push_url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||||
@@ -361,6 +369,34 @@ pub fn open_repository(path: String) -> Result<GitStatus, String> {
|
||||
status_for_repo(&repo)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn init_repository(path: String, initial_branch: Option<String>) -> Result<GitStatus, String> {
|
||||
let path = PathBuf::from(path.trim());
|
||||
if path.as_os_str().is_empty() {
|
||||
return Err("Repository path must not be empty.".to_string());
|
||||
}
|
||||
fs::create_dir_all(&path)
|
||||
.map_err(|err| format!("Could not create repository folder: {err}"))?;
|
||||
let branch = initial_branch.unwrap_or_else(|| "main".to_string());
|
||||
let branch = branch.trim();
|
||||
if branch.is_empty() {
|
||||
return Err("Initial branch must not be empty.".to_string());
|
||||
}
|
||||
let output = git_command()
|
||||
.arg("-C")
|
||||
.arg(&path)
|
||||
.args(["init", "-b", branch])
|
||||
.output()
|
||||
.map_err(|err| format!("Could not start Git. Is Git installed? {err}"))?;
|
||||
if !output.status.success() {
|
||||
return Err(format!(
|
||||
"Could not initialize repository: {}",
|
||||
command_output_details(&output)
|
||||
));
|
||||
}
|
||||
status_for_repo(&path)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn open_repo_in_explorer(path: String) -> Result<(), String> {
|
||||
let repo = resolve_repo(&path)?;
|
||||
@@ -459,6 +495,125 @@ pub fn list_branches(path: String) -> Result<Vec<GitBranch>, String> {
|
||||
branches_for_repo(&repo)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn list_remotes(path: String) -> Result<Vec<GitRemote>, String> {
|
||||
log::info!(target: "gitty::remote", "list_remotes invoked: path={path:?}");
|
||||
let repo = resolve_repo(&path)?;
|
||||
let names = run_git(&repo, ["remote"])?;
|
||||
Ok(String::from_utf8_lossy(&names)
|
||||
.lines()
|
||||
.filter_map(|line| {
|
||||
let name = line.trim();
|
||||
if name.is_empty() {
|
||||
return None;
|
||||
}
|
||||
Some(GitRemote {
|
||||
name: name.to_string(),
|
||||
fetch_url: remote_url_for(&repo, name).unwrap_or_default(),
|
||||
push_url: remote_push_url_for(&repo, name).unwrap_or_default(),
|
||||
})
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn add_remote(path: String, name: String, url: String) -> Result<Vec<GitRemote>, String> {
|
||||
let repo = resolve_repo(&path)?;
|
||||
let name = validate_remote_name(&repo, &name, false)?;
|
||||
let url = validate_remote_url(&url)?;
|
||||
run_git(&repo, ["remote", "add", name.as_str(), url.as_str()])?;
|
||||
list_remotes(path)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn update_remote(path: String, name: String, url: String) -> Result<Vec<GitRemote>, String> {
|
||||
let repo = resolve_repo(&path)?;
|
||||
let name = validate_remote_name(&repo, &name, true)?;
|
||||
let url = validate_remote_url(&url)?;
|
||||
run_git(&repo, ["remote", "set-url", name.as_str(), url.as_str()])?;
|
||||
list_remotes(path)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn remove_remote(path: String, name: String) -> Result<Vec<GitRemote>, String> {
|
||||
log::info!(target: "gitty::remote", "remove_remote invoked: path={path:?}, name={name:?}");
|
||||
let result = (|| {
|
||||
let repo = resolve_repo(&path)?;
|
||||
log::info!(target: "gitty::remote", "remove_remote resolved repository: {}", repo.display());
|
||||
let name = validate_remote_name(&repo, &name, true)?;
|
||||
log::info!(target: "gitty::remote", "remove_remote validated remote: {name}");
|
||||
run_git(&repo, ["remote", "remove", name.as_str()])?;
|
||||
log::info!(target: "gitty::remote", "remove_remote git command succeeded: {name}");
|
||||
list_remotes(path)
|
||||
})();
|
||||
match &result {
|
||||
Ok(remotes) => {
|
||||
log::info!(target: "gitty::remote", "remove_remote completed; remaining={:?}", remotes.iter().map(|remote| remote.name.as_str()).collect::<Vec<_>>())
|
||||
}
|
||||
Err(error) => log::error!(target: "gitty::remote", "remove_remote failed: {error}"),
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn set_branch_upstream(
|
||||
path: String,
|
||||
branch: String,
|
||||
upstream: Option<String>,
|
||||
) -> Result<GitStatus, String> {
|
||||
let repo = resolve_repo(&path)?;
|
||||
let branch = validate_existing_local_branch_name(&repo, &branch)?;
|
||||
match upstream
|
||||
.map(|v| v.trim().to_string())
|
||||
.filter(|v| !v.is_empty())
|
||||
{
|
||||
Some(upstream) => {
|
||||
if !ref_exists(&repo, &format!("refs/remotes/{upstream}"))? {
|
||||
return Err(format!("Remote branch '{upstream}' was not found."));
|
||||
}
|
||||
run_git(
|
||||
&repo,
|
||||
[
|
||||
"branch",
|
||||
"--set-upstream-to",
|
||||
upstream.as_str(),
|
||||
branch.as_str(),
|
||||
],
|
||||
)?;
|
||||
}
|
||||
None => {
|
||||
run_git(&repo, ["branch", "--unset-upstream", branch.as_str()])?;
|
||||
}
|
||||
}
|
||||
status_for_repo(&repo)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn delete_remote_branch(
|
||||
path: String,
|
||||
remote: String,
|
||||
branch: String,
|
||||
) -> Result<GitStatus, String> {
|
||||
log::info!(target: "gitty::remote", "delete_remote_branch invoked: path={path:?}, remote={remote:?}, branch={branch:?}");
|
||||
let result = (|| {
|
||||
let repo = resolve_repo(&path)?;
|
||||
let remote = validate_remote_name(&repo, &remote, true)?;
|
||||
let branch = branch.trim();
|
||||
if branch.is_empty() || branch.starts_with('-') {
|
||||
return Err("Invalid remote branch name.".to_string());
|
||||
}
|
||||
run_git(&repo, ["check-ref-format", "--branch", branch])?;
|
||||
log::info!(target: "gitty::remote", "deleting remote branch with git push: {remote}/{branch}");
|
||||
run_git(&repo, ["push", remote.as_str(), "--delete", branch])?;
|
||||
log::info!(target: "gitty::remote", "remote branch deleted successfully: {remote}/{branch}");
|
||||
status_for_repo(&repo)
|
||||
})();
|
||||
if let Err(error) = &result {
|
||||
log::error!(target: "gitty::remote", "delete_remote_branch failed: {error}");
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn list_stashes(path: String) -> Result<Vec<GitStash>, String> {
|
||||
let repo = resolve_repo(&path)?;
|
||||
@@ -1409,18 +1564,43 @@ pub async fn pull(
|
||||
path: String,
|
||||
username: Option<String>,
|
||||
password: Option<String>,
|
||||
strategy: Option<String>,
|
||||
remote: Option<String>,
|
||||
branch: Option<String>,
|
||||
) -> Result<GitStatus, String> {
|
||||
tauri::async_runtime::spawn_blocking(move || -> Result<GitStatus, String> {
|
||||
let repo = resolve_repo(&path)?;
|
||||
let pull_args = ["pull", "--no-rebase", "--ff", "--no-edit"];
|
||||
let strategy = strategy.as_deref().unwrap_or("merge");
|
||||
let mut pull_args = vec![OsString::from("pull")];
|
||||
match strategy {
|
||||
"merge" => {
|
||||
pull_args.extend([OsString::from("--no-rebase"), OsString::from("--no-edit")])
|
||||
}
|
||||
"rebase" => pull_args.push(OsString::from("--rebase")),
|
||||
"ff-only" => pull_args.push(OsString::from("--ff-only")),
|
||||
_ => return Err("Unknown pull strategy.".to_string()),
|
||||
}
|
||||
if let Some(remote) = remote
|
||||
.map(|v| v.trim().to_string())
|
||||
.filter(|v| !v.is_empty())
|
||||
{
|
||||
validate_remote_name(&repo, &remote, true)?;
|
||||
pull_args.push(remote.into());
|
||||
if let Some(branch) = branch
|
||||
.map(|v| v.trim().to_string())
|
||||
.filter(|v| !v.is_empty())
|
||||
{
|
||||
pull_args.push(branch.into());
|
||||
}
|
||||
}
|
||||
let output = match (username.as_deref(), password.as_deref()) {
|
||||
(Some(u), Some(p)) if !u.is_empty() || !p.is_empty() => {
|
||||
run_git_authenticated_output(&repo, pull_args, u, p)?
|
||||
run_git_authenticated_output(&repo, pull_args.clone(), u, p)?
|
||||
}
|
||||
_ => git_command()
|
||||
.arg("-C")
|
||||
.arg(&repo)
|
||||
.args(pull_args)
|
||||
.args(&pull_args)
|
||||
.output()
|
||||
.map_err(|err| format!("Could not start Git. Is Git installed? {err}"))?,
|
||||
};
|
||||
@@ -1449,18 +1629,30 @@ pub async fn fetch(
|
||||
path: String,
|
||||
username: Option<String>,
|
||||
password: Option<String>,
|
||||
prune: Option<bool>,
|
||||
remote: Option<String>,
|
||||
) -> Result<GitStatus, String> {
|
||||
tauri::async_runtime::spawn_blocking(move || -> Result<GitStatus, String> {
|
||||
let repo = resolve_repo(&path)?;
|
||||
let fetch_args = ["fetch"];
|
||||
let mut fetch_args = vec![OsString::from("fetch")];
|
||||
if prune.unwrap_or(false) {
|
||||
fetch_args.push(OsString::from("--prune"));
|
||||
}
|
||||
if let Some(remote) = remote
|
||||
.map(|v| v.trim().to_string())
|
||||
.filter(|v| !v.is_empty())
|
||||
{
|
||||
validate_remote_name(&repo, &remote, true)?;
|
||||
fetch_args.push(remote.into());
|
||||
}
|
||||
let output = match (username.as_deref(), password.as_deref()) {
|
||||
(Some(u), Some(p)) if !u.is_empty() || !p.is_empty() => {
|
||||
run_git_authenticated_output(&repo, fetch_args, u, p)?
|
||||
run_git_authenticated_output(&repo, fetch_args.clone(), u, p)?
|
||||
}
|
||||
_ => git_command()
|
||||
.arg("-C")
|
||||
.arg(&repo)
|
||||
.args(fetch_args)
|
||||
.args(&fetch_args)
|
||||
.output()
|
||||
.map_err(|err| format!("Could not start Git. Is Git installed? {err}"))?,
|
||||
};
|
||||
@@ -1484,10 +1676,15 @@ pub async fn push(
|
||||
path: String,
|
||||
username: Option<String>,
|
||||
password: Option<String>,
|
||||
force_with_lease: Option<bool>,
|
||||
remote: Option<String>,
|
||||
) -> Result<GitStatus, String> {
|
||||
tauri::async_runtime::spawn_blocking(move || -> Result<GitStatus, String> {
|
||||
let repo = resolve_repo(&path)?;
|
||||
let push_args = push_args_for_repo(&repo)?;
|
||||
let mut push_args = push_args_for_repo_to(&repo, remote.as_deref())?;
|
||||
if force_with_lease.unwrap_or(false) {
|
||||
push_args.insert(1, OsString::from("--force-with-lease"));
|
||||
}
|
||||
match (username.as_deref(), password.as_deref()) {
|
||||
(Some(u), Some(p)) if !u.is_empty() || !p.is_empty() => {
|
||||
run_git_authenticated(&repo, push_args, u, p)?;
|
||||
@@ -1557,6 +1754,43 @@ fn remote_url_for(repo: &Path, remote: &str) -> Option<String> {
|
||||
if url.is_empty() { None } else { Some(url) }
|
||||
}
|
||||
|
||||
fn remote_push_url_for(repo: &Path, remote: &str) -> Option<String> {
|
||||
let out = git_command()
|
||||
.arg("-C")
|
||||
.arg(repo)
|
||||
.args(["remote", "get-url", "--push", remote])
|
||||
.output()
|
||||
.ok()?;
|
||||
if !out.status.success() {
|
||||
return None;
|
||||
}
|
||||
let url = String::from_utf8_lossy(&out.stdout).trim().to_string();
|
||||
if url.is_empty() { None } else { Some(url) }
|
||||
}
|
||||
|
||||
fn validate_remote_url(url: &str) -> Result<String, String> {
|
||||
let url = url.trim();
|
||||
if url.is_empty() || url.starts_with('-') {
|
||||
return Err("Remote URL must not be empty.".to_string());
|
||||
}
|
||||
Ok(url.to_string())
|
||||
}
|
||||
|
||||
fn validate_remote_name(repo: &Path, name: &str, must_exist: bool) -> Result<String, String> {
|
||||
let name = name.trim();
|
||||
if name.is_empty() || name.starts_with('-') || name.chars().any(char::is_whitespace) {
|
||||
return Err("Invalid remote name.".to_string());
|
||||
}
|
||||
let exists = remote_url_for(repo, name).is_some();
|
||||
if must_exist && !exists {
|
||||
return Err(format!("Remote '{name}' was not found."));
|
||||
}
|
||||
if !must_exist && exists {
|
||||
return Err(format!("Remote '{name}' already exists."));
|
||||
}
|
||||
Ok(name.to_string())
|
||||
}
|
||||
|
||||
fn upstream_remote_name(repo: &Path) -> Option<String> {
|
||||
let branch = current_branch_name(repo).ok()?;
|
||||
let out = git_command()
|
||||
@@ -1609,7 +1843,25 @@ fn initial_push_remote_name(repo: &Path) -> Result<String, String> {
|
||||
.ok_or_else(|| "This branch has no upstream and no remote is configured.".to_string())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn push_args_for_repo(repo: &Path) -> Result<Vec<OsString>, String> {
|
||||
push_args_for_repo_to(repo, None)
|
||||
}
|
||||
|
||||
fn push_args_for_repo_to(
|
||||
repo: &Path,
|
||||
requested_remote: Option<&str>,
|
||||
) -> Result<Vec<OsString>, String> {
|
||||
if let Some(remote) = requested_remote.map(str::trim).filter(|v| !v.is_empty()) {
|
||||
let remote = validate_remote_name(repo, remote, true)?;
|
||||
let branch = current_branch_name(repo)?;
|
||||
return Ok(vec![
|
||||
OsString::from("push"),
|
||||
OsString::from("--set-upstream"),
|
||||
remote.into(),
|
||||
branch.into(),
|
||||
]);
|
||||
}
|
||||
if branch_has_upstream(repo) {
|
||||
return Ok(vec![OsString::from("push")]);
|
||||
}
|
||||
@@ -1669,7 +1921,11 @@ pub fn cred_delete(key: String) -> Result<(), String> {
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn merge_branch(path: String, branch: String) -> Result<GitStatus, String> {
|
||||
pub async fn merge_branch(
|
||||
path: String,
|
||||
branch: String,
|
||||
strategy: Option<String>,
|
||||
) -> Result<GitStatus, String> {
|
||||
tauri::async_runtime::spawn_blocking(move || -> Result<GitStatus, String> {
|
||||
let repo = resolve_repo(&path)?;
|
||||
let branch = branch.trim();
|
||||
@@ -1677,10 +1933,19 @@ pub async fn merge_branch(path: String, branch: String) -> Result<GitStatus, Str
|
||||
return Err("Branch name must not be empty.".to_string());
|
||||
}
|
||||
|
||||
let mut args = vec!["merge", "--no-edit"];
|
||||
match strategy.as_deref().unwrap_or("default") {
|
||||
"default" => {}
|
||||
"squash" => args.push("--squash"),
|
||||
"ff-only" => args.push("--ff-only"),
|
||||
"no-ff" => args.push("--no-ff"),
|
||||
_ => return Err("Unknown merge strategy.".to_string()),
|
||||
}
|
||||
args.push(branch);
|
||||
let output = git_command()
|
||||
.arg("-C")
|
||||
.arg(&repo)
|
||||
.args(["merge", "--no-edit", branch])
|
||||
.args(args)
|
||||
.output()
|
||||
.map_err(|err| format!("Could not start Git. Is Git installed? {err}"))?;
|
||||
|
||||
@@ -1712,6 +1977,52 @@ pub async fn merge_branch(path: String, branch: String) -> Result<GitStatus, Str
|
||||
.map_err(|err| format!("Could not merge: {err}"))?
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn merge_continue(path: String) -> Result<GitStatus, String> {
|
||||
let repo = resolve_repo(&path)?;
|
||||
if !merge_in_progress(&repo) {
|
||||
return Err("No merge is in progress.".to_string());
|
||||
}
|
||||
if has_unresolved_conflicts(&status_for_repo(&repo)?) {
|
||||
return Err("Resolve all conflicts before continuing the merge.".to_string());
|
||||
}
|
||||
run_git(&repo, ["commit", "--no-edit"])?;
|
||||
status_for_repo(&repo)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn merge_abort(path: String) -> Result<GitStatus, String> {
|
||||
let repo = resolve_repo(&path)?;
|
||||
if !merge_in_progress(&repo) {
|
||||
return Err("No merge is in progress.".to_string());
|
||||
}
|
||||
run_git(&repo, ["merge", "--abort"])?;
|
||||
status_for_repo(&repo)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn revert_commit(path: String, commit: String) -> Result<GitStatus, String> {
|
||||
let repo = resolve_repo(&path)?;
|
||||
let commit = verify_commit(&repo, &commit)?;
|
||||
let output = git_command()
|
||||
.arg("-C")
|
||||
.arg(&repo)
|
||||
.args(["revert", "--no-edit", commit.as_str()])
|
||||
.output()
|
||||
.map_err(|err| format!("Could not start Git. Is Git installed? {err}"))?;
|
||||
if output.status.success() {
|
||||
return status_for_repo(&repo);
|
||||
}
|
||||
let status = status_for_repo(&repo)?;
|
||||
if has_unresolved_conflicts(&status) {
|
||||
return Ok(status);
|
||||
}
|
||||
Err(format!(
|
||||
"Revert failed: {}",
|
||||
command_output_details(&output)
|
||||
))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn rebase_branch(path: String, branch: String) -> Result<GitStatus, String> {
|
||||
tauri::async_runtime::spawn_blocking(move || -> Result<GitStatus, String> {
|
||||
@@ -3118,6 +3429,7 @@ fn status_for_repo(repo: &Path) -> Result<GitStatus, String> {
|
||||
files,
|
||||
rebase_in_progress: rebase_in_progress(repo),
|
||||
cherry_pick_in_progress: cherry_pick_in_progress(repo),
|
||||
merge_in_progress: merge_in_progress(repo),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3129,6 +3441,10 @@ fn cherry_pick_in_progress(repo: &Path) -> bool {
|
||||
git_path_exists(repo, "CHERRY_PICK_HEAD")
|
||||
}
|
||||
|
||||
fn merge_in_progress(repo: &Path) -> bool {
|
||||
git_path_exists(repo, "MERGE_HEAD")
|
||||
}
|
||||
|
||||
fn git_path_exists(repo: &Path, name: &str) -> bool {
|
||||
let Ok(output) = run_git(repo, ["rev-parse", "--git-path", name]) else {
|
||||
return false;
|
||||
@@ -5633,9 +5949,16 @@ mod tests {
|
||||
],
|
||||
);
|
||||
|
||||
let status = pull(repo.path.to_string_lossy().to_string(), None, None)
|
||||
.await
|
||||
.unwrap();
|
||||
let status = pull(
|
||||
repo.path.to_string_lossy().to_string(),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(status.clean, "{:?}", status.files);
|
||||
assert!(repo.path.join("remote.txt").exists());
|
||||
@@ -5706,9 +6029,15 @@ mod tests {
|
||||
["remote", "add", "origin", remote.path.to_str().unwrap()],
|
||||
);
|
||||
|
||||
let status = push(repo.path.to_string_lossy().to_string(), None, None)
|
||||
.await
|
||||
.unwrap();
|
||||
let status = push(
|
||||
repo.path.to_string_lossy().to_string(),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
status.upstream.as_deref(),
|
||||
|
||||
+53
-10
@@ -5,24 +5,56 @@ mod git;
|
||||
|
||||
use badge::set_sync_badge;
|
||||
use git::{
|
||||
SearchCancellationState, amend_commit, apply_file_patch, cancel_code_search,
|
||||
SearchCancellationState, add_remote, amend_commit, apply_file_patch, cancel_code_search,
|
||||
cancel_file_history, checkout_branch, cherry_pick_abort, cherry_pick_commit,
|
||||
cherry_pick_continue, clone_repository, commit, commit_ai_generate, commit_ai_load,
|
||||
commit_ai_local_models, commit_ai_review, commit_ai_status, compare_commits,
|
||||
compare_file_to_head, compare_file_to_parent, create_branch, create_tag, cred_delete,
|
||||
cred_load, cred_save, delete_branch, delete_tag, diff_file_against_working_tree, fetch,
|
||||
get_file_blame, get_file_patch, get_remote_url, get_status, last_commit_message, list_branches,
|
||||
list_commits, list_file_history, list_interactive_rebase_commits, list_reflog,
|
||||
list_repository_files, list_stashes, list_tags, merge_branch, open_repo_in_explorer,
|
||||
open_repository, open_repository_bundle, open_repository_file, pull, push, push_tag,
|
||||
read_conflict, rebase_abort, rebase_branch, rebase_continue, rename_branch, resolve_conflict,
|
||||
resolve_conflict_side, restore_file_from_commit, restore_files, restore_reflog_entry,
|
||||
restore_to_commit, run_sequence_editor_if_requested, search_code_introductions, stage_files,
|
||||
cred_load, cred_save, delete_branch, delete_remote_branch, delete_tag,
|
||||
diff_file_against_working_tree, fetch, get_file_blame, get_file_patch, get_remote_url,
|
||||
get_status, init_repository, last_commit_message, list_branches, list_commits,
|
||||
list_file_history, list_interactive_rebase_commits, list_reflog, list_remotes,
|
||||
list_repository_files, list_stashes, list_tags, merge_abort, merge_branch, merge_continue,
|
||||
open_repo_in_explorer, open_repository, open_repository_bundle, open_repository_file, pull,
|
||||
push, push_tag, read_conflict, rebase_abort, rebase_branch, rebase_continue, remove_remote,
|
||||
rename_branch, resolve_conflict, resolve_conflict_side, restore_file_from_commit,
|
||||
restore_files, restore_reflog_entry, restore_to_commit, revert_commit,
|
||||
run_sequence_editor_if_requested, search_code_introductions, set_branch_upstream, stage_files,
|
||||
start_interactive_rebase, stash_apply, stash_drop, stash_pop, stash_push, undo_last_commit,
|
||||
unstage_files,
|
||||
unstage_files, update_remote,
|
||||
};
|
||||
use tauri::Manager;
|
||||
|
||||
struct ConsoleLogger;
|
||||
|
||||
impl log::Log for ConsoleLogger {
|
||||
fn enabled(&self, metadata: &log::Metadata<'_>) -> bool {
|
||||
metadata.level() <= log::Level::Info
|
||||
}
|
||||
|
||||
fn log(&self, record: &log::Record<'_>) {
|
||||
if self.enabled(record.metadata()) {
|
||||
eprintln!(
|
||||
"[{}] [{}] {}",
|
||||
record.level(),
|
||||
record.target(),
|
||||
record.args()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&self) {}
|
||||
}
|
||||
|
||||
static CONSOLE_LOGGER: ConsoleLogger = ConsoleLogger;
|
||||
|
||||
fn init_console_logging() {
|
||||
if log::set_logger(&CONSOLE_LOGGER).is_ok() {
|
||||
log::set_max_level(log::LevelFilter::Info);
|
||||
log::info!(target: "gitty", "Rust console logging initialized");
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn close_splashscreen(app: tauri::AppHandle) -> Result<(), String> {
|
||||
if let Some(window) = app.get_webview_window("splashscreen") {
|
||||
@@ -45,6 +77,7 @@ fn close_splashscreen(app: tauri::AppHandle) -> Result<(), String> {
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
init_console_logging();
|
||||
if let Some(result) = run_sequence_editor_if_requested() {
|
||||
if let Err(error) = result {
|
||||
eprintln!("{error}");
|
||||
@@ -82,11 +115,18 @@ async fn main() {
|
||||
builder
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
open_repository,
|
||||
init_repository,
|
||||
clone_repository,
|
||||
open_repo_in_explorer,
|
||||
open_repository_file,
|
||||
get_status,
|
||||
list_branches,
|
||||
list_remotes,
|
||||
add_remote,
|
||||
update_remote,
|
||||
remove_remote,
|
||||
set_branch_upstream,
|
||||
delete_remote_branch,
|
||||
list_stashes,
|
||||
checkout_branch,
|
||||
create_branch,
|
||||
@@ -124,6 +164,9 @@ async fn main() {
|
||||
restore_to_commit,
|
||||
restore_file_from_commit,
|
||||
merge_branch,
|
||||
merge_continue,
|
||||
merge_abort,
|
||||
revert_commit,
|
||||
rebase_branch,
|
||||
rebase_continue,
|
||||
rebase_abort,
|
||||
|
||||
Reference in New Issue
Block a user