org.pepsoft.util.XDG Maven / Gradle / Ivy
/*
* WorldPainter, a graphical and interactive map generator for Minecraft.
* Copyright © 2011-2015 pepsoft.org, The Netherlands
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package org.pepsoft.util;
import org.pepsoft.util.mdc.MDCCapturingRuntimeException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
/**
* Utility class for accessing the freedesktop.org "XDG Base Directory
* Specification" directories as well as the "well known" user directories as
* managed by the xdg-user-dirs tool.
*
* The string-typed constants are set whether or not the directory exists;
* either to the configured value or a default, if applicable. The file-typed
* constants are only set if the directory actually exists.
*
*
See
* http://standards.freedesktop.org/basedir-spec/latest/
* and
* http://www.freedesktop.org/wiki/Software/xdg-user-dirs/
*
*
Created by Pepijn Schmitz on 19-03-15.
*/
public final class XDG {
private XDG() {
// Prevent instantiation
}
// Base dirs
/**
* The current user's home directory. Set to the value of the
* {@code user.home} system property.
*/
public static final String HOME = System.getProperty("user.home");
/**
* Defines the base directory relative to which user specific data files
* should be stored. Set to the contents of the XDG_DATA_HOME environment
* variable, or "{@link #HOME}/.local/share" if that variable is not present.
*/
public static final String XDG_DATA_HOME = System.getenv("XDG_DATA_HOME") != null ? System.getenv("XDG_DATA_HOME") : HOME + File.separatorChar + ".local" + File.separatorChar + "share";
/**
* Defines the base directory relative to which user specific configuration
* files should be stored. Set to the contents of the XDG_CONFIG_HOME
* environment variable, or "{@link #HOME}/.config" if that variable is not present.
*/
public static final String XDG_CONFIG_HOME = System.getenv("XDG_CONFIG_HOME") != null ? System.getenv("XDG_CONFIG_HOME") : HOME + File.separatorChar + ".config";
/**
* Defines the preference-ordered set of base directories to search for data
* files in addition to the {@link #XDG_DATA_HOME} base directory. Set to
* the contents of the XDG_DATA_DIRS environment variable, or
* "/usr/local/share:/usr/share" if that variable is not present.
*/
public static final String XDG_DATA_DIRS = System.getenv("XDG_DATA_DIRS") != null ? System.getenv("XDG_DATA_DIRS") : File.separatorChar + "usr" + File.separatorChar + "local" + File.separatorChar + "share" + File.pathSeparatorChar + File.separatorChar + "usr" + File.separatorChar + "share";
/**
* Defines the preference-ordered set of base directories to search for
* configuration files in addition to the {@link #XDG_CONFIG_HOME} base
* directory. Set to the contents of the XDG_CONFIG_DIRS environment
* variable, or "/etc/xdg" if that variable is not present.
*/
public static final String XDG_CONFIG_DIRS = System.getenv("XDG_CONFIG_DIRS") != null ? System.getenv("XDG_CONFIG_DIRS") : File.separatorChar + "etc" + File.separatorChar + "xdg";
/**
* Defines the base directory relative to which user specific non-essential
* data files should be stored. Set to the contents of the XDG_CACHE_HOME
* environment variable, or "{@link #HOME}/.cache" if that variable is not present.
*/
public static final String XDG_CACHE_HOME = System.getenv("XDG_CACHE_HOME") != null ? System.getenv("XDG_CACHE_HOME") : HOME + File.separatorChar + ".cache";
/**
* Defines the base directory relative to which user-specific non-essential
* runtime files and other file objects (such as sockets, named pipes, ...)
* should be stored. Set to the contents of the XDG_RUNTIME_DIR environment
* variable, or {@code null} if that variable is not present.
*/
public static final String XDG_RUNTIME_DIR = System.getenv("XDG_RUNTIME_DIR");
/**
* {@link #XDG_DATA_HOME} as a {@link File} object, but only if that
* directory actually exists. {@code null} otherwise.
*/
public static final File XDG_DATA_HOME_FILE = new File(XDG_DATA_HOME).isDirectory() ? new File(XDG_DATA_HOME) : null;
/**
* {@link #XDG_CONFIG_HOME} as a {@link File} object, but only if that
* directory actually exists. {@code null} otherwise.
*/
public static final File XDG_CONFIG_HOME_FILE = new File(XDG_CONFIG_HOME).isDirectory() ? new File(XDG_CONFIG_HOME) : null;
/**
* {@link #XDG_CACHE_HOME} as a {@link File} object, but only if that
* directory actually exists. {@code null} otherwise.
*/
public static final File XDG_CACHE_HOME_FILE = new File(XDG_CACHE_HOME).isDirectory() ? new File(XDG_CACHE_HOME) : null;
/**
* {@link #XDG_RUNTIME_DIR} as a {@link File} object, but only if
* {@code XDG_RUNTIME_DIR} is not {@code null} and that
* directory actually exists. {@code null} otherwise.
*/
public static final File XDG_RUNTIME_DIR_FILE = XDG_RUNTIME_DIR != null ? (new File(XDG_RUNTIME_DIR).isDirectory() ? new File(XDG_RUNTIME_DIR) : null) : null;
// User dirs
/**
* The location of the "desktop" well known user directory, as specified
* in the appropriate system or user config file, or {@code null} if
* it is not configured.
*/
public static final String XDG_DESKTOP_DIR;
/**
* The location of the "documents" well known user directory, as specified
* in the appropriate system or user config file, or {@code null} if
* it is not configured.
*/
public static final String XDG_DOCUMENTS_DIR;
/**
* The location of the "download" well known user directory, as specified
* in the appropriate system or user config file, or {@code null} if
* it is not configured.
*/
public static final String XDG_DOWNLOAD_DIR;
/**
* The location of the "music" well known user directory, as specified
* in the appropriate system or user config file, or {@code null} if
* it is not configured.
*/
public static final String XDG_MUSIC_DIR;
/**
* The location of the "pictures" well known user directory, as specified
* in the appropriate system or user config file, or {@code null} if
* it is not configured.
*/
public static final String XDG_PICTURES_DIR;
/**
* The location of the "public share" well known user directory, as specified
* in the appropriate system or user config file, or {@code null} if
* it is not configured.
*/
public static final String XDG_PUBLICSHARE_DIR;
/**
* The location of the "templates" well known user directory, as specified
* in the appropriate system or user config file, or {@code null} if
* it is not configured.
*/
public static final String XDG_TEMPLATES_DIR;
/**
* The location of the "videos" well known user directory, as specified
* in the appropriate system or user config file, or {@code null} if
* it is not configured.
*/
public static final String XDG_VIDEOS_DIR;
static {
Properties userDirs = new Properties();
String[] configDirs = XDG_CONFIG_DIRS.split(File.pathSeparator);
for (String configDir: configDirs) {
File userDirFile = new File(configDir, "user-dirs.default");
if (userDirFile.isFile()) {
readShellVarScript(userDirFile, userDirs);
}
}
File userConfigFile = new File(XDG_CONFIG_HOME, "user-dirs.dirs");
if (userConfigFile.isFile()) {
readShellVarScript(userConfigFile, userDirs);
}
XDG_DESKTOP_DIR = userDirs.getProperty("XDG_DESKTOP_DIR");
XDG_DOCUMENTS_DIR = userDirs.getProperty("XDG_DOCUMENTS_DIR");
XDG_DOWNLOAD_DIR = userDirs.getProperty("XDG_DOWNLOAD_DIR");
XDG_MUSIC_DIR = userDirs.getProperty("XDG_MUSIC_DIR");
XDG_PICTURES_DIR = userDirs.getProperty("XDG_PICTURES_DIR");
XDG_PUBLICSHARE_DIR = userDirs.getProperty("XDG_PUBLICSHARE_DIR");
XDG_TEMPLATES_DIR = userDirs.getProperty("XDG_TEMPLATES_DIR");
XDG_VIDEOS_DIR = userDirs.getProperty("XDG_VIDEOS_DIR");
}
/**
* {@link #XDG_DESKTOP_DIR} as a {@link File} object, but only if
* {@code XDG_DESKTOP_DIR} is not {@code null} and that
* directory actually exists. {@code null} otherwise.
*/
public static final File XDG_DESKTOP_DIR_FILE = ((XDG_DESKTOP_DIR != null) && new File(XDG_DESKTOP_DIR).isDirectory()) ? new File(XDG_DESKTOP_DIR) : null;
/**
* {@link #XDG_DOCUMENTS_DIR} as a {@link File} object, but only if
* {@code XDG_DOCUMENTS_DIR} is not {@code null} and that
* directory actually exists. {@code null} otherwise.
*/
public static final File XDG_DOCUMENTS_DIR_FILE = ((XDG_DOCUMENTS_DIR != null) && new File(XDG_DOCUMENTS_DIR).isDirectory()) ? new File(XDG_DOCUMENTS_DIR) : null;
/**
* {@link #XDG_DOWNLOAD_DIR} as a {@link File} object, but only if
* {@code XDG_DOWNLOAD_DIR} is not {@code null} and that
* directory actually exists. {@code null} otherwise.
*/
public static final File XDG_DOWNLOAD_DIR_FILE = ((XDG_DOWNLOAD_DIR != null) && new File(XDG_DOWNLOAD_DIR).isDirectory()) ? new File(XDG_DOWNLOAD_DIR) : null;
/**
* {@link #XDG_MUSIC_DIR} as a {@link File} object, but only if
* {@code XDG_MUSIC_DIR} is not {@code null} and that
* directory actually exists. {@code null} otherwise.
*/
public static final File XDG_MUSIC_DIR_FILE = ((XDG_MUSIC_DIR != null) && new File(XDG_MUSIC_DIR).isDirectory()) ? new File(XDG_MUSIC_DIR) : null;
/**
* {@link #XDG_PICTURES_DIR} as a {@link File} object, but only if
* {@code XDG_PICTURES_DIR} is not {@code null} and that
* directory actually exists. {@code null} otherwise.
*/
public static final File XDG_PICTURES_DIR_FILE = ((XDG_PICTURES_DIR != null) && new File(XDG_PICTURES_DIR).isDirectory()) ? new File(XDG_PICTURES_DIR) : null;
/**
* {@link #XDG_PUBLICSHARE_DIR} as a {@link File} object, but only if
* {@code XDG_PUBLICSHARE_DIR} is not {@code null} and that
* directory actually exists. {@code null} otherwise.
*/
public static final File XDG_PUBLICSHARE_DIR_FILE = ((XDG_PUBLICSHARE_DIR != null) && new File(XDG_PUBLICSHARE_DIR).isDirectory()) ? new File(XDG_PUBLICSHARE_DIR) : null;
/**
* {@link #XDG_TEMPLATES_DIR} as a {@link File} object, but only if
* {@code XDG_TEMPLATES_DIR} is not {@code null} and that
* directory actually exists. {@code null} otherwise.
*/
public static final File XDG_TEMPLATES_DIR_FILE = ((XDG_TEMPLATES_DIR != null) && new File(XDG_TEMPLATES_DIR).isDirectory()) ? new File(XDG_TEMPLATES_DIR) : null;
/**
* {@link #XDG_VIDEOS_DIR} as a {@link File} object, but only if
* {@code XDG_VIDEOS_DIR} is not {@code null} and that
* directory actually exists. {@code null} otherwise.
*/
public static final File XDG_VIDEOS_DIR_FILE = ((XDG_VIDEOS_DIR != null) && new File(XDG_VIDEOS_DIR).isDirectory()) ? new File(XDG_VIDEOS_DIR) : null;
public static void main(String[] args) {
System.out.println("HOME: " + HOME);
System.out.println("XDG_DATA_HOME: " + XDG_DATA_HOME);
System.out.println("XDG_CONFIG_HOME: " + XDG_CONFIG_HOME);
System.out.println("XDG_DATA_DIRS: " + XDG_DATA_DIRS);
System.out.println("XDG_CONFIG_DIRS: " + XDG_CONFIG_DIRS);
System.out.println("XDG_CACHE_HOME: " + XDG_CACHE_HOME);
System.out.println("XDG_RUNTIME_DIR: " + XDG_RUNTIME_DIR);
System.out.println("XDG_DATA_HOME_FILE: " + XDG_DATA_HOME_FILE);
System.out.println("XDG_CONFIG_HOME_FILE: " + XDG_CONFIG_HOME_FILE);
System.out.println("XDG_CACHE_HOME_FILE: " + XDG_CACHE_HOME_FILE);
System.out.println("XDG_RUNTIME_DIR_FILE: " + XDG_RUNTIME_DIR_FILE);
System.out.println("XDG_DESKTOP_DIR: " + XDG_DESKTOP_DIR);
System.out.println("XDG_DOCUMENTS_DIR: " + XDG_DOCUMENTS_DIR);
System.out.println("XDG_DOWNLOAD_DIR: " + XDG_DOWNLOAD_DIR);
System.out.println("XDG_MUSIC_DIR: " + XDG_MUSIC_DIR);
System.out.println("XDG_PICTURES_DIR: " + XDG_PICTURES_DIR);
System.out.println("XDG_PUBLICSHARE_DIR: " + XDG_PUBLICSHARE_DIR);
System.out.println("XDG_TEMPLATES_DIR: " + XDG_TEMPLATES_DIR);
System.out.println("XDG_VIDEOS_DIR: " + XDG_VIDEOS_DIR);
System.out.println("XDG_DESKTOP_DIR_FILE: " + XDG_DESKTOP_DIR_FILE);
System.out.println("XDG_DOCUMENTS_DIR_FILE: " + XDG_DOCUMENTS_DIR_FILE);
System.out.println("XDG_DOWNLOAD_DIR_FILE: " + XDG_DOWNLOAD_DIR_FILE);
System.out.println("XDG_MUSIC_DIR_FILE: " + XDG_MUSIC_DIR_FILE);
System.out.println("XDG_PICTURES_DIR_FILE: " + XDG_PICTURES_DIR_FILE);
System.out.println("XDG_PUBLICSHARE_DIR_FILE: " + XDG_PUBLICSHARE_DIR_FILE);
System.out.println("XDG_TEMPLATES_DIR_FILE: " + XDG_TEMPLATES_DIR_FILE);
System.out.println("XDG_VIDEOS_DIR_FILE: " + XDG_VIDEOS_DIR_FILE);
}
private static void readShellVarScript(File script, Properties props) {
try {
try (BufferedReader in = new BufferedReader(new FileReader(script))) {
String line;
while ((line = in.readLine()) != null) {
line = line.trim();
// Separate the line into key and value
int p = line.indexOf('=');
if (p < 0) {
continue;
}
String key = line.substring(0, p);
String value = line.substring(p + 1);
// If the value is surrounded by double quotes, strip them
if ((value.length() >= 2) && value.startsWith("\"") && value.endsWith("\"")) {
value = value.substring(1, value.length() - 1);
}
// Expand any variables recursively
String previousValue;
do {
previousValue = value;
value = expandVariables(value);
} while (!value.equals(previousValue));
// Store the variables as properties
props.setProperty(key, value);
}
}
} catch (IOException e) {
throw new MDCCapturingRuntimeException("I/O error reading " + script, e);
}
}
private static String expandVariables(String value) {
StringBuilder result = new StringBuilder(value.length());
StringBuilder varName = new StringBuilder(100);
final int COPYING = 1;
final int DOLLAR_ENCOUNTERED = 2;
final int READING_VAR_NAME = 3;
int state = COPYING;
for (int i = 0; i < value.length(); i++) {
char c = value.charAt(i);
switch (state) {
case COPYING:
if (c == '$') {
state = DOLLAR_ENCOUNTERED;
} else {
result.append(c);
}
break;
case DOLLAR_ENCOUNTERED:
if (Character.isLetter(c) || (c == '_')) {
varName.setLength(0);
varName.append(c);
state = READING_VAR_NAME;
} else {
result.append('$');
result.append(c);
state = COPYING;
}
break;
case READING_VAR_NAME:
if (Character.isLetter(c) || Character.isDigit(c) || (c == '_')) {
varName.append(c);
} else {
String varNameStr = varName.toString();
if (varNameStr.equals("HOME")) {
result.append(System.getProperty("user.home"));
} else if (System.getenv(varNameStr) != null) {
result.append(varNameStr);
}
result.append(c);
state = COPYING;
}
break;
}
}
if (state == DOLLAR_ENCOUNTERED) {
result.append('$');
} else if (state == READING_VAR_NAME) {
String varNameStr = varName.toString();
if (varNameStr.equals("HOME")) {
result.append(System.getProperty("user.home"));
} else if (System.getenv(varNameStr) != null) {
result.append(varNameStr);
}
}
return result.toString();
}
}