Location.java
/*-
* ========================LICENSE_START=================================
* flyway-core
* ========================================================================
* Copyright (C) 2010 - 2025 Red Gate Software Ltd
* ========================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =========================LICENSE_END==================================
*/
package org.flywaydb.core.api;
import java.io.File;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import org.flywaydb.core.internal.scanner.LocationParser;
import org.flywaydb.core.internal.scanner.filesystem.FilesystemLocationHandler;
/**
* A location to load migrations from.
*/
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public final class Location implements Comparable<Location> {
/**
* The prefix for classpath locations.
*/
private static final String CLASSPATH_PREFIX = "classpath:";
/**
* The prefix for filesystem locations.
*/
@Deprecated
public static final String FILESYSTEM_PREFIX = "filesystem:";
/**
* The prefix for AWS S3 locations.
*/
private static final String AWS_S3_PREFIX = "s3:";
/**
* The prefix for Google Cloud Storage locations.
*/
private static final String GCS_PREFIX = "gcs:";
/**
* @return The prefix part of the location. Can be either classpath: or filesystem:.
*/
@Getter
private final String prefix;
/**
* The path part of the location.
*/
private final String rawPath;
/**
* The first folder in the path. This will equal rawPath if the path does not contain any wildcards
*
* @return The root part of the path part of the location.
*/
@Getter
private final String rootPath;
/**
* @return The regex that matches wildcards in the original path. Null if the original path did not contain any
* wildcards.
*/
@Getter
private final Pattern pathRegex;
public static Location fromPath(final String prefix, final String path) {
return new Location(prefix, path, path, null);
}
public static Location fromWildcardPath(final String prefix,
final String rootPath,
final String wildcardPath,
final Pattern pathRegex) {
return new Location(prefix, rootPath, wildcardPath, pathRegex);
}
@Deprecated
public Location(final String descriptor) {
final Location location = LocationParser.parseLocation(descriptor);
this.rawPath = location.rawPath;
this.rootPath = location.rootPath;
this.prefix = location.prefix;
this.pathRegex = location.pathRegex;
}
private Location(final String prefix, final String rootPath, final String rawPath, final Pattern pathRegex) {
this.rawPath = rawPath;
this.rootPath = rootPath;
this.prefix = prefix;
this.pathRegex = pathRegex;
}
/**
* @return Whether the given path matches this locations regex. Will always return true when the location did not
* contain any wildcards.
*/
@Deprecated
public boolean matchesPath(final String path) {
if (pathRegex == null) {
return true;
}
return pathRegex.matcher(path).matches();
}
/**
* Returns the path relative to this location. If the location path contains wildcards, the returned path will be
* relative to the last non-wildcard folder in the path.
*/
public String getPathRelativeToThis(final String path) {
if (pathRegex != null && pathRegex.pattern().contains("?<relpath>")) {
final Matcher matcher = pathRegex.matcher(path);
if (matcher.matches()) {
final String relPath = matcher.group("relpath");
if (relPath != null && !relPath.isEmpty()) {
return relPath;
}
}
}
return !rootPath.isEmpty() ? path.substring(rootPath.length() + 1) : path;
}
/**
* Checks whether this denotes a location on the classpath.
*
* @return {@code true} if it does, {@code false} if it doesn't.
*/
@Deprecated
public boolean isClassPath() {
return CLASSPATH_PREFIX.equals(prefix);
}
/**
* Checks whether this denotes a location on the filesystem.
*
* @return {@code true} if it does, {@code false} if it doesn't.
*/
@Deprecated
public boolean isFileSystem() {
return FilesystemLocationHandler.FILESYSTEM_PREFIX.equals(prefix);
}
/**
* Checks whether this denotes a location in AWS S3.
*
* @return {@code true} if it does, {@code false} if it doesn't;
*/
@Deprecated
public boolean isAwsS3() {
return AWS_S3_PREFIX.equals(prefix);
}
/**
* Checks whether this denotes a location in Google cloud storage.
*
* @return {@code true} if it does, {@code false} if it doesn't;
*/
@Deprecated
public boolean isGCS() {
return GCS_PREFIX.equals(prefix);
}
/**
* Checks whether this location is a parent of this other location.
*
* @param other The other location.
* @return {@code true} if it is, {@code false} if it isn't.
*/
@Deprecated
@SuppressWarnings("SimplifiableIfStatement")
public boolean isParentOf(final Location other) {
if (pathRegex != null || other.pathRegex != null) {
return false;
}
if (CLASSPATH_PREFIX.equals(prefix) && CLASSPATH_PREFIX.equals(other.prefix)) {
return (other.getDescriptor() + "/").startsWith(getDescriptor() + "/");
}
if (FilesystemLocationHandler.FILESYSTEM_PREFIX.equals(prefix)
&& FilesystemLocationHandler.FILESYSTEM_PREFIX.equals(other.prefix)) {
return (other.getDescriptor() + File.separator).startsWith(getDescriptor() + File.separator);
}
return false;
}
/**
* @return The path part of the location.
* @see #getRootPath()
* @deprecated Use the root path instead. This path will not be a genuine path for wildcard locations, whereas the
* root path is always a path.
*/
@Deprecated
public String getPath() {
return rawPath;
}
/**
* @return The complete location descriptor.
*/
@EqualsAndHashCode.Include
public String getDescriptor() {
return prefix + rawPath;
}
@Override
public int compareTo(final Location o) {
return getDescriptor().compareTo(o.getDescriptor());
}
/**
* @return The complete location descriptor.
*/
@Override
public String toString() {
return getDescriptor();
}
}