Development app builds (#5255)
* Workflow changes * Propagate app_identifier via State * Remove old updater stuff * Remove patch file * Remove unused binding * Fix application loading * Don't sign windows binaries by default * Remove the damn emojis * Figure out where windows artifacts are * Fix windows artifacts
This commit is contained in:
committed by
GitHub
parent
3552c8280b
commit
e3395a7366
57
.github/workflows/theseus-build.yml
vendored
57
.github/workflows/theseus-build.yml
vendored
@@ -19,7 +19,7 @@ on:
|
||||
sign-windows-binaries:
|
||||
description: Sign Windows binaries
|
||||
type: boolean
|
||||
default: true
|
||||
default: false
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
@@ -40,33 +40,48 @@ jobs:
|
||||
runs-on: ${{ matrix.platform }}
|
||||
|
||||
steps:
|
||||
- name: 📥 Check out code
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: 🧰 Setup Rust toolchain
|
||||
- name: Setup Rust toolchain
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
rustflags: ''
|
||||
target: ${{ startsWith(matrix.platform, 'macos') && 'x86_64-apple-darwin' || '' }}
|
||||
|
||||
- name: 🧰 Install pnpm
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: 🧰 Setup Node.js
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: .nvmrc
|
||||
cache: pnpm
|
||||
|
||||
- name: 🧰 Install Linux build dependencies
|
||||
- name: Generate tauri-dev.conf.json
|
||||
shell: bash
|
||||
run: |
|
||||
GIT_HASH=$(git rev-parse --short HEAD)
|
||||
cat > apps/app/tauri-dev.conf.json <<EOF
|
||||
{
|
||||
"productName": "Modrinth App (dev-${GIT_HASH})",
|
||||
"mainBinaryName": "Modrinth App (dev-${GIT_HASH})",
|
||||
"identifier": "ModrinthApp-dev-${GIT_HASH}",
|
||||
"bundle": {
|
||||
"fileAssociations": []
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
- name: Install Linux build dependencies
|
||||
if: startsWith(matrix.platform, 'ubuntu')
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -yq libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev
|
||||
|
||||
- name: 🧰 Setup Dasel
|
||||
- name: Setup Dasel
|
||||
uses: jaxxstorm/action-install-gh-release@v2.1.0
|
||||
with:
|
||||
repo: TomWright/dasel
|
||||
@@ -75,7 +90,7 @@ jobs:
|
||||
rename-to: ${{ startsWith(matrix.platform, 'windows') && 'dasel.exe' || 'dasel' }}
|
||||
chmod: 0755
|
||||
|
||||
- name: ⚙️ Set application version and environment
|
||||
- name: Set application version and environment
|
||||
shell: bash
|
||||
run: |
|
||||
APP_VERSION="$(git describe --tags --always | sed -E 's/-([0-9]+)-(g[0-9a-fA-F]+)$/-canary+\1.\2/')"
|
||||
@@ -86,13 +101,13 @@ jobs:
|
||||
|
||||
cp packages/app-lib/.env.prod packages/app-lib/.env
|
||||
|
||||
- name: 💨 Setup Turbo cache
|
||||
- name: Setup Turbo cache
|
||||
uses: rharkor/caching-for-turbo@v1.8
|
||||
|
||||
- name: 🧰 Install dependencies
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: ✍️ Set up Windows code signing
|
||||
- name: Set up Windows code signing
|
||||
if: startsWith(matrix.platform, 'windows')
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -102,8 +117,8 @@ jobs:
|
||||
dasel delete -f apps/app/tauri-release.conf.json 'bundle.windows.signCommand'
|
||||
fi
|
||||
|
||||
- name: 🔨 Build macOS app
|
||||
run: pnpm --filter=@modrinth/app run tauri build --target universal-apple-darwin --config tauri-release.conf.json
|
||||
- name: Build macOS app
|
||||
run: ${{ github.ref == 'refs/heads/main' && 'pnpm --filter=@modrinth/app run tauri build --target universal-apple-darwin --config tauri-release.conf.json' || 'pnpm --filter=@modrinth/app run tauri build --target universal-apple-darwin --config tauri-dev.conf.json' }}
|
||||
if: startsWith(matrix.platform, 'macos')
|
||||
env:
|
||||
ENABLE_CODE_SIGNING: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
@@ -116,19 +131,19 @@ jobs:
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
|
||||
- name: 🔨 Build Linux app
|
||||
run: pnpm --filter=@modrinth/app run tauri build --config tauri-release.conf.json
|
||||
- name: Build Linux app
|
||||
run: ${{ github.ref == 'refs/heads/main' && 'pnpm --filter=@modrinth/app run tauri build --config tauri-release.conf.json' || 'pnpm --filter=@modrinth/app run tauri build --config tauri-dev.conf.json' }}
|
||||
if: startsWith(matrix.platform, 'ubuntu')
|
||||
env:
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
|
||||
- name: 🔨 Build Windows app
|
||||
- name: Build Windows app
|
||||
run: |
|
||||
[System.Convert]::FromBase64String("$env:DIGICERT_ONE_SIGNER_CLIENT_CERTIFICATE_BASE64") | Set-Content -Path signer-client-cert.p12 -AsByteStream
|
||||
$env:DIGICERT_ONE_SIGNER_CREDENTIALS = "$env:DIGICERT_ONE_SIGNER_API_KEY|$PWD\signer-client-cert.p12|$env:DIGICERT_ONE_SIGNER_CLIENT_CERTIFICATE_PASSWORD"
|
||||
$env:JAVA_HOME = "$env:JAVA_HOME_17_X64"
|
||||
pnpm --filter=@modrinth/app run tauri build --config tauri-release.conf.json --verbose --bundles 'nsis,updater'
|
||||
${{ github.ref == 'refs/heads/main' && 'pnpm --filter=@modrinth/app run tauri build --config tauri-release.conf.json --verbose --bundles "nsis,updater"' || 'pnpm --filter=@modrinth/app run tauri build --config tauri-dev.conf.json --verbose --bundles "nsis,updater"' }}
|
||||
Remove-Item -Path signer-client-cert.p12 -ErrorAction SilentlyContinue
|
||||
if: startsWith(matrix.platform, 'windows')
|
||||
env:
|
||||
@@ -138,7 +153,7 @@ jobs:
|
||||
DIGICERT_ONE_SIGNER_CLIENT_CERTIFICATE_BASE64: ${{ secrets.DIGICERT_ONE_SIGNER_CLIENT_CERTIFICATE_BASE64 }}
|
||||
DIGICERT_ONE_SIGNER_CLIENT_CERTIFICATE_PASSWORD: ${{ secrets.DIGICERT_ONE_SIGNER_CLIENT_CERTIFICATE_PASSWORD }}
|
||||
|
||||
- name: 📤 Upload app bundles
|
||||
- name: Upload app bundles
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: App bundle (${{ matrix.artifact-target-name }})
|
||||
@@ -146,7 +161,13 @@ jobs:
|
||||
target/release/bundle/appimage/Modrinth App_*.AppImage*
|
||||
target/release/bundle/deb/Modrinth App_*.deb*
|
||||
target/release/bundle/rpm/Modrinth App-*.rpm*
|
||||
target/release/bundle/appimage/Modrinth App (dev-*)_*.AppImage*
|
||||
target/release/bundle/deb/Modrinth App (dev-*)_*.deb*
|
||||
target/release/bundle/rpm/Modrinth App (dev-*)-*.rpm*
|
||||
target/universal-apple-darwin/release/bundle/macos/Modrinth App.app.tar.gz*
|
||||
target/universal-apple-darwin/release/bundle/macos/Modrinth App (dev-*)*.app.tar.gz
|
||||
target/universal-apple-darwin/release/bundle/dmg/Modrinth App (dev-*)*.dmg
|
||||
target/universal-apple-darwin/release/bundle/dmg/Modrinth App_*.dmg*
|
||||
target/release/bundle/nsis/Modrinth App_*-setup.exe*
|
||||
target/release/bundle/nsis/Modrinth App (dev-*)_*-setup.exe*
|
||||
target/release/bundle/nsis/Modrinth App_*-setup.nsis.zip*
|
||||
|
||||
@@ -38,10 +38,10 @@ pub async fn authenticate_run() -> theseus::Result<Credentials> {
|
||||
async fn main() -> theseus::Result<()> {
|
||||
println!("Starting.");
|
||||
|
||||
let _log_guard = theseus::start_logger();
|
||||
let _log_guard = theseus::start_logger("ModrinthApp");
|
||||
|
||||
// Initialize state
|
||||
State::init().await?;
|
||||
State::init("ModrinthApp".to_owned()).await?;
|
||||
|
||||
let worlds = get_recent_worlds(4, EnumSet::all()).await?;
|
||||
for world in worlds {
|
||||
|
||||
@@ -29,6 +29,9 @@ pub async fn settings_set(settings: Settings) -> Result<()> {
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn cancel_directory_change() -> Result<()> {
|
||||
settings::cancel_directory_change().await?;
|
||||
let state = State::get().await?;
|
||||
let identifier = &state.app_identifier;
|
||||
|
||||
settings::cancel_directory_change(identifier).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -107,10 +107,12 @@ pub async fn open_path<R: Runtime>(app: tauri::AppHandle<R>, path: PathBuf) {
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn show_launcher_logs_folder<R: Runtime>(app: tauri::AppHandle<R>) {
|
||||
let path = DirectoryInfo::launcher_logs_dir().unwrap_or_default();
|
||||
// failure to get folder just opens filesystem
|
||||
// (ie: if in debug mode only and launcher_logs never created)
|
||||
open_path(app, path).await;
|
||||
if let Some(d) = DirectoryInfo::global_handle_if_ready() {
|
||||
let path = d.launcher_logs_dir().unwrap_or_default();
|
||||
// failure to get folder just opens filesystem
|
||||
// (ie: if in debug mode only and launcher_logs never created)
|
||||
open_path(app, path).await;
|
||||
}
|
||||
}
|
||||
|
||||
// Get opening command
|
||||
|
||||
@@ -28,7 +28,7 @@ async fn initialize_state(app: tauri::AppHandle) -> api::Result<()> {
|
||||
theseus::EventState::init(app.clone()).await?;
|
||||
|
||||
tracing::info!("Initializing app state...");
|
||||
State::init().await?;
|
||||
State::init(app.config().identifier.clone()).await?;
|
||||
|
||||
let state = State::get().await?;
|
||||
app.asset_protocol_scope()
|
||||
@@ -110,7 +110,10 @@ fn main() {
|
||||
RUST_LOG="theseus=trace" {run command}
|
||||
|
||||
*/
|
||||
let _log_guard = theseus::start_logger();
|
||||
|
||||
let tauri_context = tauri::generate_context!();
|
||||
|
||||
let _log_guard = theseus::start_logger(&tauri_context.config().identifier);
|
||||
|
||||
tracing::info!("Initialized tracing subscriber. Loading Modrinth App!");
|
||||
|
||||
@@ -243,7 +246,7 @@ fn main() {
|
||||
]);
|
||||
|
||||
tracing::info!("Initializing app...");
|
||||
let app = builder.build(tauri::generate_context!());
|
||||
let app = builder.build(tauri_context);
|
||||
|
||||
match app {
|
||||
Ok(app) => {
|
||||
|
||||
@@ -23,10 +23,12 @@ pub async fn set(settings: Settings) -> crate::Result<()> {
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
pub async fn cancel_directory_change() -> crate::Result<()> {
|
||||
pub async fn cancel_directory_change(
|
||||
app_identifier: &str,
|
||||
) -> crate::Result<()> {
|
||||
// This is called to handle state initialization errors due to folder migrations
|
||||
// failing, so fetching a DB connection pool from `State::get` is not reliable here
|
||||
let pool = crate::state::db::connect().await?;
|
||||
let pool = crate::state::db::connect(app_identifier).await?;
|
||||
let mut settings = Settings::get(&pool).await?;
|
||||
|
||||
if let Some(prev_custom_dir) = settings.prev_custom_dir {
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
// Handling for the live development logging
|
||||
// This will log to the console, and will not log to a file
|
||||
#[cfg(debug_assertions)]
|
||||
pub fn start_logger() -> Option<()> {
|
||||
pub fn start_logger(_app_identifier: &str) -> Option<()> {
|
||||
use tracing_subscriber::prelude::*;
|
||||
|
||||
let filter = tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
@@ -36,7 +36,7 @@ pub fn start_logger() -> Option<()> {
|
||||
// Handling for the live production logging
|
||||
// This will log to a file in the logs directory, and will not show any logs in the console
|
||||
#[cfg(not(debug_assertions))]
|
||||
pub fn start_logger() -> Option<()> {
|
||||
pub fn start_logger(app_identifier: &str) -> Option<()> {
|
||||
use crate::prelude::DirectoryInfo;
|
||||
use chrono::Local;
|
||||
use std::fs::OpenOptions;
|
||||
@@ -44,7 +44,9 @@ pub fn start_logger() -> Option<()> {
|
||||
use tracing_subscriber::prelude::*;
|
||||
|
||||
// Initialize and get logs directory path
|
||||
let logs_dir = if let Some(d) = DirectoryInfo::launcher_logs_dir() {
|
||||
let logs_dir = if let Some(d) =
|
||||
DirectoryInfo::launcher_logs_dir_path(app_identifier)
|
||||
{
|
||||
d
|
||||
} else {
|
||||
eprintln!("Could not start logger");
|
||||
|
||||
@@ -6,12 +6,13 @@ use sqlx::{Pool, Sqlite};
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
|
||||
pub(crate) async fn connect() -> crate::Result<Pool<Sqlite>> {
|
||||
let settings_dir = DirectoryInfo::get_initial_settings_dir().ok_or(
|
||||
crate::ErrorKind::FSError(
|
||||
pub(crate) async fn connect(
|
||||
app_identifier: &str,
|
||||
) -> crate::Result<Pool<Sqlite>> {
|
||||
let settings_dir = DirectoryInfo::initial_settings_dir_path(app_identifier)
|
||||
.ok_or(crate::ErrorKind::FSError(
|
||||
"Could not find valid config dir".to_string(),
|
||||
),
|
||||
)?;
|
||||
))?;
|
||||
|
||||
if !settings_dir.exists() {
|
||||
crate::util::io::create_dir_all(&settings_dir).await?;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//! Theseus directory information
|
||||
use crate::LoadingBarType;
|
||||
use crate::event::emit::{emit_loading, init_loading};
|
||||
use crate::state::LAUNCHER_STATE;
|
||||
use crate::state::{JavaVersion, Profile, Settings};
|
||||
use crate::util::fetch::IoSemaphore;
|
||||
use dashmap::DashSet;
|
||||
@@ -17,24 +18,35 @@ pub const METADATA_FOLDER_NAME: &str = "meta";
|
||||
pub struct DirectoryInfo {
|
||||
pub settings_dir: PathBuf, // Base settings directory- app database
|
||||
pub config_dir: PathBuf, // Base config directory- instances, minecraft downloads, etc. Changeable as a setting.
|
||||
pub app_identifier: String,
|
||||
}
|
||||
|
||||
impl DirectoryInfo {
|
||||
pub fn global_handle_if_ready() -> Option<&'static Self> {
|
||||
LAUNCHER_STATE.get().map(|x| &x.directories)
|
||||
}
|
||||
|
||||
pub fn get_initial_settings_dir(&self) -> Option<PathBuf> {
|
||||
Self::initial_settings_dir_path(&self.app_identifier)
|
||||
}
|
||||
|
||||
// Get the settings directory
|
||||
// init() is not needed for this function
|
||||
pub fn get_initial_settings_dir() -> Option<PathBuf> {
|
||||
pub fn initial_settings_dir_path(app_identifier: &str) -> Option<PathBuf> {
|
||||
Self::env_path("THESEUS_CONFIG_DIR")
|
||||
.or_else(|| Some(dirs::data_dir()?.join("ModrinthApp")))
|
||||
.or_else(|| Some(dirs::data_dir()?.join(app_identifier)))
|
||||
}
|
||||
|
||||
/// Get all paths needed for Theseus to operate properly
|
||||
#[tracing::instrument]
|
||||
pub async fn init(config_dir: Option<String>) -> crate::Result<Self> {
|
||||
let settings_dir = Self::get_initial_settings_dir().ok_or(
|
||||
crate::ErrorKind::FSError(
|
||||
pub async fn init(
|
||||
config_dir: Option<String>,
|
||||
app_identifier: &str,
|
||||
) -> crate::Result<Self> {
|
||||
let settings_dir = Self::initial_settings_dir_path(app_identifier)
|
||||
.ok_or(crate::ErrorKind::FSError(
|
||||
"Could not find valid settings dir".to_string(),
|
||||
),
|
||||
)?;
|
||||
))?;
|
||||
|
||||
fs::create_dir_all(&settings_dir).await.map_err(|err| {
|
||||
crate::ErrorKind::FSError(format!(
|
||||
@@ -48,6 +60,7 @@ impl DirectoryInfo {
|
||||
Ok(Self {
|
||||
settings_dir,
|
||||
config_dir,
|
||||
app_identifier: app_identifier.to_owned(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -154,8 +167,14 @@ impl DirectoryInfo {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn launcher_logs_dir() -> Option<PathBuf> {
|
||||
Self::get_initial_settings_dir()
|
||||
pub fn launcher_logs_dir(&self) -> Option<PathBuf> {
|
||||
self.get_initial_settings_dir()
|
||||
.map(|d| d.join(LAUNCHER_LOGS_FOLDER_NAME))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn launcher_logs_dir_path(app_identifier: &str) -> Option<PathBuf> {
|
||||
Self::initial_settings_dir_path(app_identifier)
|
||||
.map(|d| d.join(LAUNCHER_LOGS_FOLDER_NAME))
|
||||
}
|
||||
|
||||
@@ -176,15 +195,15 @@ impl DirectoryInfo {
|
||||
settings: &mut Settings,
|
||||
exec: E,
|
||||
io_semaphore: &IoSemaphore,
|
||||
app_identifier: &str,
|
||||
) -> crate::Result<()>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Sqlite> + Copy,
|
||||
{
|
||||
let app_dir = DirectoryInfo::get_initial_settings_dir().ok_or(
|
||||
crate::ErrorKind::FSError(
|
||||
let app_dir = DirectoryInfo::initial_settings_dir_path(app_identifier)
|
||||
.ok_or(crate::ErrorKind::FSError(
|
||||
"Could not find valid config dir".to_string(),
|
||||
),
|
||||
)?;
|
||||
))?;
|
||||
|
||||
if let Some(ref prev_custom_dir) = settings.prev_custom_dir {
|
||||
let prev_dir = PathBuf::from(prev_custom_dir);
|
||||
|
||||
@@ -71,6 +71,9 @@ pub struct State {
|
||||
/// Process manager
|
||||
pub process_manager: ProcessManager,
|
||||
|
||||
/// App identifier string (like com.modrinth.ModrinthApp)
|
||||
pub app_identifier: String,
|
||||
|
||||
/// Friends socket
|
||||
pub friends_socket: FriendsSocket,
|
||||
|
||||
@@ -80,9 +83,9 @@ pub struct State {
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub async fn init() -> crate::Result<()> {
|
||||
pub async fn init(app_identifier: String) -> crate::Result<()> {
|
||||
let state = LAUNCHER_STATE
|
||||
.get_or_try_init(Self::initialize_state)
|
||||
.get_or_try_init(move || Self::initialize_state(app_identifier))
|
||||
.await?;
|
||||
|
||||
tokio::task::spawn(async move {
|
||||
@@ -132,9 +135,11 @@ impl State {
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
async fn initialize_state() -> crate::Result<Arc<Self>> {
|
||||
async fn initialize_state(
|
||||
app_identifier: String,
|
||||
) -> crate::Result<Arc<Self>> {
|
||||
tracing::info!("Connecting to app database");
|
||||
let pool = db::connect().await?;
|
||||
let pool = db::connect(&app_identifier).await?;
|
||||
|
||||
legacy_converter::migrate_legacy_data(&pool).await?;
|
||||
|
||||
@@ -153,9 +158,12 @@ impl State {
|
||||
&mut settings,
|
||||
&pool,
|
||||
&io_semaphore,
|
||||
&app_identifier,
|
||||
)
|
||||
.await?;
|
||||
let directories = DirectoryInfo::init(settings.custom_dir).await?;
|
||||
|
||||
let directories =
|
||||
DirectoryInfo::init(settings.custom_dir, &app_identifier).await?;
|
||||
|
||||
let discord_rpc = DiscordGuard::init()?;
|
||||
|
||||
@@ -177,6 +185,7 @@ impl State {
|
||||
friends_socket,
|
||||
pool,
|
||||
file_watcher,
|
||||
app_identifier,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user