2024-03-01 17:14:30 +03:00
|
|
|
#![feature(error_generic_member_access)]
|
|
|
|
#![cfg_attr(target_os = "windows", feature(windows_by_handle))]
|
|
|
|
|
|
|
|
pub(crate) mod analytics;
|
|
|
|
pub(crate) mod app;
|
|
|
|
pub(crate) mod assets;
|
|
|
|
pub(crate) mod commands;
|
|
|
|
pub(crate) mod database;
|
|
|
|
pub(crate) mod dedup;
|
|
|
|
pub(crate) mod deltas;
|
|
|
|
pub(crate) mod error;
|
|
|
|
pub(crate) mod events;
|
|
|
|
pub(crate) mod fs;
|
|
|
|
pub(crate) mod gb_repository;
|
|
|
|
pub(crate) mod git;
|
|
|
|
pub(crate) mod github;
|
|
|
|
pub(crate) mod keys;
|
|
|
|
pub(crate) mod lock;
|
|
|
|
pub(crate) mod logs;
|
|
|
|
pub(crate) mod menu;
|
2024-03-11 21:06:22 +03:00
|
|
|
pub(crate) mod path;
|
2024-03-01 17:14:30 +03:00
|
|
|
pub(crate) mod project_repository;
|
|
|
|
pub(crate) mod projects;
|
|
|
|
pub(crate) mod reader;
|
|
|
|
pub(crate) mod sentry;
|
|
|
|
pub(crate) mod sessions;
|
|
|
|
pub(crate) mod ssh;
|
|
|
|
pub(crate) mod storage;
|
|
|
|
pub(crate) mod types;
|
|
|
|
pub(crate) mod users;
|
|
|
|
pub(crate) mod virtual_branches;
|
|
|
|
pub(crate) mod watcher;
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
pub(crate) mod windows;
|
|
|
|
pub(crate) mod writer;
|
|
|
|
pub(crate) mod zip;
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
pub(crate) mod tests;
|
|
|
|
|
|
|
|
#[deprecated = "use `gitbutler-core` instead"]
|
|
|
|
pub(crate) mod id {
|
|
|
|
#[deprecated = "use `gitbutler-core` instead"]
|
|
|
|
pub use gitbutler_core::id::Id;
|
|
|
|
}
|
|
|
|
|
2024-01-28 14:38:54 +03:00
|
|
|
use std::path::PathBuf;
|
|
|
|
|
2023-10-05 10:28:45 +03:00
|
|
|
use anyhow::Context;
|
2024-01-28 14:38:54 +03:00
|
|
|
use tauri::{generate_context, Manager, Wry};
|
2023-02-24 18:27:28 +03:00
|
|
|
|
2024-02-29 21:28:45 +03:00
|
|
|
use tauri_plugin_log::LogTarget;
|
2024-01-28 14:38:54 +03:00
|
|
|
use tauri_plugin_store::{with_store, JsonValue, StoreCollection};
|
2023-07-06 10:57:51 +03:00
|
|
|
|
2023-09-29 09:11:03 +03:00
|
|
|
fn main() {
|
2023-04-21 16:55:54 +03:00
|
|
|
let tauri_context = generate_context!();
|
|
|
|
|
2024-01-28 14:38:54 +03:00
|
|
|
let app_name = tauri_context.package_info().name.clone();
|
|
|
|
let app_version = tauri_context.package_info().version.clone().to_string();
|
2023-09-29 09:11:03 +03:00
|
|
|
tokio::runtime::Builder::new_multi_thread()
|
|
|
|
.enable_all()
|
|
|
|
.build()
|
|
|
|
.unwrap()
|
|
|
|
.block_on(async {
|
|
|
|
tauri::async_runtime::set(tokio::runtime::Handle::current());
|
|
|
|
|
2024-02-29 21:28:45 +03:00
|
|
|
let log = tauri_plugin_log::Builder::default()
|
|
|
|
.log_name("ui-logs")
|
|
|
|
.target(LogTarget::LogDir)
|
|
|
|
.level(log::LevelFilter::Error);
|
|
|
|
|
2024-03-04 18:56:30 +03:00
|
|
|
let builder = tauri::Builder::default();
|
|
|
|
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
let builder = builder
|
2023-09-29 09:11:03 +03:00
|
|
|
.on_window_event(|event| {
|
|
|
|
if let tauri::WindowEvent::CloseRequested { api, .. } = event.event() {
|
|
|
|
hide_window(&event.window().app_handle()).expect("Failed to hide window");
|
|
|
|
api.prevent_close();
|
|
|
|
}
|
2024-03-04 18:56:30 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
builder
|
2023-09-29 09:11:03 +03:00
|
|
|
.setup(move |tauri_app| {
|
|
|
|
let window =
|
|
|
|
create_window(&tauri_app.handle()).expect("Failed to create window");
|
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
window.open_devtools();
|
|
|
|
|
2024-01-24 19:28:52 +03:00
|
|
|
tokio::task::spawn(async move {
|
|
|
|
let mut six_hours = tokio::time::interval(tokio::time::Duration::new(6 * 60 * 60, 0));
|
|
|
|
loop {
|
|
|
|
six_hours.tick().await;
|
|
|
|
_ = window.emit_and_trigger("tauri://update", ());
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-09-29 09:11:03 +03:00
|
|
|
let app_handle = tauri_app.handle();
|
|
|
|
|
|
|
|
logs::init(&app_handle);
|
|
|
|
|
2024-03-05 19:54:08 +03:00
|
|
|
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");
|
|
|
|
|
|
|
|
std::fs::create_dir_all(&app_data_dir).expect("failed to create app data dir");
|
|
|
|
std::fs::create_dir_all(&app_cache_dir).expect("failed to create cache dir");
|
|
|
|
|
2023-10-20 15:24:40 +03:00
|
|
|
tracing::info!(version = %app_handle.package_info().version, name = %app_handle.package_info().name, "starting app");
|
2023-09-29 09:11:03 +03:00
|
|
|
|
2024-03-05 19:54:08 +03:00
|
|
|
let storage_controller = storage::Storage::new(&app_data_dir);
|
|
|
|
app_handle.manage(storage_controller.clone());
|
2023-09-29 09:11:03 +03:00
|
|
|
|
2024-03-05 19:54:08 +03:00
|
|
|
let watcher_controller = watcher::Watchers::new(app_handle.clone());
|
|
|
|
app_handle.manage(watcher_controller.clone());
|
2023-09-29 09:11:03 +03:00
|
|
|
|
2024-03-05 19:54:08 +03:00
|
|
|
let projects_storage_controller = projects::storage::Storage::new(storage_controller.clone());
|
|
|
|
app_handle.manage(projects_storage_controller.clone());
|
2023-09-29 09:11:03 +03:00
|
|
|
|
2024-03-05 19:54:08 +03:00
|
|
|
let users_storage_controller = users::storage::Storage::new(storage_controller.clone());
|
|
|
|
app_handle.manage(users_storage_controller.clone());
|
2023-09-29 09:11:03 +03:00
|
|
|
|
2024-03-05 19:54:08 +03:00
|
|
|
let users_controller = users::Controller::new(users_storage_controller.clone());
|
|
|
|
app_handle.manage(users_controller.clone());
|
2023-10-06 16:08:42 +03:00
|
|
|
|
2024-03-05 19:54:08 +03:00
|
|
|
let projects_controller = projects::Controller::new(
|
|
|
|
app_data_dir.clone(),
|
|
|
|
projects_storage_controller.clone(),
|
|
|
|
users_controller.clone(),
|
|
|
|
Some(watcher_controller.clone())
|
|
|
|
);
|
|
|
|
app_handle.manage(projects_controller.clone());
|
|
|
|
|
|
|
|
app_handle.manage(assets::Proxy::new(app_cache_dir.join("images")));
|
|
|
|
|
2024-03-06 17:19:51 +03:00
|
|
|
let database_controller = database::Database::open_in_directory(&app_data_dir).expect("failed to open database");
|
2024-03-05 19:54:08 +03:00
|
|
|
app_handle.manage(database_controller.clone());
|
2023-11-08 14:28:50 +03:00
|
|
|
|
2024-03-05 19:54:08 +03:00
|
|
|
let zipper = zip::Zipper::new(&app_cache_dir);
|
|
|
|
app_handle.manage(zipper.clone());
|
2023-11-08 11:16:40 +03:00
|
|
|
|
2024-03-05 19:54:08 +03:00
|
|
|
app_handle.manage(zip::Controller::new(app_data_dir.clone(), app_log_dir.clone(), zipper.clone(), projects_controller.clone()));
|
2023-10-05 16:44:34 +03:00
|
|
|
|
2024-03-05 19:54:08 +03:00
|
|
|
let deltas_database_controller = deltas::database::Database::new(database_controller.clone());
|
|
|
|
app_handle.manage(deltas_database_controller.clone());
|
2023-09-29 09:11:03 +03:00
|
|
|
|
2024-03-05 19:54:08 +03:00
|
|
|
let deltas_controller = deltas::Controller::new(deltas_database_controller.clone());
|
|
|
|
app_handle.manage(deltas_controller);
|
|
|
|
|
|
|
|
let keys_storage_controller = keys::storage::Storage::new(storage_controller.clone());
|
|
|
|
app_handle.manage(keys_storage_controller.clone());
|
|
|
|
|
|
|
|
let keys_controller = keys::Controller::new(keys_storage_controller.clone());
|
|
|
|
app_handle.manage(keys_controller.clone());
|
2023-10-06 16:25:48 +03:00
|
|
|
|
2024-03-05 19:54:08 +03:00
|
|
|
let git_credentials_controller = git::credentials::Helper::new(
|
|
|
|
keys_controller.clone(),
|
|
|
|
users_controller.clone(),
|
|
|
|
std::env::var_os("HOME").map(PathBuf::from)
|
|
|
|
);
|
|
|
|
app_handle.manage(git_credentials_controller.clone());
|
|
|
|
|
|
|
|
app_handle.manage(virtual_branches::controller::Controller::new(
|
|
|
|
app_data_dir.clone(),
|
|
|
|
projects_controller.clone(),
|
|
|
|
users_controller.clone(),
|
|
|
|
keys_controller.clone(),
|
|
|
|
git_credentials_controller.clone(),
|
|
|
|
));
|
2024-01-28 14:38:54 +03:00
|
|
|
|
|
|
|
let stores = tauri_app.state::<StoreCollection<Wry>>();
|
|
|
|
if let Some(path) = app_handle.path_resolver().app_config_dir().map(|path| path.join(PathBuf::from("settings.json"))) {
|
|
|
|
if let Ok((metrics_enabled, error_reporting_enabled)) = with_store(app_handle.clone(), stores, path, |store| {
|
|
|
|
let metrics_enabled = store.get("appMetricsEnabled")
|
|
|
|
.and_then(JsonValue::as_bool)
|
|
|
|
.unwrap_or(true);
|
|
|
|
let error_reporting_enabled = store.get("appErrorReportingEnabled")
|
|
|
|
.and_then(JsonValue::as_bool)
|
|
|
|
.unwrap_or(true);
|
|
|
|
Ok((metrics_enabled, error_reporting_enabled))
|
|
|
|
}) {
|
|
|
|
if metrics_enabled {
|
|
|
|
let analytics_cfg = if cfg!(debug_assertions) {
|
|
|
|
analytics::Config {
|
|
|
|
posthog_token: Some("phc_t7VDC9pQELnYep9IiDTxrq2HLseY5wyT7pn0EpHM7rr"),
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
analytics::Config {
|
|
|
|
posthog_token: Some("phc_yJx46mXv6kA5KTuM2eEQ6IwNTgl5YW3feKV5gi7mfGG"),
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let analytics_client = analytics::Client::new(&app_handle, &analytics_cfg);
|
|
|
|
tauri_app.manage(analytics_client);
|
|
|
|
}
|
|
|
|
|
|
|
|
if error_reporting_enabled {
|
|
|
|
let _guard = sentry::init(app_name.as_str(), app_version);
|
|
|
|
sentry::configure_scope(users_controller.get_user().context("failed to get user")?.as_ref());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2024-03-05 19:54:08 +03:00
|
|
|
let sessions_database_controller = sessions::database::Database::new(database_controller.clone());
|
|
|
|
app_handle.manage(sessions_database_controller.clone());
|
|
|
|
|
|
|
|
app_handle.manage(sessions::Controller::new(
|
|
|
|
app_data_dir.clone(),
|
|
|
|
sessions_database_controller.clone(),
|
|
|
|
projects_controller.clone(),
|
|
|
|
users_controller.clone(),
|
|
|
|
));
|
|
|
|
|
|
|
|
let app = app::App::new(
|
|
|
|
app_data_dir,
|
|
|
|
projects_controller,
|
|
|
|
users_controller,
|
|
|
|
watcher_controller,
|
|
|
|
sessions_database_controller,
|
|
|
|
);
|
2023-09-29 09:11:03 +03:00
|
|
|
|
2023-11-14 17:02:16 +03:00
|
|
|
app.init().context("failed to init app")?;
|
2023-09-29 09:11:03 +03:00
|
|
|
|
|
|
|
app_handle.manage(app);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
})
|
|
|
|
.plugin(tauri_plugin_window_state::Builder::default().build())
|
2023-10-19 16:25:27 +03:00
|
|
|
.plugin(tauri_plugin_single_instance::init(|_, _, _| {}))
|
2023-10-28 21:43:58 +03:00
|
|
|
.plugin(tauri_plugin_context_menu::init())
|
2024-01-28 14:38:54 +03:00
|
|
|
.plugin(tauri_plugin_store::Builder::default().build())
|
2024-02-29 21:28:45 +03:00
|
|
|
.plugin(log.build())
|
2023-09-29 09:11:03 +03:00
|
|
|
.invoke_handler(tauri::generate_handler![
|
2023-10-05 10:28:45 +03:00
|
|
|
commands::list_session_files,
|
|
|
|
commands::git_remote_branches,
|
|
|
|
commands::git_head,
|
|
|
|
commands::delete_all_data,
|
|
|
|
commands::mark_resolved,
|
|
|
|
commands::git_set_global_config,
|
|
|
|
commands::git_get_global_config,
|
2023-11-08 18:34:33 +03:00
|
|
|
commands::project_flush_and_push,
|
2024-03-06 23:19:59 +03:00
|
|
|
commands::git_test_push,
|
2024-03-07 20:49:10 +03:00
|
|
|
commands::git_test_fetch,
|
2023-10-06 16:08:42 +03:00
|
|
|
zip::commands::get_logs_archive_path,
|
|
|
|
zip::commands::get_project_archive_path,
|
|
|
|
zip::commands::get_project_data_archive_path,
|
2023-10-06 09:40:27 +03:00
|
|
|
users::commands::set_user,
|
|
|
|
users::commands::delete_user,
|
|
|
|
users::commands::get_user,
|
2023-10-05 16:44:34 +03:00
|
|
|
projects::commands::add_project,
|
|
|
|
projects::commands::get_project,
|
|
|
|
projects::commands::update_project,
|
|
|
|
projects::commands::delete_project,
|
|
|
|
projects::commands::list_projects,
|
2023-11-08 11:16:40 +03:00
|
|
|
sessions::commands::list_sessions,
|
2023-11-08 14:28:50 +03:00
|
|
|
deltas::commands::list_deltas,
|
2023-09-29 09:11:03 +03:00
|
|
|
virtual_branches::commands::list_virtual_branches,
|
|
|
|
virtual_branches::commands::create_virtual_branch,
|
|
|
|
virtual_branches::commands::commit_virtual_branch,
|
|
|
|
virtual_branches::commands::get_base_branch_data,
|
|
|
|
virtual_branches::commands::set_base_branch,
|
|
|
|
virtual_branches::commands::update_base_branch,
|
|
|
|
virtual_branches::commands::merge_virtual_branch_upstream,
|
|
|
|
virtual_branches::commands::update_virtual_branch,
|
|
|
|
virtual_branches::commands::delete_virtual_branch,
|
|
|
|
virtual_branches::commands::apply_branch,
|
|
|
|
virtual_branches::commands::unapply_branch,
|
|
|
|
virtual_branches::commands::unapply_ownership,
|
2024-02-29 15:19:16 +03:00
|
|
|
virtual_branches::commands::reset_files,
|
2023-09-29 09:11:03 +03:00
|
|
|
virtual_branches::commands::push_virtual_branch,
|
|
|
|
virtual_branches::commands::create_virtual_branch_from_branch,
|
|
|
|
virtual_branches::commands::can_apply_virtual_branch,
|
|
|
|
virtual_branches::commands::can_apply_remote_branch,
|
|
|
|
virtual_branches::commands::list_remote_commit_files,
|
2023-10-10 15:52:16 +03:00
|
|
|
virtual_branches::commands::reset_virtual_branch,
|
2023-10-23 16:57:44 +03:00
|
|
|
virtual_branches::commands::cherry_pick_onto_virtual_branch,
|
2023-11-01 15:42:58 +03:00
|
|
|
virtual_branches::commands::amend_virtual_branch,
|
2023-11-08 16:38:27 +03:00
|
|
|
virtual_branches::commands::list_remote_branches,
|
2024-02-11 23:49:14 +03:00
|
|
|
virtual_branches::commands::get_remote_branch_data,
|
2023-11-10 11:05:20 +03:00
|
|
|
virtual_branches::commands::squash_branch_commit,
|
2023-12-13 15:40:41 +03:00
|
|
|
virtual_branches::commands::fetch_from_target,
|
2024-02-16 17:21:54 +03:00
|
|
|
virtual_branches::commands::move_commit,
|
2023-11-23 14:58:15 +03:00
|
|
|
menu::menu_item_set_enabled,
|
2023-09-29 09:11:03 +03:00
|
|
|
keys::commands::get_public_key,
|
2023-10-10 20:06:00 +03:00
|
|
|
github::commands::init_device_oauth,
|
|
|
|
github::commands::check_auth_status,
|
2023-09-29 09:11:03 +03:00
|
|
|
])
|
2023-11-23 14:58:15 +03:00
|
|
|
.menu(menu::build(tauri_context.package_info()))
|
|
|
|
.on_menu_event(|event|menu::handle_event(&event))
|
2023-09-29 09:11:03 +03:00
|
|
|
.build(tauri_context)
|
|
|
|
.expect("Failed to build tauri app")
|
2024-02-19 23:41:49 +03:00
|
|
|
.run(|app_handle, event| {
|
2024-02-20 23:30:16 +03:00
|
|
|
#[cfg(target_os = "macos")]
|
2024-02-19 23:41:49 +03:00
|
|
|
if let tauri::RunEvent::ExitRequested { api, .. } = event {
|
2023-09-29 09:11:03 +03:00
|
|
|
hide_window(app_handle).expect("Failed to hide window");
|
|
|
|
api.prevent_exit();
|
|
|
|
}
|
2024-03-04 18:56:30 +03:00
|
|
|
|
|
|
|
// To make the compiler happy.
|
|
|
|
#[cfg(not(target_os = "macos"))]
|
|
|
|
{
|
|
|
|
let _ = (app_handle, event);
|
|
|
|
}
|
2023-09-29 09:11:03 +03:00
|
|
|
});
|
2023-04-21 16:55:54 +03:00
|
|
|
});
|
2023-01-31 17:55:57 +03:00
|
|
|
}
|
2023-02-22 13:49:25 +03:00
|
|
|
|
2023-02-22 15:38:04 +03:00
|
|
|
#[cfg(not(target_os = "macos"))]
|
2023-02-22 13:49:25 +03:00
|
|
|
fn create_window(handle: &tauri::AppHandle) -> tauri::Result<tauri::Window> {
|
2023-04-21 16:55:54 +03:00
|
|
|
let app_title = handle.package_info().name.clone();
|
2023-09-06 10:33:27 +03:00
|
|
|
let window =
|
|
|
|
tauri::WindowBuilder::new(handle, "main", tauri::WindowUrl::App("index.html".into()))
|
|
|
|
.resizable(true)
|
|
|
|
.title(app_title)
|
|
|
|
.disable_file_drop_handler()
|
2023-11-28 21:11:38 +03:00
|
|
|
.min_inner_size(800.0, 600.0)
|
|
|
|
.inner_size(1160.0, 720.0)
|
2023-09-06 10:33:27 +03:00
|
|
|
.build()?;
|
|
|
|
tracing::info!("app window created");
|
|
|
|
Ok(window)
|
2023-02-22 15:38:04 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
fn create_window(handle: &tauri::AppHandle) -> tauri::Result<tauri::Window> {
|
2023-09-06 10:33:27 +03:00
|
|
|
let window =
|
|
|
|
tauri::WindowBuilder::new(handle, "main", tauri::WindowUrl::App("index.html".into()))
|
|
|
|
.resizable(true)
|
|
|
|
.title(handle.package_info().name.clone())
|
2023-11-28 21:11:38 +03:00
|
|
|
.min_inner_size(800.0, 600.0)
|
|
|
|
.inner_size(1160.0, 720.0)
|
2023-09-06 10:33:27 +03:00
|
|
|
.hidden_title(true)
|
|
|
|
.disable_file_drop_handler()
|
|
|
|
.title_bar_style(tauri::TitleBarStyle::Overlay)
|
|
|
|
.build()?;
|
|
|
|
tracing::info!("window created");
|
|
|
|
Ok(window)
|
2023-02-22 13:49:25 +03:00
|
|
|
}
|
|
|
|
|
2024-02-22 01:38:28 +03:00
|
|
|
#[cfg(target_os = "macos")]
|
2023-04-27 14:29:55 +03:00
|
|
|
fn hide_window(handle: &tauri::AppHandle) -> tauri::Result<()> {
|
2023-04-27 14:39:44 +03:00
|
|
|
handle.hide()?;
|
|
|
|
Ok(())
|
2023-02-22 13:49:25 +03:00
|
|
|
}
|