Browse / github.com/storytold/craft-launcher / patch
Add CraftSuite install location option
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- Squithy (imported from pull request #560, open)
- Base
307efcf45a080af9643e750d43034eb25540cef8- Size
- +55 −12 in 15 files
- Review
- pending
- Shared
- 2026-10-28
- Id
805dc3350da49d8c58f436c5
How it went
No other operator has reported using it yet.
Diff
raw · crates/native/src/detect.rs crates/native/src/install.rs crates/native/src/self_update.rs crates/ui-egui/src/dialogs.rs crates/ui-egui/src/i18n/cs.tsv crates/ui-egui/src/i18n/de.tsv crates/ui-egui/src/i18n/es.tsv crates/ui-egui/src/i18n/fr.tsv crates/ui-egui/src/i18n/hu.tsv crates/ui-egui/src/i18n/ja.tsv crates/ui-egui/src/i18n/pl.tsv crates/ui-egui/src/i18n/pt-BR.tsv crates/ui-egui/src/i18n/ru.tsv crates/ui-egui/src/i18n/zh-CN.tsv crates/ui-egui/tests/ui.rs
@@ -1,6 +1,7 @@ //! Finding Craft Apps that are already installed, however they got there. //!-//! - macOS: `<App>.app` in `/Applications` or `~/Applications`, read from its `Info.plist`.+//! - macOS: `<App>.app` in `/Applications`, `/Applications/CraftSuite` or `~/Applications`, read+//! from its `Info.plist`. //! - Windows: the Windows Installer's uninstall entries (`Learning Machines LLC`), and portable //! copies the launcher unpacked. //! - Linux: AppImages in `~/Applications` (where the launcher and AppImageLauncher put them),@@ -143,10 +144,10 @@ pub mod macos { use super::*; - /// Where a `.app` might be: the system and the user's Applications folders.+ /// Where a `.app` might be: the system, CraftSuite and the user's Applications folders. pub fn candidates(app: &CraftApp) -> Vec<PathBuf> { let bundle = format!("{}.app", app.name);- let mut out = vec![Path::new("/Applications").join(&bundle)];+ let mut out = vec![Path::new("/Applications").join(&bundle), Path::new("/Applications/CraftSuite").join(&bundle)]; if let Some(home) = dirs::home_dir() { out.push(home.join("Applications").join(&bundle)); }@@ -530,6 +531,13 @@ mod tests { } } + #[cfg(target_os = "macos")]+ #[test]+ fn looks_for_apps_in_the_craft_suite_folder() {+ let app = CraftApp::by_id("photocraft").unwrap();+ assert!(macos::candidates(app).contains(&PathBuf::from("/Applications/CraftSuite/PhotoCraft.app")));+ }+ #[test] fn parse_cli_version_accepts_id_display_name_and_former_id() { let photo = CraftApp::by_id("photocraft").unwrap();@@ -2,7 +2,7 @@ //! //! Apps go where their platform keeps applications, installed the platform's own way: //!-//! - macOS: the signed `.app` from the release DMG into `/Applications`.+//! - macOS: the signed `.app` from the release DMG into `/Applications` or the selected folder. //! - Windows: the release MSI (Windows Installer) into `C:\Program Files\<App>`. //! - Linux: the distro's own package (`.deb` through apt on the Debian family, `.rpm` through //! dnf/zypper/rpm on the Fedora, Red Hat and SUSE families, read from `os-release`) with the@@ -207,9 +207,7 @@ fn selected_folder(folder: &str, writable: bool) -> Result<PathBuf, String> { if !path.is_absolute() { return Err(invalid("choose an absolute path")); }- if !path.is_dir() {- return Err(invalid("the folder is unavailable. Create it or reconnect its drive first"));- }+ std::fs::create_dir_all(&path).map_err(|e| invalid(&format!("couldn't create the folder ({e})")))?; if writable { let probe = path.join(format!( ".artcraft-launcher-write-test-{}-{}",@@ -1405,7 +1403,7 @@ mod tests { use super::*; #[test]- fn selected_folders_must_exist_and_leave_no_probe_files() {+ fn selected_folders_are_created_and_leave_no_probe_files() { let dir = tempfile::tempdir().unwrap(); assert_eq!(selected_folder(dir.path().to_str().unwrap(), true).unwrap(), dir.path()); assert_eq!(std::fs::read_dir(dir.path()).unwrap().count(), 0);@@ -1416,8 +1414,9 @@ mod tests { assert_eq!(selected_folder(quoted.to_str().unwrap(), true).unwrap(), quoted); } let missing = dir.path().join("unavailable/Apps");- assert!(selected_folder(missing.to_str().unwrap(), true).is_err());- assert!(!missing.exists());+ assert_eq!(selected_folder(missing.to_str().unwrap(), true).unwrap(), missing);+ assert!(missing.is_dir());+ assert_eq!(std::fs::read_dir(&missing).unwrap().count(), 0); assert!(selected_folder("relative/folder", true).is_err()); assert!(selected_folder("bad\nfolder", true).is_err()); let app = CraftApp::by_id("photocraft").unwrap();@@ -181,7 +181,7 @@ pub fn update( #[cfg(target_os = "macos")] Install::MacApp(bundle) => { let existing = Installed { version: None, source: InstallSource::MacApp, location: bundle.display().to_string(), package: None };- let placed = install::macos::install_dmg(&LAUNCHER, &file, Some(&existing), None, paths, &install::macos::Expect::release(release));+ let placed = install::macos::install_dmg(&LAUNCHER, &file, Some(&existing), None, false, paths, &install::macos::Expect::release(release)); let _ = std::fs::remove_file(&file); let placed = placed?; relaunch_after_exit(pid, &[Path::new("/usr/bin/open").as_os_str(), placed.as_os_str()])@@ -371,7 +371,7 @@ mod tests { let existing = Installed { version: None, source: InstallSource::MacApp, location: current.display().to_string(), package: None }; // An unsigned test bundle: the signature check has its own tests in `install`. let expect = install::macos::Expect { team: None, version: None };- let placed = install::macos::install_dmg(&LAUNCHER, &dmg, Some(&existing), None, &Paths::under(dir.path()), &expect).unwrap();+ let placed = install::macos::install_dmg(&LAUNCHER, &dmg, Some(&existing), None, false, &Paths::under(dir.path()), &expect).unwrap(); assert_eq!(placed, current); assert_eq!(std::fs::read_to_string(current.join("Contents/MacOS/ArtCraft Launcher")).unwrap(), "0.2.0"); assert_eq!(@@ -10,6 +10,8 @@ use crate::settings::{CheckEvery, Settings}; use crate::theme::{self, ThemeChoice, Tokens}; use crate::widgets::{self, Cell, Kind}; +const MACOS_CRAFTSUITE_INSTALL_FOLDER: &str = "/Applications/CraftSuite";+ impl LauncherUi { pub(crate) fn dialogs(&mut self, ctx: &egui::Context, host: &mut dyn Host) { let Some(mut dialog) = self.dialog.clone() else {@@ -365,6 +367,13 @@ impl LauncherUi { if self.caps.manage_apps { section(ui, tl!("Default install folder"));+ if self.platform.is_some_and(|p| p.os == Os::MacOs) {+ let mut install_in_craft_suite = self.settings.install_locations.root.as_deref() == Some(MACOS_CRAFTSUITE_INSTALL_FOLDER);+ if ui.checkbox(&mut install_in_craft_suite, tl!("Install new apps in /Applications/CraftSuite")).changed() {+ self.settings.install_locations.root =+ install_in_craft_suite.then(|| MACOS_CRAFTSUITE_INSTALL_FOLDER.to_string());+ }+ } if self.custom_install_folders() { let mut folder = self.settings.install_locations.root.clone().unwrap_or_default(); Self::folder_field(ui, &mut folder, None, host);@@ -318,6 +318,7 @@ filter Installed Nainstalováno System default Výchozí nastavení systému Browse… Procházet… Use default Použít výchozí+ Install new apps in /Applications/CraftSuite Instalovat nové aplikace do /Applications/CraftSuite New installs use this folder. Updates stay in their current location. Nové instalace používají tuto složku. Aktualizace zůstávají v aktuálním umístění. Custom folders use AppImage on Linux. Vlastní složky používají v Linuxu formát AppImage. The system manages install locations here. Umístění instalací zde spravuje systém.@@ -350,6 +350,7 @@ filter Installed Installiert System default Systemstandard Browse… Durchsuchen… Use default Standard verwenden+ Install new apps in /Applications/CraftSuite Neue Apps in /Applications/CraftSuite installieren New installs use this folder. Updates stay in their current location. Neue Installationen verwenden diesen Ordner. Updates bleiben am bisherigen Speicherort. Custom folders use AppImage on Linux. Für eigene Ordner wird unter Linux AppImage verwendet. The system manages install locations here. Das System verwaltet hier die Installationsorte.@@ -331,6 +331,7 @@ filter Installed Instaladas System default Predeterminada del sistema Browse… Examinar… Use default Usar predeterminada+ Install new apps in /Applications/CraftSuite Instalar las aplicaciones nuevas en /Applications/CraftSuite New installs use this folder. Updates stay in their current location. Las nuevas instalaciones usan esta carpeta. Las actualizaciones conservan su ubicación actual. Custom folders use AppImage on Linux. Las carpetas personalizadas usan AppImage en Linux. The system manages install locations here. El sistema gestiona las ubicaciones de instalación aquí.@@ -348,6 +348,7 @@ filter Installed Installées System default Par défaut du système Browse… Parcourir… Use default Par défaut+ Install new apps in /Applications/CraftSuite Installer les nouvelles applications dans /Applications/CraftSuite New installs use this folder. Updates stay in their current location. Les nouvelles installations utilisent ce dossier. Les mises à jour conservent leur emplacement actuel. Custom folders use AppImage on Linux. Les dossiers personnalisés utilisent AppImage sous Linux. The system manages install locations here. Le système gère les emplacements d’installation ici.@@ -351,6 +351,7 @@ filter Installed Telepítve System default Rendszer alapértelmezése Browse… Tallózás… Use default Alapértelmezett használata+ Install new apps in /Applications/CraftSuite Új alkalmazások telepítése ide: /Applications/CraftSuite New installs use this folder. Updates stay in their current location. Az új telepítések ezt a mappát használják. A frissítések a jelenlegi helyükön maradnak. Custom folders use AppImage on Linux. Linuxon az egyéni mappákhoz AppImage szükséges. The system manages install locations here. Itt a rendszer kezeli a telepítési helyeket.@@ -353,6 +353,7 @@ filter Installed インストール済み System default システムの既定 Browse… 参照… Use default 既定を使用+ Install new apps in /Applications/CraftSuite 新しいアプリを /Applications/CraftSuite にインストール New installs use this folder. Updates stay in their current location. 新しいインストールにはこのフォルダーを使用します。更新時は現在の場所を維持します。 Custom folders use AppImage on Linux. Linuxで任意のフォルダーにインストールする場合はAppImageを使用します。 The system manages install locations here. この環境ではシステムがインストール先を管理します。@@ -352,6 +352,7 @@ filter Installed Zainstalowane System default Domyślny systemowy Browse… Przeglądaj… Use default Użyj domyślnego+ Install new apps in /Applications/CraftSuite Instaluj nowe aplikacje w /Applications/CraftSuite New installs use this folder. Updates stay in their current location. Nowe instalacje używają tego folderu. Aktualizacje pozostają w obecnej lokalizacji. Custom folders use AppImage on Linux. W Linuksie własne foldery korzystają z formatu AppImage. The system manages install locations here. W tym środowisku system zarządza lokalizacjami instalacji.@@ -338,6 +338,7 @@ filter Installed Instalados System default Padrão do sistema Browse… Procurar… Use default Usar padrão+ Install new apps in /Applications/CraftSuite Instalar novos aplicativos em /Applications/CraftSuite New installs use this folder. Updates stay in their current location. Novas instalações usam esta pasta. As atualizações mantêm o local atual. Custom folders use AppImage on Linux. Pastas personalizadas usam AppImage no Linux. The system manages install locations here. O sistema gerencia os locais de instalação neste ambiente.@@ -346,6 +346,7 @@ filter Installed Установлены System default По умолчанию в системе Browse… Обзор… Use default Использовать по умолчанию+ Install new apps in /Applications/CraftSuite Устанавливать новые приложения в /Applications/CraftSuite New installs use this folder. Updates stay in their current location. Новые приложения устанавливаются в эту папку. При обновлении текущее расположение сохраняется. Custom folders use AppImage on Linux. В Linux для установки в выбранную папку используется AppImage. The system manages install locations here. В этой среде расположением приложений управляет система.@@ -318,6 +318,7 @@ figcraft Interface design and prototyping 界面设计与原型制作 System default 系统默认 Browse… 浏览… Use default 使用默认+ Install new apps in /Applications/CraftSuite 将新应用安装到 /Applications/CraftSuite New installs use this folder. Updates stay in their current location. 新安装的应用使用此文件夹。更新时保留当前位置。 Custom folders use AppImage on Linux. 在 Linux 上,自定义文件夹使用 AppImage。 The system manages install locations here. 此环境中的安装位置由系统管理。@@ -393,6 +393,23 @@ fn use_default_removes_an_app_override_and_settings_can_reset_the_root() { assert_eq!(h.state().as_ref().unwrap().settings.install_locations.root, None); } +#[test]+fn macos_setting_selects_the_craft_suite_folder_for_new_installs() {+ let (mut h, sent) = harness(ViewMode::Grid, egui::Theme::Light, true);+ h.run_steps(8);+ h.get_by_label("Settings").click();+ h.run_steps(4);+ h.get_by_label("Install new apps in /Applications/CraftSuite").click();+ h.run_steps(3);++ assert_eq!(h.state().as_ref().unwrap().settings.install_locations.root.as_deref(), Some("/Applications/CraftSuite"));+ assert!(+ sent.borrow().iter().any(+ |command| matches!(command, Command::Configure(options) if options.install_locations.root.as_deref() == Some("/Applications/CraftSuite"))+ )+ );+}+ #[cfg(windows)] #[test] fn windows_package_choice_can_select_portable_and_configures_the_backend() {