mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-18 14:31:30 +03:00
Merge pull request #3725 from gitbutlerapp/global-askpass
make askpass broker a global
This commit is contained in:
commit
190a75eb5b
@ -5,6 +5,31 @@ use tokio::sync::{oneshot, Mutex};
|
||||
|
||||
use crate::{id::Id, virtual_branches::BranchId};
|
||||
|
||||
static mut GLOBAL_ASKPASS_BROKER: Option<AskpassBroker> = None;
|
||||
|
||||
/// Initialize the global askpass broker.
|
||||
///
|
||||
/// # Safety
|
||||
/// This function **must** be called **at least once**, from only one thread at a time,
|
||||
/// before any other function from this module is called. **Calls to [`get`] before [`init`] will panic.**
|
||||
///
|
||||
/// This function is **NOT** thread safe.
|
||||
pub unsafe fn init(submit_prompt: impl Fn(PromptEvent<Context>) + Send + Sync + 'static) {
|
||||
GLOBAL_ASKPASS_BROKER.replace(AskpassBroker::init(submit_prompt));
|
||||
}
|
||||
|
||||
/// Get the global askpass broker.
|
||||
///
|
||||
/// # Panics
|
||||
/// Will panic if [`init`] was not called before this function.
|
||||
pub fn get_broker() -> &'static AskpassBroker {
|
||||
unsafe {
|
||||
GLOBAL_ASKPASS_BROKER
|
||||
.as_ref()
|
||||
.expect("askpass broker not initialized")
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AskpassRequest {
|
||||
sender: oneshot::Sender<Option<String>>,
|
||||
}
|
||||
|
@ -9,9 +9,7 @@ use anyhow::{Context, Result};
|
||||
use super::conflicts;
|
||||
use crate::error::{AnyhowContextExt, Code, ErrorWithContext};
|
||||
use crate::{
|
||||
askpass,
|
||||
askpass::AskpassBroker,
|
||||
error,
|
||||
askpass, error,
|
||||
git::{self, credentials::HelpError, Url},
|
||||
keys,
|
||||
projects::{self, AuthKey},
|
||||
@ -171,7 +169,7 @@ impl Repository {
|
||||
credentials: &git::credentials::Helper,
|
||||
remote_name: &str,
|
||||
branch_name: &str,
|
||||
askpass: Option<(AskpassBroker, Option<BranchId>)>,
|
||||
askpass: Option<Option<BranchId>>,
|
||||
) -> Result<()> {
|
||||
let target_branch_refname =
|
||||
git::Refname::from_str(&format!("refs/remotes/{}/{}", remote_name, branch_name))?;
|
||||
@ -184,14 +182,7 @@ impl Repository {
|
||||
let refname =
|
||||
git::RemoteRefname::from_str(&format!("refs/remotes/{remote_name}/{branch_name}",))?;
|
||||
|
||||
match self.push(
|
||||
&commit_id,
|
||||
&refname,
|
||||
false,
|
||||
credentials,
|
||||
None,
|
||||
askpass.clone(),
|
||||
) {
|
||||
match self.push(&commit_id, &refname, false, credentials, None, askpass) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => Err(anyhow::anyhow!(e.to_string())),
|
||||
}?;
|
||||
@ -446,7 +437,7 @@ impl Repository {
|
||||
with_force: bool,
|
||||
credentials: &git::credentials::Helper,
|
||||
refspec: Option<String>,
|
||||
askpass_broker: Option<(AskpassBroker, Option<BranchId>)>,
|
||||
askpass_broker: Option<Option<BranchId>>,
|
||||
) -> Result<(), RemoteError> {
|
||||
let refspec = refspec.unwrap_or_else(|| {
|
||||
if with_force {
|
||||
@ -545,7 +536,7 @@ impl Repository {
|
||||
&self,
|
||||
remote_name: &str,
|
||||
credentials: &git::credentials::Helper,
|
||||
askpass: Option<(AskpassBroker, String)>,
|
||||
askpass: Option<String>,
|
||||
) -> Result<(), RemoteError> {
|
||||
let refspec = format!("+refs/heads/*:refs/remotes/{}/*", remote_name);
|
||||
|
||||
@ -658,11 +649,11 @@ pub enum LogUntil {
|
||||
|
||||
async fn handle_git_prompt_push(
|
||||
prompt: String,
|
||||
askpass: Option<(AskpassBroker, Option<BranchId>)>,
|
||||
askpass: Option<Option<BranchId>>,
|
||||
) -> Option<String> {
|
||||
if let Some((askpass_broker, branch_id)) = askpass {
|
||||
if let Some(branch_id) = askpass {
|
||||
tracing::info!("received prompt for branch push {branch_id:?}: {prompt:?}");
|
||||
askpass_broker
|
||||
askpass::get_broker()
|
||||
.submit_prompt(prompt, askpass::Context::Push { branch_id })
|
||||
.await
|
||||
} else {
|
||||
@ -671,13 +662,10 @@ async fn handle_git_prompt_push(
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_git_prompt_fetch(
|
||||
prompt: String,
|
||||
askpass: Option<(AskpassBroker, String)>,
|
||||
) -> Option<String> {
|
||||
if let Some((askpass_broker, action)) = askpass {
|
||||
async fn handle_git_prompt_fetch(prompt: String, askpass: Option<String>) -> Option<String> {
|
||||
if let Some(action) = askpass {
|
||||
tracing::info!("received prompt for fetch with action {action:?}: {prompt:?}");
|
||||
askpass_broker
|
||||
askpass::get_broker()
|
||||
.submit_prompt(prompt, askpass::Context::Fetch { action })
|
||||
.await
|
||||
} else {
|
||||
|
@ -16,7 +16,6 @@ use super::{
|
||||
target, target_to_base_branch, BaseBranch, RemoteBranchFile, VirtualBranchesHandle,
|
||||
};
|
||||
use crate::{
|
||||
askpass::AskpassBroker,
|
||||
git, keys, project_repository,
|
||||
projects::{self, ProjectId},
|
||||
users,
|
||||
@ -336,7 +335,7 @@ impl Controller {
|
||||
project_id: &ProjectId,
|
||||
branch_id: &BranchId,
|
||||
with_force: bool,
|
||||
askpass: Option<(AskpassBroker, Option<BranchId>)>,
|
||||
askpass: Option<Option<BranchId>>,
|
||||
) -> Result<(), Error> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
@ -403,7 +402,7 @@ impl Controller {
|
||||
pub async fn fetch_from_target(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
askpass: Option<(AskpassBroker, String)>,
|
||||
askpass: Option<String>,
|
||||
) -> Result<BaseBranch, Error> {
|
||||
self.inner(project_id)
|
||||
.await
|
||||
@ -923,7 +922,7 @@ impl ControllerInner {
|
||||
project_id: &ProjectId,
|
||||
branch_id: &BranchId,
|
||||
with_force: bool,
|
||||
askpass: Option<(AskpassBroker, Option<BranchId>)>,
|
||||
askpass: Option<Option<BranchId>>,
|
||||
) -> Result<(), Error> {
|
||||
let _permit = self.semaphore.acquire().await;
|
||||
let helper = self.helper.clone();
|
||||
@ -1019,7 +1018,7 @@ impl ControllerInner {
|
||||
pub async fn fetch_from_target(
|
||||
&self,
|
||||
project_id: &ProjectId,
|
||||
askpass: Option<(AskpassBroker, String)>,
|
||||
askpass: Option<String>,
|
||||
) -> Result<BaseBranch, Error> {
|
||||
let project = self.projects.get(project_id)?;
|
||||
let mut project_repository = project_repository::Repository::open(&project)?;
|
||||
|
@ -27,7 +27,6 @@ use super::{
|
||||
use crate::git::diff::{diff_files_into_hunks, trees, FileDiff};
|
||||
use crate::virtual_branches::branch::HunkHash;
|
||||
use crate::{
|
||||
askpass::AskpassBroker,
|
||||
dedup::{dedup, dedup_fmt},
|
||||
git::{
|
||||
self,
|
||||
@ -2441,7 +2440,7 @@ pub fn push(
|
||||
branch_id: &BranchId,
|
||||
with_force: bool,
|
||||
credentials: &git::credentials::Helper,
|
||||
askpass: Option<(AskpassBroker, Option<BranchId>)>,
|
||||
askpass: Option<Option<BranchId>>,
|
||||
) -> Result<(), errors::PushError> {
|
||||
let vb_state = project_repository.project().virtual_branches();
|
||||
|
||||
@ -2505,7 +2504,7 @@ pub fn push(
|
||||
with_force,
|
||||
credentials,
|
||||
None,
|
||||
askpass.clone(),
|
||||
askpass,
|
||||
)?;
|
||||
|
||||
vbranch.upstream = Some(remote_branch.clone());
|
||||
@ -2516,7 +2515,7 @@ pub fn push(
|
||||
project_repository.fetch(
|
||||
remote_branch.remote(),
|
||||
credentials,
|
||||
askpass.map(|(broker, _)| (broker, "modal".to_string())),
|
||||
askpass.map(|_| "modal".to_string()),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
|
@ -3,7 +3,6 @@ use std::{collections::HashMap, path};
|
||||
use anyhow::{Context, Result};
|
||||
use gitbutler_core::error::Error as CoreError;
|
||||
use gitbutler_core::{
|
||||
askpass::AskpassBroker,
|
||||
gb_repository, git,
|
||||
project_repository::{self, conflicts},
|
||||
projects::{self, ProjectId},
|
||||
@ -92,7 +91,7 @@ impl App {
|
||||
remote_name: &str,
|
||||
branch_name: &str,
|
||||
credentials: &git::credentials::Helper,
|
||||
askpass: Option<(AskpassBroker, Option<BranchId>)>,
|
||||
askpass: Option<Option<BranchId>>,
|
||||
) -> Result<(), CoreError> {
|
||||
let project = self.projects.get(project_id)?;
|
||||
let project_repository = project_repository::Repository::open(&project)?;
|
||||
@ -104,7 +103,7 @@ impl App {
|
||||
project_id: &ProjectId,
|
||||
remote_name: &str,
|
||||
credentials: &git::credentials::Helper,
|
||||
askpass: Option<(AskpassBroker, String)>,
|
||||
askpass: Option<String>,
|
||||
) -> Result<(), CoreError> {
|
||||
let project = self.projects.get(project_id)?;
|
||||
let project_repository = project_repository::Repository::open(&project)?;
|
||||
|
@ -1,21 +1,16 @@
|
||||
pub mod commands {
|
||||
use gitbutler_core::{
|
||||
askpass::{AskpassBroker, AskpassRequest},
|
||||
askpass::{self, AskpassRequest},
|
||||
id::Id,
|
||||
};
|
||||
use tauri::{AppHandle, Manager};
|
||||
|
||||
#[tauri::command(async)]
|
||||
#[tracing::instrument(skip(handle, response))]
|
||||
#[tracing::instrument(skip(response))]
|
||||
pub async fn submit_prompt_response(
|
||||
handle: AppHandle,
|
||||
id: Id<AskpassRequest>,
|
||||
response: Option<String>,
|
||||
) -> Result<(), ()> {
|
||||
handle
|
||||
.state::<AskpassBroker>()
|
||||
.handle_response(id, response)
|
||||
.await;
|
||||
askpass::get_broker().handle_response(id, response).await;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -48,16 +48,13 @@ pub async fn git_test_push(
|
||||
) -> Result<(), Error> {
|
||||
let app = handle.state::<app::App>();
|
||||
let helper = handle.state::<gitbutler_core::git::credentials::Helper>();
|
||||
let askpass_broker = handle
|
||||
.state::<gitbutler_core::askpass::AskpassBroker>()
|
||||
.inner()
|
||||
.clone();
|
||||
Ok(app.git_test_push(
|
||||
&project_id,
|
||||
remote_name,
|
||||
branch_name,
|
||||
&helper,
|
||||
Some((askpass_broker, None)),
|
||||
// Run askpass, but don't pass any action
|
||||
Some(None),
|
||||
)?)
|
||||
}
|
||||
|
||||
@ -71,15 +68,11 @@ pub async fn git_test_fetch(
|
||||
) -> Result<(), Error> {
|
||||
let app = handle.state::<app::App>();
|
||||
let helper = handle.state::<gitbutler_core::git::credentials::Helper>();
|
||||
let askpass_broker = handle
|
||||
.state::<gitbutler_core::askpass::AskpassBroker>()
|
||||
.inner()
|
||||
.clone();
|
||||
Ok(app.git_test_fetch(
|
||||
&project_id,
|
||||
remote_name,
|
||||
&helper,
|
||||
Some((askpass_broker, action.unwrap_or_else(|| "test".to_string()))),
|
||||
Some(action.unwrap_or_else(|| "test".to_string())),
|
||||
)?)
|
||||
}
|
||||
|
||||
|
@ -68,6 +68,17 @@ fn main() {
|
||||
|
||||
logs::init(&app_handle);
|
||||
|
||||
// SAFETY(qix-): This is safe because we're initializing the askpass broker here,
|
||||
// SAFETY(qix-): before any other threads would ever access it.
|
||||
unsafe {
|
||||
gitbutler_core::askpass::init({
|
||||
let handle = app_handle.clone();
|
||||
move |event| {
|
||||
handle.emit_all("git_prompt", event).expect("tauri event emission doesn't fail in practice")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let app_data_dir = app_handle.path_resolver().app_data_dir().expect("missing app data dir");
|
||||
let app_cache_dir = app_handle.path_resolver().app_cache_dir().expect("missing app cache dir");
|
||||
let app_log_dir = app_handle.path_resolver().app_log_dir().expect("missing app log dir");
|
||||
@ -77,14 +88,6 @@ fn main() {
|
||||
|
||||
tracing::info!(version = %app_handle.package_info().version, name = %app_handle.package_info().name, "starting app");
|
||||
|
||||
let askpass_broker = gitbutler_core::askpass::AskpassBroker::init({
|
||||
let handle = app_handle.clone();
|
||||
move |event| {
|
||||
handle.emit_all("git_prompt", event).expect("tauri event emission doesn't fail in practice")
|
||||
}
|
||||
});
|
||||
app_handle.manage(askpass_broker);
|
||||
|
||||
let storage_controller = storage::Storage::new(&app_data_dir);
|
||||
app_handle.manage(storage_controller.clone());
|
||||
|
||||
|
@ -2,7 +2,6 @@ pub mod commands {
|
||||
use crate::error::Error;
|
||||
use anyhow::Context;
|
||||
use gitbutler_core::{
|
||||
askpass::AskpassBroker,
|
||||
assets,
|
||||
error::Code,
|
||||
git, projects,
|
||||
@ -266,15 +265,9 @@ pub mod commands {
|
||||
branch_id: BranchId,
|
||||
with_force: bool,
|
||||
) -> Result<(), Error> {
|
||||
let askpass_broker = handle.state::<AskpassBroker>();
|
||||
handle
|
||||
.state::<Controller>()
|
||||
.push_virtual_branch(
|
||||
&project_id,
|
||||
&branch_id,
|
||||
with_force,
|
||||
Some((askpass_broker.inner().clone(), Some(branch_id))),
|
||||
)
|
||||
.push_virtual_branch(&project_id, &branch_id, with_force, Some(Some(branch_id)))
|
||||
.await
|
||||
.map_err(|err| err.context(Code::Unknown))?;
|
||||
emit_vbranches(&handle, &project_id).await;
|
||||
@ -499,15 +492,11 @@ pub mod commands {
|
||||
project_id: ProjectId,
|
||||
action: Option<String>,
|
||||
) -> Result<BaseBranch, Error> {
|
||||
let askpass_broker = handle.state::<AskpassBroker>().inner().clone();
|
||||
let base_branch = handle
|
||||
.state::<Controller>()
|
||||
.fetch_from_target(
|
||||
&project_id,
|
||||
Some((
|
||||
askpass_broker,
|
||||
action.unwrap_or_else(|| "unknown".to_string()),
|
||||
)),
|
||||
Some(action.unwrap_or_else(|| "unknown".to_string())),
|
||||
)
|
||||
.await?;
|
||||
emit_vbranches(&handle, &project_id).await;
|
||||
|
Loading…
Reference in New Issue
Block a user