X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;ds=inline;f=bundles%2Forg.simantics%2Fsrc%2Forg%2Fsimantics%2FDatabaseBaselines.java;fp=bundles%2Forg.simantics%2Fsrc%2Forg%2Fsimantics%2FDatabaseBaselines.java;h=96db5ed72f46339fb869cbaa25c9bc1f26b8ec5c;hb=b913419ca9037bf9734c56a5f079024c3a1cd177;hp=0000000000000000000000000000000000000000;hpb=a8d030f7db1f59a5b51cdc34f18de7c0a0ee8549;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics/src/org/simantics/DatabaseBaselines.java b/bundles/org.simantics/src/org/simantics/DatabaseBaselines.java new file mode 100644 index 000000000..96db5ed72 --- /dev/null +++ b/bundles/org.simantics/src/org/simantics/DatabaseBaselines.java @@ -0,0 +1,130 @@ +package org.simantics; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; + +import org.simantics.utils.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Tuukka Lehtonen + * @since 1.34.0 + */ +public class DatabaseBaselines { + + private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseBaselines.class); + + private static final boolean REQUIRE_INDEX_IN_BASELINE = false; + + private static final String DB_DIRECTORY = "db"; //$NON-NLS-1$ + private static final String INDEX_DIRECTORY = ".metadata/.plugins/org.simantics.db.indexing"; //$NON-NLS-1$ + + private static final DateTimeFormatter TIMESTAMP_FORMAT = DateTimeFormatter.ofPattern("d. MMM yyyy HH:mm:ss"); + + public static Path packageBaseline(Path fromWorkspace, Path packageFile) throws IOException { + return compressZip(fromWorkspace, collectBaselinePaths(fromWorkspace), packageFile); + } + + private static List collectBaselinePaths(Path workspace) throws IOException { + Path dbPath = workspace.resolve(DB_DIRECTORY); + Path indexPath = workspace.resolve(INDEX_DIRECTORY); + + if (!Files.isDirectory(dbPath)) + throw new IllegalArgumentException("workspace database directory " + dbPath + " does not exist"); + + List paths = Files.walk(dbPath).collect(Collectors.toList()); + if (Files.isDirectory(indexPath)) { + List indexPaths = Files.walk(indexPath).collect(Collectors.toList()); + paths.addAll(indexPaths); + } else { + if (REQUIRE_INDEX_IN_BASELINE) + throw new IllegalArgumentException("workspace database index directory " + indexPath + " does not exist"); + } + return paths; + } + + private static Path compressZip(Path relativeRoot, List paths, Path zipFile) throws IOException { + if (LOGGER.isDebugEnabled()) + LOGGER.debug("Compressing " + paths.size() + " path entries into ZIP file " + zipFile); + try (ZipOutputStream zout = new ZipOutputStream(Files.newOutputStream(zipFile))) { + compressZip(relativeRoot, zout, paths); + return zipFile; + } finally { + if (LOGGER.isDebugEnabled()) + LOGGER.debug("Compressed " + paths.size() + " entries into " + zipFile); + } + } + + private static void compressZip(Path relativeRoot, ZipOutputStream zout, List paths) throws IOException { + for (Path p : paths) { + Path rp = relativeRoot.relativize(p); + String name = rp.toString(); + if (Files.isDirectory(p)) { + name = name.endsWith("/") ? name : name + "/"; + zout.putNextEntry(new ZipEntry(name)); + } else { + zout.putNextEntry(new ZipEntry(name)); + FileUtils.copy(p.toFile(), zout); + zout.closeEntry(); + } + } + } + + public static byte[] baselineIndicatorContents(Path path) throws IOException { + return String.format("%s%n%s%n", + path.toString(), + Instant.now().atZone(ZoneId.systemDefault()).format(TIMESTAMP_FORMAT)) + .getBytes("UTF-8"); + } + + public static void validateWorkspaceForBaselineInitialization(Path workspaceLocation) throws PlatformException { + try { + Path db = workspaceLocation.resolve(DB_DIRECTORY); + if (Files.exists(db)) + throw new PlatformException("Database location " + db + " already exists. Cannot re-initialize workspace from baseline."); + if (REQUIRE_INDEX_IN_BASELINE) { + Path index = workspaceLocation.resolve(INDEX_DIRECTORY); + if (!Files.exists(index) || !isEmptyDirectory(index)) + throw new PlatformException("Index location " + index + " already exists. Cannot re-initialize workspace from baseline."); + } + } catch (IOException e) { + throw new PlatformException("Failed to validate workspace for baseline initialization", e); + } + } + + private static boolean isEmptyDirectory(Path dir) throws IOException { + return Files.walk(dir).count() == 1; + } + + public static void validateBaselineFile(Path baseline) throws PlatformException { + try (ZipFile zip = new ZipFile(baseline.toFile())) { + ZipEntry db = zip.getEntry(DB_DIRECTORY); + if (db == null) + throw new PlatformException("Baseline archive does not contain database directory '" + DB_DIRECTORY + "'"); + + if (REQUIRE_INDEX_IN_BASELINE) { + ZipEntry index = zip.getEntry(INDEX_DIRECTORY); + if (index == null) + throw new PlatformException("Baseline archive does not contain database index directory '" + INDEX_DIRECTORY + "'"); + } + } catch (IOException e) { + throw new PlatformException("Failed to validate baseline archive " + baseline, e); + } + } + + public static void main(String[] args) throws IOException { + packageBaseline(Paths.get("D:/temp/desktop/workspace"), Paths.get("d:/temp/desktop/workspace/baseline.zip")); + } + +}