mirror of
https://github.com/processing/processing4.git
synced 2026-06-16 04:26:26 +02:00
Rewrite of the Base.getSettingsFolder() and Platform.getSettingsFolder() (#1335)
* Rewrite of the `Base.getSettingsFolder()` and `Platform.getSettingsFolder()` Rewrote both function so they fit into a single file, negating the need for hopping around when looking into what this functionality does. Also rewrote it so it is no longer generates random awt windows through the `Messages` class * Fixed issue with missing / * Added both options for overrides - Added the previous settings override in base again - Added a system property to override the settings folder within tests * Add support for portable settings detection Introduces logic to detect a preferences.txt file in the same folder as the running executable or jar. If found, settings are loaded from this location, improving portability and allowing users to override default settings without modifying system directories.
This commit is contained in:
@@ -2212,29 +2212,54 @@ public class Base {
|
||||
* something similar on Windows, a dot folder on Linux.) Removed this as a
|
||||
* preference for 3.0a3 because we need this to be stable, but adding back
|
||||
* for 4.0 beta 4 so that folks can do 'portable' versions again.
|
||||
*
|
||||
* @deprecated use processing.utils.Settings.getFolder() instead, this method will invoke AWT
|
||||
*/
|
||||
static public File getSettingsFolder() {
|
||||
File settingsFolder = null;
|
||||
|
||||
try {
|
||||
settingsFolder = Platform.getSettingsFolder();
|
||||
|
||||
// create the folder if it doesn't exist already
|
||||
if (!settingsFolder.exists()) {
|
||||
if (!settingsFolder.mkdirs()) {
|
||||
Messages.showError("Settings issues",
|
||||
"Processing cannot run because it could not\n" +
|
||||
"create a folder to store your settings at\n" +
|
||||
settingsFolder, null);
|
||||
}
|
||||
var override = getSettingsOverride();
|
||||
if (override != null) {
|
||||
return override;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Messages.showTrace("An rare and unknowable thing happened",
|
||||
"Could not get the settings folder. Please report:\n" +
|
||||
"http://github.com/processing/processing/issues/new",
|
||||
e, true);
|
||||
}
|
||||
return settingsFolder;
|
||||
try {
|
||||
return processing.utils.Settings.getFolder();
|
||||
} catch (processing.utils.Settings.SettingsFolderException e) {
|
||||
switch (e.getType()) {
|
||||
case COULD_NOT_CREATE_FOLDER -> Messages.showError("Settings issues",
|
||||
"""
|
||||
Processing cannot run because it could not
|
||||
create a folder to store your settings at
|
||||
""" + e.getMessage(), null);
|
||||
case WINDOWS_APPDATA_NOT_FOUND -> Messages.showError("Settings issues",
|
||||
"""
|
||||
Processing cannot run because it could not
|
||||
find the AppData or LocalAppData folder on your system.
|
||||
""", null);
|
||||
case MACOS_LIBRARY_FOLDER_NOT_FOUND -> Messages.showError("Settings issues",
|
||||
"""
|
||||
Processing cannot run because it could not
|
||||
find the Library folder on your system.
|
||||
""", null);
|
||||
case LINUX_CONFIG_FOLDER_NOT_FOUND -> Messages.showError("Settings issues",
|
||||
"""
|
||||
Processing cannot run because either your
|
||||
XDG_CONFIG_HOME or SNAP_USER_COMMON is set
|
||||
but the folder does not exist.
|
||||
""", null);
|
||||
case LINUX_SUDO_USER_ERROR -> Messages.showError("Settings issues",
|
||||
"""
|
||||
Processing cannot run because it was started
|
||||
with sudo and Processing could not resolve
|
||||
the original users home directory.
|
||||
""", null);
|
||||
default -> Messages.showTrace("An rare and unknowable thing happened",
|
||||
"""
|
||||
Could not get the settings folder. Please report:
|
||||
http://github.com/processing/processing4/issues/new
|
||||
""",
|
||||
e, true);
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Unreachable code in Base.getSettingsFolder()");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class Platform {
|
||||
public class Platform extends processing.utils.Platform {
|
||||
static DefaultPlatform inst;
|
||||
|
||||
/*
|
||||
@@ -136,12 +136,7 @@ public class Platform {
|
||||
}
|
||||
|
||||
|
||||
static public File getSettingsFolder() throws Exception {
|
||||
return inst.getSettingsFolder();
|
||||
}
|
||||
|
||||
|
||||
static public File getDefaultSketchbookFolder() throws Exception {
|
||||
static public File getDefaultSketchbookFolder() throws Exception {
|
||||
return inst.getDefaultSketchbookFolder();
|
||||
}
|
||||
|
||||
@@ -303,29 +298,8 @@ public class Platform {
|
||||
// the MACOSX constant would instead read as the LINUX constant.
|
||||
|
||||
|
||||
/**
|
||||
* returns true if Processing is running on a Mac OS X machine.
|
||||
*/
|
||||
static public boolean isMacOS() {
|
||||
return System.getProperty("os.name").contains("Mac"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* returns true if running on windows.
|
||||
*/
|
||||
static public boolean isWindows() {
|
||||
return System.getProperty("os.name").contains("Windows"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* true if running on linux.
|
||||
*/
|
||||
static public boolean isLinux() {
|
||||
return System.getProperty("os.name").contains("Linux"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
|
||||
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
|
||||
@@ -3,10 +3,13 @@ package processing.app
|
||||
import androidx.compose.runtime.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import processing.utils.Settings
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.nio.file.*
|
||||
import java.util.Properties
|
||||
import java.nio.file.FileSystems
|
||||
import java.nio.file.StandardWatchEventKinds
|
||||
import java.nio.file.WatchEvent
|
||||
import java.util.*
|
||||
|
||||
|
||||
const val PREFERENCES_FILE_NAME = "preferences.txt"
|
||||
@@ -20,7 +23,7 @@ fun PlatformStart(){
|
||||
fun loadPreferences(): Properties{
|
||||
PlatformStart()
|
||||
|
||||
val settingsFolder = Platform.getSettingsFolder()
|
||||
val settingsFolder = Settings.getFolder()
|
||||
val preferencesFile = settingsFolder.resolve(PREFERENCES_FILE_NAME)
|
||||
|
||||
if(!preferencesFile.exists()){
|
||||
|
||||
@@ -23,24 +23,19 @@
|
||||
|
||||
package processing.app.platform;
|
||||
|
||||
import java.awt.Desktop;
|
||||
import java.awt.Font;
|
||||
import java.io.File;
|
||||
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.FlatLightLaf;
|
||||
import com.sun.jna.Library;
|
||||
import com.sun.jna.Native;
|
||||
|
||||
import processing.app.Base;
|
||||
import processing.app.Preferences;
|
||||
import processing.app.ui.Toolkit;
|
||||
import processing.awt.ShimAWT;
|
||||
import processing.core.PApplet;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
|
||||
|
||||
/**
|
||||
* Used by Base for platform-specific tweaking, for instance finding the
|
||||
@@ -206,24 +201,7 @@ public class DefaultPlatform {
|
||||
public void saveLanguage(String languageCode) { }
|
||||
|
||||
|
||||
/**
|
||||
* This function should throw an exception or return a value.
|
||||
* Do not return null.
|
||||
*/
|
||||
public File getSettingsFolder() throws Exception {
|
||||
File override = Base.getSettingsOverride();
|
||||
if (override != null) {
|
||||
return override;
|
||||
}
|
||||
|
||||
// If no subclass has a behavior, default to making a
|
||||
// ".processing" directory in the user's home directory.
|
||||
File home = new File(System.getProperty("user.home"));
|
||||
return new File(home, ".processing");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* @return if not overridden, a folder named "sketchbook" in user.home.
|
||||
* @throws Exception so that subclasses can throw a fit
|
||||
*/
|
||||
|
||||
@@ -22,16 +22,13 @@
|
||||
|
||||
package processing.app.platform;
|
||||
|
||||
import java.io.File;
|
||||
import java.awt.Desktop;
|
||||
import java.awt.Toolkit;
|
||||
|
||||
import processing.app.Base;
|
||||
import processing.app.Messages;
|
||||
import processing.app.Preferences;
|
||||
import processing.core.PApplet;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
|
||||
|
||||
public class LinuxPlatform extends DefaultPlatform {
|
||||
@@ -90,40 +87,7 @@ public class LinuxPlatform extends DefaultPlatform {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public File getSettingsFolder() throws Exception {
|
||||
File override = Base.getSettingsOverride();
|
||||
if (override != null) {
|
||||
return override;
|
||||
}
|
||||
|
||||
// https://github.com/processing/processing4/issues/203
|
||||
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||
|
||||
File configHome = null;
|
||||
|
||||
// Check to see if the user has set a different location for their config
|
||||
String configHomeEnv = System.getenv("XDG_CONFIG_HOME");
|
||||
if (configHomeEnv != null && !configHomeEnv.isBlank()) {
|
||||
configHome = new File(configHomeEnv);
|
||||
if (!configHome.exists()) {
|
||||
Messages.err("XDG_CONFIG_HOME is set to " + configHomeEnv + " but does not exist.");
|
||||
configHome = null; // don't use non-existent folder
|
||||
}
|
||||
}
|
||||
String snapUserCommon = System.getenv("SNAP_USER_COMMON");
|
||||
if (snapUserCommon != null && !snapUserCommon.isBlank()) {
|
||||
configHome = new File(snapUserCommon);
|
||||
}
|
||||
// If not set properly, use the default
|
||||
if (configHome == null) {
|
||||
configHome = new File(getHomeDir(), ".config");
|
||||
}
|
||||
return new File(configHome, "processing");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public File getDefaultSketchbookFolder() throws Exception {
|
||||
return new File(getHomeDir(), "sketchbook");
|
||||
}
|
||||
|
||||
@@ -22,23 +22,20 @@
|
||||
|
||||
package processing.app.platform;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.desktop.AppReopenedEvent;
|
||||
import java.awt.desktop.AppReopenedListener;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
|
||||
import processing.app.Base;
|
||||
import processing.app.Messages;
|
||||
import processing.app.ui.About;
|
||||
import processing.core.PApplet;
|
||||
import processing.data.StringList;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.desktop.AppReopenedListener;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
|
||||
/**
|
||||
* Platform handler for macOS.
|
||||
@@ -112,16 +109,7 @@ public class MacPlatform extends DefaultPlatform {
|
||||
}
|
||||
|
||||
|
||||
public File getSettingsFolder() throws Exception {
|
||||
File override = Base.getSettingsOverride();
|
||||
if (override != null) {
|
||||
return override;
|
||||
}
|
||||
return new File(getLibraryFolder(), "Processing");
|
||||
}
|
||||
|
||||
|
||||
public File getDefaultSketchbookFolder() throws Exception {
|
||||
public File getDefaultSketchbookFolder() throws Exception {
|
||||
return new File(getDocumentsFolder(), "Processing");
|
||||
}
|
||||
|
||||
@@ -144,19 +132,6 @@ public class MacPlatform extends DefaultPlatform {
|
||||
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
|
||||
// TODO I suspect this won't work much longer, since access to the user's
|
||||
// home directory seems verboten on more recent macOS versions [fry 191008]
|
||||
// However, anecdotally it seems that just using the name works,
|
||||
// and the localization is handled transparently. [fry 220116]
|
||||
// https://github.com/processing/processing4/issues/9
|
||||
protected String getLibraryFolder() throws FileNotFoundException {
|
||||
File folder = new File(System.getProperty("user.home"), "Library");
|
||||
if (!folder.exists()) {
|
||||
throw new FileNotFoundException("Folder missing: " + folder);
|
||||
}
|
||||
return folder.getAbsolutePath();
|
||||
}
|
||||
|
||||
|
||||
// TODO See above, and https://github.com/processing/processing4/issues/9
|
||||
protected String getDocumentsFolder() throws FileNotFoundException {
|
||||
|
||||
@@ -22,20 +22,22 @@
|
||||
|
||||
package processing.app.platform;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import com.sun.jna.Library;
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.platform.win32.*;
|
||||
|
||||
import processing.app.*;
|
||||
import com.sun.jna.platform.win32.GDI32;
|
||||
import com.sun.jna.platform.win32.Shell32Util;
|
||||
import com.sun.jna.platform.win32.ShlObj;
|
||||
import com.sun.jna.platform.win32.WinDef;
|
||||
import processing.app.Base;
|
||||
import processing.app.Messages;
|
||||
import processing.app.Preferences;
|
||||
import processing.app.platform.WindowsRegistry.REGISTRY_ROOT_KEY;
|
||||
|
||||
import processing.core.PApplet;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
|
||||
// With the changes to include .pyde files for 3.4, this class is
|
||||
// a bit of a mess. Registering a single extension has moved to
|
||||
@@ -351,54 +353,6 @@ public class WindowsPlatform extends DefaultPlatform {
|
||||
}
|
||||
|
||||
|
||||
// looking for Documents and Settings/blah/Application Data/Processing
|
||||
public File getSettingsFolder() throws Exception {
|
||||
File override = Base.getSettingsOverride();
|
||||
if (override != null) {
|
||||
return override;
|
||||
}
|
||||
|
||||
try {
|
||||
String appDataRoaming = getAppDataPath();
|
||||
if (appDataRoaming != null) {
|
||||
File settingsFolder = new File(appDataRoaming, APP_NAME);
|
||||
if (settingsFolder.exists() || settingsFolder.mkdirs()) {
|
||||
return settingsFolder;
|
||||
}
|
||||
}
|
||||
|
||||
String appDataLocal = getLocalAppDataPath();
|
||||
if (appDataLocal != null) {
|
||||
File settingsFolder = new File(appDataLocal, APP_NAME);
|
||||
if (settingsFolder.exists() || settingsFolder.mkdirs()) {
|
||||
return settingsFolder;
|
||||
}
|
||||
}
|
||||
|
||||
if (appDataRoaming == null && appDataLocal == null) {
|
||||
throw new IOException("Could not get the AppData folder");
|
||||
}
|
||||
|
||||
// https://github.com/processing/processing/issues/3838
|
||||
throw new IOException("Permissions error: make sure that " +
|
||||
appDataRoaming + " or " + appDataLocal +
|
||||
" is writable.");
|
||||
|
||||
} catch (UnsatisfiedLinkError ule) {
|
||||
String path = new File("lib").getCanonicalPath();
|
||||
|
||||
String msg = Util.containsNonASCII(path) ?
|
||||
"""
|
||||
Please move Processing to a location with only
|
||||
ASCII characters in the path and try again.
|
||||
https://github.com/processing/processing/issues/3543
|
||||
""" :
|
||||
"Could not find JNA support files, please reinstall Processing.";
|
||||
Messages.showError("Windows JNA Problem", msg, ule);
|
||||
return null; // unreachable
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
What's happening internally with JNA https://github.com/java-native-access/jna/blob/master/contrib/platform/src/com/sun/jna/platform/win32/Shell32.java
|
||||
@@ -413,19 +367,7 @@ public class WindowsPlatform extends DefaultPlatform {
|
||||
*/
|
||||
|
||||
|
||||
/** Get the Users\name\AppData\Roaming path to write settings files. */
|
||||
static private String getAppDataPath() {
|
||||
return Shell32Util.getSpecialFolderPath(ShlObj.CSIDL_APPDATA, true);
|
||||
}
|
||||
|
||||
|
||||
/** Get the Users\name\AppData\Local path as a settings fallback. */
|
||||
static private String getLocalAppDataPath() {
|
||||
return Shell32Util.getSpecialFolderPath(ShlObj.CSIDL_LOCAL_APPDATA, true);
|
||||
}
|
||||
|
||||
|
||||
/** Get the Documents and Settings\name\My Documents\Processing folder. */
|
||||
/** Get the Documents and Settings\name\My Documents\Processing folder. */
|
||||
public File getDefaultSketchbookFolder() throws Exception {
|
||||
String documentsPath = getDocumentsPath();
|
||||
if (documentsPath != null) {
|
||||
|
||||
@@ -4,9 +4,9 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
import processing.app.Messages
|
||||
import processing.app.Platform
|
||||
import processing.app.PlatformStart
|
||||
import processing.app.watchFile
|
||||
import processing.utils.Settings
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.util.*
|
||||
@@ -42,7 +42,7 @@ val LocalLocale = compositionLocalOf { Locale() }
|
||||
fun LocaleProvider(content: @Composable () -> Unit) {
|
||||
PlatformStart()
|
||||
|
||||
val settingsFolder = Platform.getSettingsFolder()
|
||||
val settingsFolder = Settings.getFolder()
|
||||
val languageFile = File(settingsFolder, "language.txt")
|
||||
watchFile(languageFile)
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package processing.utils;
|
||||
|
||||
public class Platform {
|
||||
/**
|
||||
* returns true if Processing is running on a Mac OS X machine.
|
||||
*/
|
||||
static public boolean isMacOS() {
|
||||
return System.getProperty("os.name").contains("Mac"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* returns true if running on windows.
|
||||
*/
|
||||
static public boolean isWindows() {
|
||||
return System.getProperty("os.name").contains("Windows"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* true if running on linux.
|
||||
*/
|
||||
static public boolean isLinux() {
|
||||
return System.getProperty("os.name").contains("Linux"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package processing.utils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Optional;
|
||||
|
||||
public class Settings {
|
||||
public static File getFolder() throws SettingsFolderException {
|
||||
try {
|
||||
var folder = getFolderForPlatform();
|
||||
if (!folder.exists() && !folder.mkdirs()) {
|
||||
throw new SettingsFolderException(SettingsFolderException.Type.COULD_NOT_CREATE_FOLDER, folder.getAbsolutePath());
|
||||
}
|
||||
return folder;
|
||||
} catch (RuntimeException e) {
|
||||
throw new SettingsFolderException(SettingsFolderException.Type.UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
private static File getFolderForPlatform() throws SettingsFolderException {
|
||||
var settingsOverride = System.getProperty("processing.settings.folder");
|
||||
if (settingsOverride != null && !settingsOverride.isEmpty()) {
|
||||
return new File(settingsOverride);
|
||||
}
|
||||
|
||||
var portableSettings = FindPortableSettings();
|
||||
if (portableSettings.isPresent()) {
|
||||
return portableSettings.get();
|
||||
}
|
||||
|
||||
if (Platform.isWindows()) {
|
||||
var options = new String[]{
|
||||
"APPDATA",
|
||||
"LOCALAPPDATA"
|
||||
};
|
||||
for (String option : options) {
|
||||
var folder = new File(System.getenv(option), "Processing");
|
||||
if (!folder.exists() && !folder.mkdirs()) {
|
||||
continue;
|
||||
}
|
||||
return folder;
|
||||
}
|
||||
throw new SettingsFolderException(SettingsFolderException.Type.WINDOWS_APPDATA_NOT_FOUND);
|
||||
}
|
||||
if (Platform.isMacOS()) {
|
||||
var folder = new File(System.getProperty("user.home"), "Library");
|
||||
if (!folder.exists()) {
|
||||
throw new SettingsFolderException(SettingsFolderException.Type.MACOS_LIBRARY_FOLDER_NOT_FOUND);
|
||||
}
|
||||
return new File(folder, "Processing");
|
||||
}
|
||||
if (Platform.isLinux()) {
|
||||
var options = new String[]{
|
||||
"SNAP_USER_COMMON",
|
||||
"XDG_CONFIG_HOME"
|
||||
};
|
||||
for (String option : options) {
|
||||
var configHomeEnv = System.getenv(option);
|
||||
if (configHomeEnv == null || configHomeEnv.isBlank()) {
|
||||
continue;
|
||||
}
|
||||
var parentFolder = new File(configHomeEnv);
|
||||
if (!parentFolder.exists()) {
|
||||
throw new SettingsFolderException(SettingsFolderException.Type.LINUX_CONFIG_FOLDER_NOT_FOUND);
|
||||
}
|
||||
var folder = new File(parentFolder, "processing");
|
||||
if (!folder.exists() && !folder.mkdirs()) {
|
||||
continue;
|
||||
}
|
||||
return folder;
|
||||
}
|
||||
var subfolder = "/.config/processing";
|
||||
var isSudo = System.getenv("SUDO_USER");
|
||||
if (isSudo == null || isSudo.isEmpty()) {
|
||||
return new File(System.getProperty("user.home") + subfolder);
|
||||
}
|
||||
// If user is SUDO_USER, try to get their home directory
|
||||
try {
|
||||
var process = Runtime.getRuntime().exec(
|
||||
new String[]{
|
||||
"/bin/sh", "-c", "echo ~" + isSudo
|
||||
}
|
||||
);
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
|
||||
return new File(reader.readLine() + subfolder);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new SettingsFolderException(SettingsFolderException.Type.LINUX_SUDO_USER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
// If all else fails, use ~/.processing
|
||||
return new File(System.getProperty("user.home"), ".processing");
|
||||
}
|
||||
|
||||
/**
|
||||
* find a preferences.txt file in the same folder as the running jar/executable
|
||||
*
|
||||
* @return Optional File pointing to preferences.txt if found, empty otherwise
|
||||
*/
|
||||
private static Optional<File> FindPortableSettings() {
|
||||
var command = ProcessHandle.current().info().command();
|
||||
if (command.isEmpty()) return Optional.empty();
|
||||
|
||||
var path = command.get();
|
||||
path = path.replaceAll("/[^/]+$", "");
|
||||
|
||||
if (Platform.isMacOS()) {
|
||||
// On macOS, the executable is inside the .app bundle, so we need to go up to above the .app folder
|
||||
path = path.replaceAll("/[^/]+\\.app/.*$", "");
|
||||
}
|
||||
var file = new File(path, "preferences.txt");
|
||||
if (System.getenv().containsKey("DEBUG"))
|
||||
System.out.println("Looking for portable settings at: " + file.getAbsolutePath());
|
||||
|
||||
if (!file.exists()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(new File(path));
|
||||
|
||||
}
|
||||
|
||||
public static class SettingsFolderException extends Exception {
|
||||
public enum Type {
|
||||
COULD_NOT_CREATE_FOLDER,
|
||||
WINDOWS_APPDATA_NOT_FOUND,
|
||||
MACOS_LIBRARY_FOLDER_NOT_FOUND,
|
||||
LINUX_CONFIG_FOLDER_NOT_FOUND,
|
||||
LINUX_SUDO_USER_ERROR,
|
||||
UNKNOWN
|
||||
}
|
||||
|
||||
private final Type type;
|
||||
|
||||
public SettingsFolderException(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public SettingsFolderException(Type type, String message) {
|
||||
super(message);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import org.junit.jupiter.api.Test;
|
||||
import processing.utils.Settings;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
||||
public class SettingsTest {
|
||||
|
||||
/**
|
||||
* Requesting the settings folder should create it if it doesn't exist
|
||||
*/
|
||||
@Test
|
||||
public void testSettingsFolder() {
|
||||
try {
|
||||
var folder = Settings.getFolder();
|
||||
assert (folder.exists());
|
||||
} catch (Settings.SettingsFolderException e) {
|
||||
assert (false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriding the settings folder via system property should work
|
||||
*/
|
||||
@Test
|
||||
public void testOverrideFolder() throws IOException {
|
||||
var settings = Files.createTempDirectory("settings_test");
|
||||
System.setProperty("processing.settings.folder", settings.toString());
|
||||
|
||||
try {
|
||||
var folder = Settings.getFolder();
|
||||
assert (folder.toPath().toString().equals(settings.toString()));
|
||||
} catch (Settings.SettingsFolderException e) {
|
||||
assert (false);
|
||||
} finally {
|
||||
System.clearProperty("processing.settings.folder");
|
||||
Files.deleteIfExists(settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user