diff --git a/wallettemplate/src/main/java/wallettemplate/utils/AppDataDirectory.java b/core/src/main/java/org/bitcoinj/utils/AppDataDirectory.java similarity index 51% rename from wallettemplate/src/main/java/wallettemplate/utils/AppDataDirectory.java rename to core/src/main/java/org/bitcoinj/utils/AppDataDirectory.java index 7856e7bf8..f421084cd 100644 --- a/wallettemplate/src/main/java/wallettemplate/utils/AppDataDirectory.java +++ b/core/src/main/java/org/bitcoinj/utils/AppDataDirectory.java @@ -14,16 +14,25 @@ * limitations under the License. */ -package wallettemplate.utils; +package org.bitcoinj.utils; import org.bitcoinj.core.Utils; import java.io.IOException; +import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; /** * Find/create App Data Directory in correct platform-specific location. + * This class is based on the conventions used in Bitcoin Core which + * uses the following locations: + *
+ *
Windows
{@code ${APPDATA}/.bitcoin}
+ *
macOS
{@code ${HOME}/Library/Application Support/Bitcoin}
+ *
Linux
{@code ${HOME}/.bitcoin}
+ *
+ * Note that {@code appName} is converted to lower-case on Windows and Linux/Unix. */ public class AppDataDirectory { @@ -45,19 +54,36 @@ public class AppDataDirectory { return applicationDataDirectory; } - private static Path getPath(String appName) { + /** + * Return the Path to the application data directory without making + * sure it exists or creating it. (No disk I/O) + * + * @param appName The name of the current application + * @return Path to the application data directory + */ + public static Path getPath(String appName) { final Path applicationDataDirectory; if (Utils.isWindows()) { - applicationDataDirectory = Path.of(System.getenv("APPDATA"), appName.toLowerCase()); + applicationDataDirectory = pathOf(System.getenv("APPDATA"), appName.toLowerCase()); } else if (Utils.isMac()) { - applicationDataDirectory = Path.of(System.getProperty("user.home"),"Library/Application Support", appName); + applicationDataDirectory = pathOf(System.getProperty("user.home"),"Library/Application Support", appName); } else if (Utils.isLinux()) { - applicationDataDirectory = Path.of(System.getProperty("user.home"), "." + appName.toLowerCase()); + applicationDataDirectory = pathOf(System.getProperty("user.home"), "." + appName.toLowerCase()); } else { // Unknown, assume unix-like - applicationDataDirectory = Path.of(System.getProperty("user.home"), "." + appName.toLowerCase()); + applicationDataDirectory = pathOf(System.getProperty("user.home"), "." + appName.toLowerCase()); } return applicationDataDirectory; } + + /** + * Create a {@code Path} by joining path strings. Same functionality as Path.of() in JDK 11+ + * @param first A base path string + * @param additional additional components to add + * @return the joined {@code Path} + */ + private static Path pathOf(String first, String... additional) { + return FileSystems.getDefault().getPath(first, additional); + } } diff --git a/core/src/main/java/org/bitcoinj/utils/BlockFileLoader.java b/core/src/main/java/org/bitcoinj/utils/BlockFileLoader.java index ae728e984..3c781f223 100644 --- a/core/src/main/java/org/bitcoinj/utils/BlockFileLoader.java +++ b/core/src/main/java/org/bitcoinj/utils/BlockFileLoader.java @@ -71,16 +71,9 @@ public class BlockFileLoader implements Iterable, Iterator { } public static File defaultBlocksDir() { - final File defaultBlocksDir; - if (Utils.isWindows()) { - defaultBlocksDir = new File(System.getenv("APPDATA") + "\\.bitcoin\\blocks\\"); - } else if (Utils.isMac()) { - defaultBlocksDir = new File(System.getProperty("user.home") + "/Library/Application Support/Bitcoin/blocks/"); - } else if (Utils.isLinux()) { - defaultBlocksDir = new File(System.getProperty("user.home") + "/.bitcoin/blocks/"); - } else { - throw new RuntimeException("Unsupported system"); - } + File defaultBlocksDir = AppDataDirectory.getPath("Bitcoin").resolve("blocks").toFile(); + if (!defaultBlocksDir.isDirectory()) + throw new RuntimeException("Default blocks directory not found"); return defaultBlocksDir; } diff --git a/core/src/test/java/org/bitcoinj/utils/AppDataDirectoryTest.java b/core/src/test/java/org/bitcoinj/utils/AppDataDirectoryTest.java new file mode 100644 index 000000000..ff54c0704 --- /dev/null +++ b/core/src/test/java/org/bitcoinj/utils/AppDataDirectoryTest.java @@ -0,0 +1,72 @@ +/* + * Copyright 2019 Michael Sean Gilligan + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.bitcoinj.utils; + +import org.bitcoinj.core.Utils; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Basic test of AppDataDirectory + */ +public class AppDataDirectoryTest { + private static final String HOMEDIR = System.getProperty("user.home"); + private static final String WINAPPDATA = System.getenv("APPDATA"); + + @Test + public void worksOnCurrentPlatform() { + final String appName = "bitcoinj"; + String path = AppDataDirectory.get(appName).toString(); + if (Utils.isWindows()) { + assertEquals("Path wrong on Mac", winPath(appName), path); + } else if (Utils.isMac()) { + assertEquals("Path wrong on Mac", macPath(appName), path); + } else if (Utils.isLinux()) { + assertEquals("Path wrong on Linux", unixPath(appName), path); + } else { + assertEquals("Path wrong on unknown/default", unixPath(appName), path); + } + } + + @Test + public void worksOnCurrentPlatformForBitcoinCore() { + final String appName = "Bitcoin"; + String path = AppDataDirectory.get(appName).toString(); + if (Utils.isWindows()) { + assertEquals("Path wrong on Mac", winPath(appName), path); + } else if (Utils.isMac()) { + assertEquals("Path wrong on Mac", macPath(appName), path); + } else if (Utils.isLinux()) { + assertEquals("Path wrong on Linux", unixPath(appName), path); + } else { + assertEquals("Path wrong on unknown/default", unixPath(appName), path); + } + } + + private static String winPath(String appName) { + return WINAPPDATA + "\\." + appName.toLowerCase(); + } + + private static String macPath(String appName) { + return HOMEDIR + "/Library/Application Support/" + appName; + } + + private static String unixPath(String appName) { + return HOMEDIR + "/." + appName.toLowerCase(); + } +} diff --git a/wallettemplate/src/main/java/wallettemplate/Main.java b/wallettemplate/src/main/java/wallettemplate/Main.java index 97cc91bf9..3a2b0a062 100644 --- a/wallettemplate/src/main/java/wallettemplate/Main.java +++ b/wallettemplate/src/main/java/wallettemplate/Main.java @@ -18,6 +18,7 @@ package wallettemplate; import com.google.common.util.concurrent.*; import javafx.scene.input.*; +import org.bitcoinj.utils.AppDataDirectory; import org.bitcoinj.core.NetworkParameters; import org.bitcoinj.core.Utils; import org.bitcoinj.kits.WalletAppKit; @@ -35,7 +36,6 @@ import javafx.scene.layout.Pane; import javafx.scene.layout.StackPane; import javafx.stage.Stage; import wallettemplate.controls.NotificationBarPane; -import wallettemplate.utils.AppDataDirectory; import wallettemplate.utils.GuiUtils; import wallettemplate.utils.TextFieldValidator;