-
Notifications
You must be signed in to change notification settings - Fork 642
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support relative paths in volumes
statements in docker-compose.yaml
#848
Merged
Merged
Changes from 8 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
b2e9238
Support relative paths in `volumes` statements in docker-compose.yaml
emetsger e962997
Use JMockit; remove Mockito.
emetsger ed66e24
Add a public DockerPathUtil class (with tests). Update ComposeUtils …
emetsger d6cd442
Move DockerComposeServiceWrapper.resolveRelativeVolumeBinding(...) to…
emetsger f5a988b
Volume binding strings with relative paths are resolved against the b…
emetsger 5289775
Update changelog
emetsger 84e0bba
Additional javadoc and more informative exception handling.
emetsger bddc00e
Update test configuration by providing a base directory necessary to …
emetsger eb1242a
Support relative path reference to parent directories
emetsger 51ca2dd
Support relative paths in the <run> configuration.
emetsger 8552deb
Support access control specifications in volume binding strings..
emetsger 406a690
Update tests to work on Windows platform as well as on *nix platforms.
emetsger File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
src/main/java/io/fabric8/maven/docker/config/handler/compose/ComposeUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package io.fabric8.maven.docker.config.handler.compose; | ||
|
||
import io.fabric8.maven.docker.util.DockerPathUtil; | ||
import org.apache.maven.project.MavenProject; | ||
|
||
import java.io.File; | ||
|
||
/** | ||
* Path-resolution methods | ||
*/ | ||
class ComposeUtils { | ||
|
||
/** | ||
* Resolves a docker-compose file against the supplied base directory. The returned {@code File} is guaranteed to | ||
* be {@link File#isAbsolute() absolute}. | ||
* <p> | ||
* If {@code composeFile} is {@link File#isAbsolute() absolute}, then it is returned unmodified. Otherwise, the | ||
* {@code composeFile} is returned as an absolute {@code File} using the {@link #resolveAbsolutely(String, | ||
* MavenProject) resolved} {@code baseDir} as its parent. | ||
* </p> | ||
* | ||
* @param baseDir the base directory containing the docker-compose file (ignored if {@code composeFile} is absolute) | ||
* @param composeFile the path of the docker-compose file, may be absolute | ||
* @param project the {@code MavenProject} used to resolve the {@code baseDir} | ||
* @return an absolute {@code File} reference to the {@code composeFile} | ||
*/ | ||
static File resolveComposeFileAbsolutely(String baseDir, String composeFile, MavenProject project) { | ||
File yamlFile = new File(composeFile); | ||
return yamlFile.isAbsolute() ? yamlFile : new File(resolveAbsolutely(baseDir, project),composeFile); | ||
} | ||
|
||
/** | ||
* Resolves the supplied resource (a path or directory on the filesystem) relative the Maven {@link | ||
* MavenProject#getBasedir() base directory}. The returned {@code File} is guaranteed to be {@link | ||
* File#isAbsolute() absolute}. The returned file is <em>not</em> guaranteed to exist. | ||
* <p> | ||
* If {@code pathToResolve} is {@link File#isAbsolute() absolute}, then it is returned unmodified. Otherwise, the | ||
* {@code pathToResolve} is returned as an absolute {@code File} using the {@link MavenProject#getBasedir() Maven | ||
* Project base directory} as its parent. | ||
* </p> | ||
* | ||
* @param pathToResolve represents a filesystem resource, which may be an absolute path | ||
* @param project the Maven project used to resolve non-absolute path resources, may be {@code null} if | ||
* {@code pathToResolve} is {@link File#isAbsolute() absolute} | ||
* @return an absolute {@code File} reference to {@code pathToResolve}; <em>not</em> guaranteed to exist | ||
* @throws IllegalArgumentException if {@code pathToResolve} is relative, and {@code project} is {@code null} or | ||
* provides a relative {@link MavenProject#getBasedir() base directory} | ||
*/ | ||
static File resolveAbsolutely(String pathToResolve, MavenProject project) { | ||
// avoid an NPE if the Maven project is not needed by DockerPathUtil | ||
return DockerPathUtil.resolveAbsolutely(pathToResolve, | ||
(project == null) ? null : project.getBasedir().getAbsolutePath()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50 changes: 50 additions & 0 deletions
50
src/main/java/io/fabric8/maven/docker/util/DockerPathUtil.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package io.fabric8.maven.docker.util; | ||
|
||
import java.io.File; | ||
|
||
/** | ||
* Docker path resolution and manipulation utility methods. | ||
* <p> | ||
* This class provides methods for manipulating paths <em>as they appear in docker-compose or Dockerfiles</em>. This | ||
* class does not provide for generic path manipulation across platforms or file systems. Paths that appear in Docker | ||
* configurations use forward slash as a separator character, so this class makes no provisions for handling Windows | ||
* platform path semantics (e.g. the presence of drive letters or backward slash). | ||
* </p> | ||
*/ | ||
public class DockerPathUtil { | ||
|
||
/** | ||
* Resolves the supplied resource (a path or directory on the filesystem) relative the supplied {@code | ||
* baseDir}. The returned {@code File} is guaranteed to be {@link File#isAbsolute() absolute}. The returned file | ||
* is <em>not</em> guaranteed to exist. | ||
* <p> | ||
* If the supplied {@code pathToResolve} is already {@link File#isAbsolute() absolute}, then it is returned | ||
* <em>unmodified</em>. Otherwise, the {@code pathToResolve} is returned as an absolute {@code File} using the | ||
* supplied {@code baseDir} as its parent. | ||
* </p> | ||
* | ||
* @param pathToResolve represents a filesystem resource, which may be an absolute path | ||
* @param baseDir the absolute path used to resolve non-absolute path resources; <em>must</em> be absolute | ||
* @return an absolute {@code File} reference to {@code pathToResolve}; <em>not</em> guaranteed to exist | ||
* @throws IllegalArgumentException if the supplied {@code baseDir} does not represent an absolute path | ||
*/ | ||
public static File resolveAbsolutely(String pathToResolve, String baseDir) { | ||
File fileToResolve = new File(pathToResolve); | ||
|
||
if (fileToResolve.isAbsolute()) { | ||
return fileToResolve; | ||
} | ||
|
||
if (baseDir == null) { | ||
throw new IllegalArgumentException("Cannot resolve relative path '" + pathToResolve + "' with a " + | ||
"null base directory."); | ||
} | ||
|
||
File baseDirAsFile = new File(baseDir); | ||
if (!baseDirAsFile.isAbsolute()) { | ||
throw new IllegalArgumentException("Base directory '" + baseDirAsFile + "' must be absolute"); | ||
} | ||
|
||
return new File(baseDirAsFile, pathToResolve); | ||
} | ||
} |
133 changes: 133 additions & 0 deletions
133
src/main/java/io/fabric8/maven/docker/util/VolumeBindingUtil.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package io.fabric8.maven.docker.util; | ||
|
||
import io.fabric8.maven.docker.config.RunVolumeConfiguration; | ||
|
||
import java.io.File; | ||
import java.util.List; | ||
|
||
/** | ||
* Utility methods for working with Docker volume bindings. | ||
*/ | ||
public class VolumeBindingUtil { | ||
|
||
/** | ||
* Resolves relative paths in the supplied {@code bindingString}, and returns a binding string that has relative | ||
* paths replaced with absolute paths. If the supplied {@code bindingString} does not contain a relative path, it | ||
* is returned unmodified. | ||
* <h3>Discussion:</h3> | ||
* <p> | ||
* Volumes may be defined inside of {@code service} blocks <a href="https://docs.docker.com/compose/compose-file/compose-file-v2/#volumes-volume_driver"> | ||
* as documented here</a>: | ||
* </p> | ||
* <pre> | ||
* volumes: | ||
* # Just specify a path and let the Engine create a volume | ||
* - /var/lib/mysql | ||
* | ||
* # Specify an absolute path mapping | ||
* - /opt/data:/var/lib/mysql | ||
* | ||
* # Path on the host, relative to the Compose file | ||
* - ./cache:/tmp/cache | ||
* | ||
* # User-relative path | ||
* - ~/configs:/etc/configs/:ro | ||
* | ||
* # Named volume | ||
* - datavolume:/var/lib/mysql" | ||
* </pre> | ||
* <p> | ||
* This method only operates on volume strings that are relative: beginning with {@code ./} or {@code ~/}. Relative | ||
* paths beginning with {@code ./} are absolutized relative to the supplied {@code baseDir}, which <em>must</em> be | ||
* absolute. Paths beginning with {@code ~/} are interpreted relative to {@code new File(System.getProperty( | ||
* "user.home"))}, and {@code baseDir} is ignored. | ||
* </p> | ||
* <p> | ||
* Volume strings that do not begin with a {@code ./} or {@code ~/} are returned as-is. | ||
* </p> | ||
* <h3>Examples:</h3> | ||
* <p> | ||
* Given {@code baseDir} equal to "/path/to/basedir" and a {@code bindingString} string equal to | ||
* "./reldir:/some/other/dir", this method returns {@code /path/to/basedir/reldir:/some/other/dir} | ||
* </p> | ||
* <p> | ||
* Given {@code baseDir} equal to "/path/to/basedir" and a {@code bindingString} string equal to | ||
* "~/reldir:/some/other/dir", this method returns {@code /path/to/user/home/reldir:/some/other/dir} | ||
* </p> | ||
* | ||
* @param baseDir the base directory used to resolve paths beginning with {@code ./}; <em>must</em> be absolute | ||
* @param bindingString the volume string from the docker-compose file | ||
* @return the volume string, with any relative paths resolved as absolute paths | ||
* @throws IllegalArgumentException if the supplied {@code baseDir} is not absolute | ||
*/ | ||
public static String resolveRelativeVolumeBinding(File baseDir, String bindingString) { | ||
|
||
if (!baseDir.isAbsolute()) { | ||
throw new IllegalArgumentException("Base directory '" + baseDir + "' must be absolute."); | ||
} | ||
|
||
// a 'services:' -> service -> 'volumes:' may be formatted as: | ||
// (https://docs.docker.com/compose/compose-file/compose-file-v2/#volumes-volume_driver) | ||
// | ||
// volumes: | ||
// # Just specify a path and let the Engine create a volume | ||
// - /var/lib/mysql | ||
// | ||
// # Specify an absolute path mapping | ||
// - /opt/data:/var/lib/mysql | ||
// | ||
// # Path on the host, relative to the Compose file | ||
// - ./cache:/tmp/cache | ||
// | ||
// # User-relative path | ||
// - ~/configs:/etc/configs/:ro | ||
// | ||
// # Named volume | ||
// - datavolume:/var/lib/mysql | ||
|
||
String[] pathParts = bindingString.split(":"); | ||
String localPath = pathParts[0]; | ||
String serverPath = (pathParts.length > 1) ? pathParts[1] : ""; | ||
|
||
// only perform resolution if the localPath begins with '~/' or './' | ||
|
||
if (localPath.startsWith("./")) { | ||
localPath = new File(baseDir, localPath.substring(2)).getAbsolutePath(); | ||
} | ||
|
||
if (localPath.startsWith("~/")) { | ||
localPath = new File(System.getProperty("user.home"), localPath.substring(2)).getAbsolutePath(); | ||
} | ||
|
||
if (serverPath.length() > 0) { | ||
return String.format("%s:%s", localPath, serverPath); | ||
} | ||
|
||
return localPath; | ||
} | ||
|
||
/** | ||
* Iterates over each {@link RunVolumeConfiguration#getBind() binding} in the {@code volumeConfiguration}, and | ||
* resolves any relative paths in the binding strings using {@link #resolveRelativeVolumeBinding(File, String)}. | ||
* | ||
* @param baseDir the base directory used to resolve paths beginning with {@code ./}; <em>must</em> be absolute | ||
* @param volumeConfiguration the volume configuration that may contain volume binding specifications | ||
* @throws IllegalArgumentException if the supplied {@code baseDir} is not absolute | ||
*/ | ||
public static void resolveRelativeVolumeBindings(File baseDir, RunVolumeConfiguration volumeConfiguration) { | ||
|
||
if (!baseDir.isAbsolute()) { | ||
throw new IllegalArgumentException("Base directory '" + baseDir + "' must be absolute."); | ||
} | ||
|
||
List<String> bindings = volumeConfiguration.getBind(); | ||
|
||
if (bindings.isEmpty()) { | ||
return; | ||
} | ||
|
||
for (int i = 0; i < bindings.size(); i++) { | ||
bindings.set(i, resolveRelativeVolumeBinding(baseDir, bindings.get(i))); | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe a better option would be using the
File#getCanonicalPath
method to resolve relative paths. So that also../
is resolved correctly.