refactor directory handling

Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
pull/4718/head
Jimmy Tanagra 2025-05-12 11:11:37 +10:00 committed by Kai Kreuzer
parent d8c07d5601
commit ff2cafa690
6 changed files with 108 additions and 53 deletions

View File

@ -47,6 +47,9 @@ public class UpgradeTool {
private static final String OPT_LOG = "log"; private static final String OPT_LOG = "log";
private static final String OPT_FORCE = "force"; private static final String OPT_FORCE = "force";
private static final String ENV_USERDATA = "OPENHAB_USERDATA";
private static final String ENV_CONF = "OPENHAB_CONF";
private static final List<Upgrader> UPGRADERS = List.of( // private static final List<Upgrader> UPGRADERS = List.of( //
new ItemUnitToMetadataUpgrader(), // new ItemUnitToMetadataUpgrader(), //
new JSProfileUpgrader(), // new JSProfileUpgrader(), //
@ -105,26 +108,15 @@ public class UpgradeTool {
System.exit(0); System.exit(0);
} }
String userdataDir = commandLine.hasOption(OPT_USERDATA_DIR) ? commandLine.getOptionValue(OPT_USERDATA_DIR) Path userdataPath = getPath("userdata", commandLine, OPT_USERDATA_DIR, ENV_USERDATA);
: System.getenv("OPENHAB_USERDATA"); Path confPath = getPath("conf", commandLine, OPT_CONF_DIR, ENV_CONF);
if (command == null && (userdataDir == null || userdataDir.isBlank())) {
println("Please either set the environment variable ${OPENHAB_USERDATA} or provide a directory through the --userdata option.");
System.exit(0);
return;
} else if (userdataDir != null) {
logger.info("Using userdataDir: {}", userdataDir);
Path upgradeJsonDatabasePath = Path.of(userdataDir, "jsondb", "org.openhab.core.tools.UpgradeTool");
upgradeRecords = new JsonStorage<>(upgradeJsonDatabasePath.toFile(), null, 5, 0, 0, List.of());
}
String confDir = commandLine.hasOption(OPT_CONF_DIR) ? commandLine.getOptionValue(OPT_CONF_DIR) if (userdataPath != null) {
: System.getenv("OPENHAB_CONF"); Path upgradeJsonDatabasePath = userdataPath
if (confDir == null || confDir.isBlank()) { .resolve(Path.of("jsondb", "org.openhab.core.tools.UpgradeTool"));
println("Please either set the environment variable ${OPENHAB_CONF} or provide a directory through the --conf option."); upgradeRecords = new JsonStorage<>(upgradeJsonDatabasePath.toFile(), null, 5, 0, 0, List.of());
System.exit(0);
return;
} else { } else {
logger.info("Using confDir: {}", confDir); logger.warn("Upgrade records storage is not initialized.");
} }
UPGRADERS.forEach(upgrader -> { UPGRADERS.forEach(upgrader -> {
@ -139,7 +131,7 @@ public class UpgradeTool {
} }
try { try {
logger.info("Executing {}: {}", upgraderName, upgrader.getDescription()); logger.info("Executing {}: {}", upgraderName, upgrader.getDescription());
if (upgrader.execute(userdataDir, confDir)) { if (upgrader.execute(userdataPath, confPath)) {
updateUpgradeRecord(upgraderName); updateUpgradeRecord(upgraderName);
} }
} catch (Exception e) { } catch (Exception e) {
@ -154,6 +146,40 @@ public class UpgradeTool {
System.exit(0); System.exit(0);
} }
/**
* Returns the path to the given directory, either from the command line or from the environment variable.
* If neither is set, it defaults to a relative subdirectory of the given pathName ('./userdata' or './conf').
*
* @param pathName the name of the directory (e.g., "userdata" or "conf").
* @param commandLine a CommandLine instance.
* @param option the command line option for the directory (e.g., "userdata" or "conf").
* @param env the environment variable name for the directory (e.g., "OPENHAB_USERDATA" or "OPENHAB_CONF").
* @return the absolute path to the directory, or null if it does not exist.
*/
private static @Nullable Path getPath(String pathName, CommandLine commandLine, String option, String env) {
Path path = Path.of(pathName);
String optionValue = commandLine.getOptionValue(option);
String envValue = System.getenv(env);
if (optionValue != null && !optionValue.isBlank()) {
path = Path.of(optionValue);
} else if (envValue != null && !envValue.isBlank()) {
path = Path.of(envValue);
}
path = path.toAbsolutePath();
if (path.toFile().isDirectory()) {
return path;
} else {
logger.warn(
"The '{}' directory '{}' does not exist. Some tasks may fail. To set it, either set the environment variable ${{}} or provide a directory through the --{} option.",
pathName, path, env, option);
return null;
}
}
private static @Nullable String lastExecuted(String upgrader) { private static @Nullable String lastExecuted(String upgrader) {
JsonStorage<UpgradeRecord> records = upgradeRecords; JsonStorage<UpgradeRecord> records = upgradeRecords;
if (records != null) { if (records != null) {
@ -161,8 +187,6 @@ public class UpgradeTool {
if (upgradeRecord != null) { if (upgradeRecord != null) {
return upgradeRecord.executionDate; return upgradeRecord.executionDate;
} }
} else {
logger.error("Upgrade records storage is not initialized.");
} }
return null; return null;
} }
@ -172,8 +196,6 @@ public class UpgradeTool {
if (records != null) { if (records != null) {
records.put(upgrader, new UpgradeRecord(ZonedDateTime.now())); records.put(upgrader, new UpgradeRecord(ZonedDateTime.now()));
records.flush(); records.flush();
} else {
logger.error("Upgrade records storage is not initialized.");
} }
} }

View File

@ -12,7 +12,10 @@
*/ */
package org.openhab.core.tools; package org.openhab.core.tools;
import java.nio.file.Path;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/** /**
* The {@link Upgrader} provides an interface for upgrading openHAB configuration files. * The {@link Upgrader} provides an interface for upgrading openHAB configuration files.
@ -30,11 +33,11 @@ public interface Upgrader {
/** /**
* Executes the upgrade process. * Executes the upgrade process.
* *
* @param userdataDir the OPENHAB_USERDATA directory for the upgrade, * @param userdataPath the OPENHAB_USERDATA directory for the upgrade,
* or a custom path given by the user as --userdata argument * or a custom path given by the user as --userdata argument
* @param confDir the OPENHAB_CONF directory for the upgrade, * @param confPath the OPENHAB_CONF directory for the upgrade,
* or a custom path given by the user as --conf argument * or a custom path given by the user as --conf argument
* @return true if the upgrade was successful, false otherwise * @return true if the upgrade was successful, false otherwise
*/ */
boolean execute(String userdataDir, String confDir); boolean execute(@Nullable Path userdataPath, @Nullable Path confPath);
} }

View File

@ -24,6 +24,7 @@ import java.util.Objects;
import javax.measure.Unit; import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.items.ManagedItemProvider; import org.openhab.core.items.ManagedItemProvider;
import org.openhab.core.items.Metadata; import org.openhab.core.items.Metadata;
import org.openhab.core.items.MetadataKey; import org.openhab.core.items.MetadataKey;
@ -57,13 +58,19 @@ public class ItemUnitToMetadataUpgrader implements Upgrader {
} }
@Override @Override
public boolean execute(String userdataDir, String confDir) { public boolean execute(@Nullable Path userdataPath, @Nullable Path confPath) {
if (userdataPath == null) {
logger.error("{} skipped: no userdata directory found.", getName());
return false;
}
userdataPath = userdataPath.resolve("jsondb");
boolean noLink; boolean noLink;
Path itemJsonDatabasePath = Path.of(userdataDir, "jsondb", "org.openhab.core.items.Item.json"); Path itemJsonDatabasePath = userdataPath.resolve("org.openhab.core.items.Item.json");
Path metadataJsonDatabasePath = Path.of(userdataDir, "jsondb", "org.openhab.core.items.Metadata.json"); Path metadataJsonDatabasePath = userdataPath.resolve("org.openhab.core.items.Metadata.json");
Path linkJsonDatabasePath = Path.of(userdataDir, "jsondb", "org.openhab.core.thing.link.ItemChannelLink.json"); Path linkJsonDatabasePath = userdataPath.resolve("org.openhab.core.thing.link.ItemChannelLink.json");
Path thingJsonDatabasePath = Path.of(userdataDir, "jsondb", "org.openhab.core.thing.Thing.json"); Path thingJsonDatabasePath = userdataPath.resolve("org.openhab.core.thing.Thing.json");
logger.info("Copying item unit from state description to metadata in database '{}'", itemJsonDatabasePath); logger.info("Copying item unit from state description to metadata in database '{}'", itemJsonDatabasePath);
if (!Files.isReadable(itemJsonDatabasePath)) { if (!Files.isReadable(itemJsonDatabasePath)) {

View File

@ -18,6 +18,7 @@ import java.util.List;
import java.util.Objects; import java.util.Objects;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.config.core.Configuration; import org.openhab.core.config.core.Configuration;
import org.openhab.core.storage.json.internal.JsonStorage; import org.openhab.core.storage.json.internal.JsonStorage;
import org.openhab.core.thing.internal.link.ItemChannelLinkConfigDescriptionProvider; import org.openhab.core.thing.internal.link.ItemChannelLinkConfigDescriptionProvider;
@ -47,8 +48,15 @@ public class JSProfileUpgrader implements Upgrader {
} }
@Override @Override
public boolean execute(String userdataDir, String confDir) { public boolean execute(@Nullable Path userdataPath, @Nullable Path confPath) {
Path linkJsonDatabasePath = Path.of(userdataDir, "jsondb", "org.openhab.core.thing.link.ItemChannelLink.json"); if (userdataPath == null) {
logger.error("{} skipped: no userdata directory found.", getName());
return false;
}
userdataPath = userdataPath.resolve("jsondb");
Path linkJsonDatabasePath = userdataPath.resolve("org.openhab.core.thing.link.ItemChannelLink.json");
logger.info("Upgrading JS profile configuration in database '{}'", linkJsonDatabasePath); logger.info("Upgrading JS profile configuration in database '{}'", linkJsonDatabasePath);
if (!Files.isWritable(linkJsonDatabasePath)) { if (!Files.isWritable(linkJsonDatabasePath)) {

View File

@ -18,6 +18,7 @@ import java.util.List;
import java.util.Objects; import java.util.Objects;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.config.core.Configuration; import org.openhab.core.config.core.Configuration;
import org.openhab.core.storage.json.internal.JsonStorage; import org.openhab.core.storage.json.internal.JsonStorage;
import org.openhab.core.thing.internal.link.ItemChannelLinkConfigDescriptionProvider; import org.openhab.core.thing.internal.link.ItemChannelLinkConfigDescriptionProvider;
@ -50,8 +51,14 @@ public class ScriptProfileUpgrader implements Upgrader {
} }
@Override @Override
public boolean execute(String userdataDir, String confDir) { public boolean execute(@Nullable Path userdataPath, @Nullable Path confPath) {
Path linkJsonDatabasePath = Path.of(userdataDir, "jsondb", "org.openhab.core.thing.link.ItemChannelLink.json"); if (userdataPath == null) {
logger.error("{} skipped: no userdata directory found.", getName());
return false;
}
Path linkJsonDatabasePath = userdataPath
.resolve(Path.of("jsondb", "org.openhab.core.thing.link.ItemChannelLink.json"));
logger.info("Upgrading script profile configuration in database '{}'", linkJsonDatabasePath); logger.info("Upgrading script profile configuration in database '{}'", linkJsonDatabasePath);
if (!Files.isWritable(linkJsonDatabasePath)) { if (!Files.isWritable(linkJsonDatabasePath)) {

View File

@ -20,6 +20,7 @@ import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.tools.Upgrader; import org.openhab.core.tools.Upgrader;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -96,16 +97,22 @@ public class YamlConfigurationV1TagsUpgrader implements Upgrader {
} }
@Override @Override
public boolean execute(String userdataDir, String confDir) { public boolean execute(@Nullable Path userdataPath, @Nullable Path confPath) {
String confEnv = System.getenv("OPENHAB_CONF"); if (confPath == null) {
// If confDir is set to OPENHAB_CONF, look inside /tags/ subdirectory logger.error("{} skipped: no conf directory found.", getName());
// otherwise use the given confDir as is return false;
if (confEnv != null && !confEnv.isBlank() && confEnv.equals(confDir)) {
confDir = Path.of(confEnv, "tags").toString();
} }
Path configPath = Path.of(confDir).toAbsolutePath();
logger.info("Upgrading YAML tags configurations in '{}'", configPath);
String confEnv = System.getenv("OPENHAB_CONF");
// If confPath is set to OPENHAB_CONF, look inside /tags/ subdirectory
// otherwise use the given confPath as is
if (confEnv != null && !confEnv.isBlank() && Path.of(confEnv).toAbsolutePath().equals(confPath)) {
confPath = confPath.resolve("tags");
}
logger.info("Upgrading YAML tags configurations in '{}'", confPath);
Path configPath = confPath; // make configPath "effectively final" inside the lambda below
try { try {
Files.walkFileTree(configPath, new SimpleFileVisitor<>() { Files.walkFileTree(configPath, new SimpleFileVisitor<>() {
@Override @Override
@ -115,7 +122,6 @@ public class YamlConfigurationV1TagsUpgrader implements Upgrader {
Path relativePath = configPath.relativize(file); Path relativePath = configPath.relativize(file);
String modelName = relativePath.toString(); String modelName = relativePath.toString();
if (!relativePath.startsWith("automation") && modelName.endsWith(".yaml")) { if (!relativePath.startsWith("automation") && modelName.endsWith(".yaml")) {
logger.info("Checking {}", file);
convertTagsListToMap(file); convertTagsListToMap(file);
} }
} }
@ -142,15 +148,17 @@ public class YamlConfigurationV1TagsUpgrader implements Upgrader {
JsonNode versionNode = fileContent.get(VERSION); JsonNode versionNode = fileContent.get(VERSION);
if (versionNode == null || !versionNode.canConvertToInt() || versionNode.asInt() != 1) { if (versionNode == null || !versionNode.canConvertToInt() || versionNode.asInt() != 1) {
logger.debug("{} skipped: it doesn't contain a version key", filePath);
return; return;
} }
JsonNode tagsNode = fileContent.get("tags"); JsonNode tagsNode = fileContent.get("tags");
if (tagsNode == null || !tagsNode.isArray()) { if (tagsNode == null || !tagsNode.isArray()) {
logger.debug("{} skipped: it doesn't contain a 'tags' array.", filePath);
return; return;
} }
logger.info("Found v1 yaml file with tags list {}", filePath); logger.debug("{} found containing v1 yaml file with a 'tags' array", filePath);
fileContent.properties().forEach(entry -> { fileContent.properties().forEach(entry -> {
String key = entry.getKey(); String key = entry.getKey();
JsonNode node = entry.getValue(); JsonNode node = entry.getValue();
@ -187,7 +195,7 @@ public class YamlConfigurationV1TagsUpgrader implements Upgrader {
try { try {
Files.move(filePath, backupPath); Files.move(filePath, backupPath);
Files.writeString(filePath, content); Files.writeString(filePath, content);
logger.info("Converted {} to map format, and the original file saved as {}", filePath, backupPath); logger.info("{} converted to map format, and the original file saved as {}", filePath, backupPath);
} catch (IOException e) { } catch (IOException e) {
logger.error("Failed to save YAML file {}: {}", filePath, e.getMessage()); logger.error("Failed to save YAML file {}: {}", filePath, e.getMessage());
} }