Skip to content

Commit

Permalink
Merge branch 'master' into hessjcg-patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
hessjcg committed Jul 8, 2022
2 parents 2b314f7 + 4fb56c5 commit c8066a7
Show file tree
Hide file tree
Showing 27 changed files with 2,199 additions and 39 deletions.
34 changes: 34 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,40 @@
Liquibase Core Changelog
===========================================

Changes in version 4.13.0 (2022.07.07)

## Enhancements
* Added new liquibase.duplicateFileMode setting by @nvoxland in https://github.com/liquibase/liquibase/pull/3006
* Add additional info in CLI's --version output by @nvoxland in https://github.com/liquibase/liquibase/pull/2942
* Added support for new "searchPath" global configuration by @nvoxland in https://github.com/liquibase/liquibase/pull/2917

## Fixes
* Hide CommandFailedException stacktrace when thrown to set exit code (DAT-9608) by @StevenMassaro in https://github.com/liquibase/liquibase/pull/2938
* Update copyright year in txt files; also update links in txt files (DAT-10261) by @StevenMassaro in https://github.com/liquibase/liquibase/pull/2955
* add support for default-catalog-name in SQL Server (DAT-10484) by @StevenMassaro in https://github.com/liquibase/liquibase/pull/2940
* Make additional query for more column information for MariaDB DAT-8693 by @wwillard7800 in https://github.com/liquibase/liquibase/pull/2898
* Include should fail if a parser cannot be found for the specified file by @nvoxland in https://github.com/liquibase/liquibase/pull/2972
* Improved postgresql prepared statement performance by @nvoxland in https://github.com/liquibase/liquibase/pull/2914
* Cleanup relative paths preventing sql files being found by the class loader by @marcsowen in https://github.com/liquibase/liquibase/pull/2932
* Fix missing attributes in serialization by @tms-91 in https://github.com/liquibase/liquibase/pull/2585
* Improved parsing of single-quoted strings by @nvoxland in https://github.com/liquibase/liquibase/pull/2949
* DAT-10260: add outputFile argument in maven plugin for checks.run target by @StevenMassaro in https://github.com/liquibase/liquibase/pull/2975
* Formatted SQL files with uppercase in the liquibase attributes (DAT-10531) by @abrackx in https://github.com/liquibase/liquibase/pull/2985
* handle empty or null input to stripComments method (DAT-10296) by @StevenMassaro in https://github.com/liquibase/liquibase/pull/2970
* Fixed issue with parameter expression parsing by @nvoxland in https://github.com/liquibase/liquibase/pull/2984
* Fixed before/after/at column arguments in addColumn by @nvoxland in https://github.com/liquibase/liquibase/pull/2943
* Adds liquibase.psql.conf example (DAT-10303) by @abrackx in https://github.com/liquibase/liquibase/pull/2939
* [DAT-10093] added schema escaping to getColumns call to jdbc metadata classes by @KushnirykOleh in https://github.com/liquibase/liquibase/pull/2895
* Use "numeric" (without parameters) data type in PostgreSQL by @LonwoLonwo in https://github.com/liquibase/liquibase/pull/1906
* Force "json" resultset formats in Snowflake when running Java 17+ by @nvoxland in https://github.com/liquibase/liquibase/pull/3019

## JDBC Driver and Third-Party Library Updates
* Upgraded jaxb-core from 2.3.0.1 to 4.0.0 by @dependabot in https://github.com/liquibase/liquibase/pull/2962
* Upgraded snowflake-jdbc from 3.13.19 to 3.13.20 by @dependabot in https://github.com/liquibase/liquibase/pull/3001
* Upgraded mariadb-java-client from 3.0.4 to 3.0.5 by @dependabot in https://github.com/liquibase/liquibase/pull/2881
* Upgraded ojdbc8 from 21.5.0.0 to 21.6.0.0.1 by @dependabot in https://github.com/liquibase/liquibase/pull/2987
* Upgraded h2 from 2.1.212 to 2.1.214 by @dependabot in https://github.com/liquibase/liquibase/pull/2944

Changes in version 4.12.0 (2022.06.16)

