package com.devskiller.jpa2ddl; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.PathMatcher; import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; import java.util.List; import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import static java.util.regex.Pattern.CASE_INSENSITIVE; class FileResolver { private final static Pattern FILENAME_PATTERN = Pattern.compile("v([0-9]+)__.+\\.sql", CASE_INSENSITIVE); private final static Pattern SCHEMA_FILENAME_PATTERN = Pattern.compile("v([0-9]+)__jpa2ddl.*\\.sql", CASE_INSENSITIVE); static File resolveNextMigrationFile(File migrationDir) { Optional<Path> lastFile = resolveExistingMigrations(migrationDir, true, false) .stream() .findFirst(); Long fileIndex = lastFile.map((Path input) -> FILENAME_PATTERN.matcher(input.getFileName().toString())) .map(matcher -> { if (matcher.find()) { return Long.valueOf(matcher.group(1)); } else { return 0L; } }).orElse(0L); return migrationDir.toPath().resolve("v" + ++fileIndex + "__jpa2ddl.sql").toFile(); } static List<Path> resolveExistingMigrations(File migrationsDir, boolean reversed, boolean onlySchemaMigrations) { if (!migrationsDir.exists()) { migrationsDir.mkdirs(); } File[] files = migrationsDir.listFiles(); if (files == null) { return Collections.emptyList(); } Comparator<Path> pathComparator = Comparator.comparingLong(FileResolver::compareVersionedMigrations); if (reversed) { pathComparator = pathComparator.reversed(); } return Arrays.stream(files) .map(File::toPath) .filter(path -> !onlySchemaMigrations || SCHEMA_FILENAME_PATTERN.matcher(path.getFileName().toString()).matches()) .sorted(pathComparator) .collect(Collectors.toList()); } static List<String> listClassNamesInPackage(String packageName) throws Exception { List<String> classes = new ArrayList<>(); Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources(packageName.replace('.', File.separatorChar)); if (!resources.hasMoreElements()) { throw new IllegalStateException("No package found: " + packageName); } PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:*.class"); while (resources.hasMoreElements()) { URL resource = resources.nextElement(); Files.walkFileTree(Paths.get(resource.toURI()), new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException { if (pathMatcher.matches(path.getFileName())) { try { String className = Paths.get(resource.toURI()).relativize(path).toString().replace(File.separatorChar, '.'); classes.add(packageName + '.' + className.substring(0, className.length() - 6)); } catch (URISyntaxException e) { throw new IllegalStateException(e); } } return FileVisitResult.CONTINUE; } }); } return classes; } private static Long compareVersionedMigrations(Path path) { Matcher filenameMatcher = FILENAME_PATTERN.matcher(path.getFileName().toString()); if (filenameMatcher.find()) { return Long.valueOf(filenameMatcher.group(1)); } else { return Long.MIN_VALUE; } } }