use os specific default directories

- /Users/<your_user_name>/Library/Application Support/SCM-Manager for OSX
- %APPDATA%\SCM-Manager for Windows
- ~/.scm for Unix
This commit is contained in:
Sebastian Sdorra
2020-04-25 12:38:01 +02:00
parent 5140bdf6b0
commit dd7a727def
5 changed files with 319 additions and 108 deletions

View File

@@ -0,0 +1,141 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package sonia.scm;
import com.google.common.base.Strings;
import sonia.scm.util.SystemUtil;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import java.util.Properties;
/**
* Determines the base directory for SCM-Manager.
* This class should not be used directory, use {@link SCMContextProvider#getBaseDirectory()} instead.
*
* @since 2.0.0
*/
final class BaseDirectory {
/** Environment variable for the SCM-Manager base directory */
static final String ENVIRONMENT_VARIABLE = "SCM_HOME";
/** Java system property for the SCM-Manager base directory */
static final String SYSTEM_PROPERTY = "scm.home";
/** Classpath resource for the SCM-Manager base directory */
@SuppressWarnings("java:S1075") // it is already configurable
static final String CLASSPATH_RESOURCE = "/scm.properties";
/** Property name in resource file */
static final String RESOURCE_PROPERTY = "scm.home";
private final Platform platform;
private final String classPathResource;
private final Map<String,String> environment;
private final Properties systemProperties;
BaseDirectory(Platform platform, String classPathResource, Map<String, String> environment, Properties systemProperties) {
this.platform = platform;
this.classPathResource = classPathResource;
this.environment = environment;
this.systemProperties = systemProperties;
}
/**
* Returns the determined base directory.
*
* @return base directory
*/
static Path get() {
return new BaseDirectory(
SystemUtil.getPlatform(),
CLASSPATH_RESOURCE,
System.getenv(),
System.getProperties()
).find();
}
Path find() {
String directory = getFromResource();
if (Strings.isNullOrEmpty(directory)) {
directory = getFromSystemProperty();
}
if (Strings.isNullOrEmpty(directory)) {
directory = getFromEnvironmentVariable();
}
if (Strings.isNullOrEmpty(directory)) {
directory = getOsSpecificDefault();
}
return Paths.get(directory);
}
private String getFromResource() {
try (InputStream input = BasicContextProvider.class.getResourceAsStream(classPathResource))
{
if (input != null)
{
Properties properties = new Properties();
properties.load(input);
return properties.getProperty(RESOURCE_PROPERTY);
}
}
catch (IOException ex)
{
throw new ConfigurationException("could not load properties form resource " + CLASSPATH_RESOURCE, ex);
}
return null;
}
private String getFromEnvironmentVariable() {
return environment.get(ENVIRONMENT_VARIABLE);
}
private String getFromSystemProperty() {
return systemProperties.getProperty(SYSTEM_PROPERTY);
}
private String getOsSpecificDefault() {
if (platform.isMac()) {
return getOsxDefault();
} else if (platform.isWindows()) {
return getWindowsDefault();
}
return systemProperties.getProperty("user.home") + "/.scm";
}
private String getOsxDefault() {
return systemProperties.getProperty("user.home") + "/Library/Application Support/SCM-Manager";
}
private String getWindowsDefault() {
return environment.get("APPDATA") + "\\SCM-Manager";
}
}

View File