## Enhancements
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@
import liquibase.license.LicenseServiceFactory;
import liquibase.logging.LogService;
import liquibase.logging.core.JavaLogService;
import liquibase.resource.CompositeResourceAccessor;
import liquibase.resource.FileSystemResourceAccessor;
import liquibase.resource.*;
import liquibase.ui.ConsoleUIService;
import liquibase.ui.UIService;
import liquibase.util.*;
Expand Down Expand Up @@ -670,7 +669,9 @@ private CommandLine getRootCommand(CommandLine commandLine) {
private Map<String, Object> configureResourceAccessor(ClassLoader classLoader) {
Map<String, Object> returnMap = new HashMap<>();

returnMap.put(Scope.Attr.resourceAccessor.name(), new CompositeResourceAccessor(new FileSystemResourceAccessor(Paths.get(".").toAbsolutePath().toFile()), new CommandLineResourceAccessor(classLoader)));
returnMap.put(Scope.Attr.resourceAccessor.name(), new SearchPathResourceAccessor(
new FileSystemResourceAccessor(Paths.get(".").toAbsolutePath().toFile()),
new CommandLineResourceAccessor(classLoader)));

return returnMap;
}
Expand All @@ -690,7 +691,7 @@ protected ClassLoader configureClassLoader() throws IllegalArgumentException {
for (String classpathEntry : classpathSoFar) {
File classPathFile = new File(classpathEntry);
if (!classPathFile.exists()) {
throw new IllegalArgumentException(classPathFile.getAbsolutePath() + " does.not.exist");
throw new IllegalArgumentException(classPathFile.getAbsolutePath() + " does not exist");
}

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public class GlobalConfiguration implements AutoloadedConfigurations {
public static final ConfigurationDefinition<Boolean> STRICT;
public static final ConfigurationDefinition<Integer> DDL_LOCK_TIMEOUT;
public static final ConfigurationDefinition<Boolean> SECURE_PARSING;
public static final ConfigurationDefinition<String> SEARCH_PATH;

static {
ConfigurationDefinition.Builder builder = new ConfigurationDefinition.Builder("liquibase");
Expand Down Expand Up @@ -205,6 +206,10 @@ public class GlobalConfiguration implements AutoloadedConfigurations {
.setDescription("How to handle multiple files being found in the search path that have duplicate paths. Options are WARN (log warning and choose one at random) or ERROR (fail current operation)")
.setDefaultValue(DuplicateFileMode.ERROR)
.build();

SEARCH_PATH = builder.define("searchPath", String.class)
.setDescription("Complete list of Location(s) to search for files such as changelog files in. Multiple paths can be specified by separating them with commas.")
.build();
}

public enum DuplicateFileMode {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,7 @@ private void addToChangeSets(Change[] changes, List<ChangeSet> changeSets, Objec
if (useSeparateChangeSets(changes)) {
for (Change change : changes) {
ChangeSet changeSet = new ChangeSet(generateId(changes), getChangeSetAuthor(), false, false, this.changeSetPath, changeSetContext,
null, false, quotingStrategy, null);
null, true, quotingStrategy, null);
changeSet.setCreated(created);
if (diffOutputControl.getLabels() != null) {
changeSet.setLabels(diffOutputControl.getLabels());
Expand All @@ -782,7 +782,7 @@ private void addToChangeSets(Change[] changes, List<ChangeSet> changeSets, Objec
}
} else {
ChangeSet changeSet = new ChangeSet(generateId(changes), getChangeSetAuthor(), false, false, this.changeSetPath, csContext,
null, false, quotingStrategy, null);
null, true, quotingStrategy, null);
changeSet.setCreated(created);
if (diffOutputControl.getLabels() != null) {
changeSet.setLabels(diffOutputControl.getLabels());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import java.io.Writer;

public abstract class AbstractChangeLogBasedTask extends BaseLiquibaseTask {

private String searchPath;
private String changeLogDirectory;
private String changeLogFile;
private String contexts;
Expand Down Expand Up @@ -42,7 +44,20 @@ public String getChangeLogDirectory() {
public void setChangeLogDirectory(String changeLogDirectory) {
this.changeLogDirectory = changeLogDirectory;
}


/**
* Gets the change log directory set from Ant.
* @return The change log directory resource.
*/
@Override
public String getSearchPath() {
return searchPath;
}

public void setSearchPath(String searchPath) {
this.searchPath = searchPath;
}

/**
* Gets the change log file set from Ant.
* @return The change log file resource.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import liquibase.resource.ClassLoaderResourceAccessor;
import liquibase.resource.CompositeResourceAccessor;
import liquibase.resource.ResourceAccessor;
import liquibase.resource.SearchPathResourceAccessor;
import org.apache.tools.ant.AntClassLoader;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
Expand Down Expand Up @@ -118,6 +119,15 @@ public String getChangeLogDirectory() {
return null;
}

/**
* This method is designed to be overridden by subclasses when a change log is needed. By default it returns null.
*
* @return Returns null in this implementation. Subclasses that need a change log should implement.
*/
public String getSearchPath() {
return null;
}

/**
* This method is designed to be overridden by subclasses when a change log is needed. By default it returns null.
*
Expand Down Expand Up @@ -156,7 +166,7 @@ protected void validateParameters() {
* @return A ResourceAccessor.
*/
private ResourceAccessor createResourceAccessor(AntClassLoader classLoader) {
return new CompositeResourceAccessor(
return new SearchPathResourceAccessor(getSearchPath(),
new AntResourceAccessor(classLoader, getChangeLogDirectory()),
new ClassLoaderResourceAccessor(Thread.currentThread().getContextClassLoader())
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.LiquibaseException;
import liquibase.integration.commandline.LiquibaseCommandLineConfiguration;
import liquibase.resource.ClassLoaderResourceAccessor;
import liquibase.resource.CompositeResourceAccessor;
import liquibase.resource.FileSystemResourceAccessor;
import liquibase.resource.ResourceAccessor;
import liquibase.resource.*;
import liquibase.util.NetUtil;
import liquibase.util.StringUtil;

Expand Down Expand Up @@ -230,7 +227,7 @@ private void executeUpdate(GenericServletWrapper.ServletContext servletContext,

database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
database.setDefaultSchemaName(getDefaultSchema());
liquibase = new Liquibase(getChangeLogFile(), new CompositeResourceAccessor(clFO, fsFO, threadClFO), database);
liquibase = new Liquibase(getChangeLogFile(), new SearchPathResourceAccessor(clFO, fsFO, threadClFO), database);

@SuppressWarnings("unchecked")
Enumeration<String> initParameters = servletContext.getInitParameterNames();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package liquibase.resource;

/**
* Convenience base class for {@link PathHandler}s.
*/
public abstract class AbstractPathHandler implements PathHandler {
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

/**
* A {@link liquibase.resource.ResourceAccessor} that contains multiple sub-accessors and combines the results of all of them.
* For the "overall" aggregate resource accessor, integrations should generally use {@link SearchPathResourceAccessor} instead of this.
*/
public class CompositeResourceAccessor extends AbstractResourceAccessor {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package liquibase.resource;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Paths;

/**
* {@link PathHandler} that converts the path into a {@link FileSystemResourceAccessor}.
*/
public class FileSystemPathHandler extends AbstractPathHandler {

/**
* Returns {@link #PRIORITY_DEFAULT} for all paths except for ones that are for a non-"file:" protocol.
*/
public int getPriority(String root) {
if (root == null) {
return PRIORITY_NOT_APPLICABLE;
}

if (!root.startsWith("/") && root.contains(":")) {
if (root.startsWith("file:") || root.matches("^[A-Za-z]:.*")) {
return PRIORITY_DEFAULT;
} else {
return PRIORITY_NOT_APPLICABLE;
}
}
return PRIORITY_DEFAULT;
}

public ResourceAccessor getResourceAccessor(String root) {
return new FileSystemResourceAccessor(new File(root.replace("\\", "/")));
}
@Override
public InputStream open(String path) throws IOException {
try {
return Files.newInputStream(Paths.get(path));
} catch (NoSuchFileException e) {
throw new IOException("File '"+path+"' does not exist");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@
import java.nio.file.FileSystem;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.*;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
Expand All @@ -25,21 +22,14 @@ public class FileSystemResourceAccessor extends AbstractResourceAccessor {

//Set to avoid duplicates but LinkedHashSet to preserve order. Kept private to control access through get/set since we are an ExtensibleObject
private LinkedHashSet<Path> rootPaths = new LinkedHashSet<>();
private Set<String> invalidPaths = new HashSet<>();

/**
* Creates a FileSystemResourceAccessor with the given directories/files as the roots.
*/
public FileSystemResourceAccessor(File... baseDirsAndFiles) {
for (File base : CollectionUtil.createIfNull(baseDirsAndFiles)) {
if (!base.exists()) {
Scope.getCurrentScope().getLog(getClass()).warning("Non-existent path: " + base.getAbsolutePath());
} else if (base.isDirectory()) {
addRootPath(base.toPath());
} else if (base.getName().endsWith(".jar") || base.getName().toLowerCase().endsWith("zip")) {
addRootPath(base.toPath());
} else {
throw new IllegalArgumentException(base.getAbsolutePath() + " must be a directory, jar or zip");
}
addRootPath(base);
}
}

Expand All @@ -56,6 +46,23 @@ protected void addRootPath(Path path) {
rootPaths.add(path);
}

protected void addRootPath(File base) {
if (base == null) {
return;
}

if (!base.exists()) {
Scope.getCurrentScope().getLog(getClass()).warning("Non-existent path: " + base.getAbsolutePath());
invalidPaths.add(base.toPath().toAbsolutePath().toString());
} else if (base.isDirectory()) {
addRootPath(base.toPath());
} else if (base.getName().endsWith(".jar") || base.getName().toLowerCase().endsWith("zip")) {
addRootPath(base.toPath());
} else {
throw new IllegalArgumentException(base.getAbsolutePath() + " must be a directory, jar or zip");
}
}

protected LinkedHashSet<Path> getRootPaths() {
return rootPaths;
}
Expand Down Expand Up @@ -292,7 +299,11 @@ public SortedSet<String> describeLocations() {
SortedSet<String> returnSet = new TreeSet<>();

for (Path path : getRootPaths()) {
returnSet.add(path.toString());
returnSet.add(path.toAbsolutePath().toString());
}

for (String path : invalidPaths) {
returnSet.add(path);
}

return returnSet;
Expand Down
31 changes: 31 additions & 0 deletions liquibase-core/src/main/java/liquibase/resource/PathHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package liquibase.resource;

import liquibase.plugin.Plugin;

import java.io.IOException;
import java.io.InputStream;

/**
* Interface for extensions that can translate path strings into {@link ResourceAccessor}s and {@link java.io.InputStream}s.
*/
public interface PathHandler extends Plugin {

/**
* Priority of this parser for the given path. The implementation with the highest priority will be used.
*/
int getPriority(String root);

/**
* Parse the given path and return a {@link ResourceAccessor} for it.
*
* @throws IOException if the path is invalid
*/
ResourceAccessor getResourceAccessor(String root) throws IOException;

/**
* Parse the given path and return an {@link java.io.InputStream} for it.
*
* @throws IOException if the path is invalid
*/
InputStream open(String path) throws IOException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package liquibase.resource;

import liquibase.plugin.AbstractPluginFactory;

import java.io.IOException;

/**
* Singleton for working with {@link PathHandler}s.
*/
public class PathHandlerFactory extends AbstractPluginFactory<PathHandler> {

private PathHandlerFactory() {
}

@Override
protected Class<PathHandler> getPluginClass() {
return PathHandler.class;
}

@Override
protected int getPriority(PathHandler obj, Object... args) {
return obj.getPriority((String) args[0]);
}

/**
* Creates the {@link ResourceAccessor} for the given path.
*/
public ResourceAccessor getResourceAccessor(String root) throws IOException {
final PathHandler plugin = getPlugin(root);
if (plugin == null) {
throw new IOException("Cannot parse resource location: '" + root + "'");
}
return plugin.getResourceAccessor(root);
}
}

0 comments on commit c8066a7

Please sign in to comment.