@@ -21,7 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package sonia.scm;
//~--- non-JDK imports --------------------------------------------------------
@@ -30,21 +30,21 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.Locale;
import java.util.Properties;
//~--- JDK imports ------------------------------------------------------------
/**
* The default implementation of {@link SCMContextProvider}.
*
* @author Sebastian Sdorra
*/
@SuppressWarnings("java:S106") // we can not use logger until base directory is not determined
public class BasicContextProvider implements SCMContextProvider
{
@@ -174,58 +174,29 @@ public class BasicContextProvider implements SCMContextProvider
*
* @return base directory SCM-Manager
*/
private File findBaseDirectory()
{
String path = getPathFromResource();
private File findBaseDirectory() {
File directory = BaseDirectory.get().toFile();
if (Util.isEmpty(path))
{
path = System.getProperty(DIRECTORY_PROPERTY);
if (Util.isEmpty(path))
{
path = System.getenv(DIRECTORY_ENVIRONMENT);
if (Util.isEmpty(path))
{
path = System.getProperty("user.home").concat(File.separator).concat(
DIRECTORY_DEFAULT);
}
}
}
File directory = new File(path);
if (!directory.exists() &&!directory.mkdirs())
{
String msg = "could not create home directory at ".concat(
directory.getAbsolutePath());
// do not use logger
// http://www.slf4j.org/codes.html#substituteLogger
System.err.println("===================================================");
System.err.append("Error: ").println(msg);
System.err.println("===================================================");
throw new IllegalStateException(msg);
}
else if (directory.exists() && !directory.canWrite())
{
String msg = "could not modify home directory at ".concat(
directory.getAbsolutePath());
// do not use logger
// http://www.slf4j.org/codes.html#substituteLogger
System.err.println("===================================================");
System.err.append("Error: ").println(msg);
System.err.println("===================================================");
throw new IllegalStateException(msg);
if (!directory.exists() &&!directory.mkdirs()) {
error("could not create home directory at " + directory.getAbsolutePath());
} else if (directory.exists() && !directory.canWrite()) {
error("could not modify home directory at " + directory.getAbsolutePath());
}
return directory;
}
private void error(String msg) {
// do not use logger
// http://www.slf4j.org/codes.html#substituteLogger
System.err.println("===================================================");
System.err.append("Error: ").println(msg);
System.err.println("===================================================");
throw new IllegalStateException(msg);
}
/**
* Find the current stage.
*
@@ -256,11 +227,11 @@ public class BasicContextProvider implements SCMContextProvider
}
private String determineVersion() {
String version = System.getProperty(VERSION_PROPERTY);
if (Strings.isNullOrEmpty(version)) {
version = loadVersion();
String v = System.getProperty(VERSION_PROPERTY);
if (Strings.isNullOrEmpty(v)) {
v = loadVersion();
}
return version;
return v;
}
/**
@@ -304,59 +275,6 @@ public class BasicContextProvider implements SCMContextProvider
return properties.getProperty(MAVEN_PROPERTY_VERSION, VERSION_DEFAULT);
}
//~--- get methods ----------------------------------------------------------
/**
* Load path from classpath resource.
*
*
* @return path from classpath resource or null
*/
private String getPathFromResource()
{
String path = null;
InputStream input = null;
try
{
input =
BasicContextProvider.class.getResourceAsStream(DIRECTORY_RESOURCE);
if (input != null)
{
Properties properties = new Properties();
properties.load(input);
path = properties.getProperty(DIRECTORY_PROPERTY);
}
}
catch (IOException ex)
{
throw new ConfigurationException(
"could not load properties form resource ".concat(DIRECTORY_RESOURCE),
ex);
}
finally
{
// do not use logger or IOUtil,
// http://www.slf4j.org/codes.html#substituteLogger
if (input != null)
{
try
{
input.close();
}
catch (IOException ex)
{
ex.printStackTrace(System.err);
}
}
}
return path;
}
//~--- fields ---------------------------------------------------------------
/** The base directory of the SCM-Manager */

View File

@@ -0,0 +1,127 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package sonia.scm;
import com.google.common.collect.ImmutableMap;
import lombok.Builder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import java.util.Map;
import java.util.Properties;
import static org.assertj.core.api.Assertions.assertThat;
class BaseDirectoryTest {
@Test
void shouldGetFromClassPathResource() {
BaseDirectory directory = builder().withClassPathResource("/sonia/scm/basedirectory.properties").create();
assertThat(directory.find().toString()).isEqualTo("/tmp/scm_home");
}
@Test
void shouldGetFromSystemProperty() {
BaseDirectory directory = builder().withSystemProperty(BaseDirectory.SYSTEM_PROPERTY, "/tmp/scm_home").create();
assertThat(directory.find().toString()).isEqualTo("/tmp/scm_home");
}
@Test
void shouldGetFromEnvironmentVariable() {
BaseDirectory directory = builder().withEnvironment(BaseDirectory.ENVIRONMENT_VARIABLE, "/tmp/scm_home").create();
assertThat(directory.find().toString()).isEqualTo("/tmp/scm_home");
}
@Nested
class OsSpecificDefaults {
@Test
void linux() {
BaseDirectory directory = builder().withSystemProperty("user.home", "/tmp").create();
assertThat(directory.find().toString()).isEqualTo("/tmp/.scm");
}
@Test
void osx() {
BaseDirectory directory = builder().withOsx().withSystemProperty("user.home", "/tmp").create();
assertThat(directory.find().toString()).isEqualTo("/tmp/Library/Application Support/SCM-Manager");
}
@Test
void windows() {
BaseDirectory directory = builder().withWindows().withEnvironment("APPDATA", "/tmp").create();
assertThat(directory.find().toString()).isEqualTo("/tmp\\SCM-Manager");
}
}
private BaseDirectoryBuilder builder() {
return new BaseDirectoryBuilder();
}
static class BaseDirectoryBuilder {
private Platform platform = platform("Linux");
private String classPathResource = "/scm.properties";
private Map<String, String> environment = ImmutableMap.of();
private Properties systemProperties = new Properties();
public BaseDirectoryBuilder withOsx() {
this.platform = platform("Mac OS X");
return this;
}
public BaseDirectoryBuilder withWindows() {
this.platform = platform("Windows");
return this;
}
private Platform platform(String osName) {
return new Platform(osName, "64", "x86_64");
}
public BaseDirectoryBuilder withClassPathResource(String classPathResource) {
this.classPathResource = classPathResource;
return this;
}
public BaseDirectoryBuilder withEnvironment(String key, String value) {
this.environment = ImmutableMap.of(key, value);
return this;
}
public BaseDirectoryBuilder withSystemProperty(String key, String value) {
systemProperties.put(key, value);
return this;
}
public BaseDirectory create() {
return new BaseDirectory(platform, classPathResource, environment, systemProperties);
}
}
}

View File

@@ -21,7 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package sonia.scm;
import org.junit.jupiter.api.BeforeEach;

View File

@@ -0,0 +1,25 @@
#
# MIT License
#
# Copyright (c) 2020-present Cloudogu GmbH and Contributors
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
scm.home = /tmp/scm_home