public static String resolveRelativeVolumeBinding(File baseDir, String bindingString) {

        // 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];

        if (isRelativePath(localPath)) {
            File resolvedFile;
            if (isUserHomeRelativePath(localPath)) {
                resolvedFile = resolveAbsolutely(prepareUserHomeRelativePath(localPath), System.getProperty("user.home"));
            } else {
                if (!baseDir.isAbsolute()) {
                    throw new IllegalArgumentException("Base directory '" + baseDir + "' must be absolute.");
                }
                resolvedFile = resolveAbsolutely(localPath, baseDir.getAbsolutePath());
            }
            try {
                localPath = resolvedFile.getCanonicalFile().getAbsolutePath();
            } catch (IOException e) {
                throw new RuntimeException("Unable to canonicalize '" + resolvedFile + "'");
            }
        }

        if (pathParts.length > 1) {
            pathParts[0] = localPath;
            return join(":", pathParts);
        }

        return localPath;
    }
public static String resolveRelativeVolumeBinding ( File baseDir , String bindingString ) { String [ ] pathParts = bindingString . split ( ":" ) ; String localPath = pathParts [ 0 ] ; if ( isRelativePath ( localPath ) ) { File resolvedFile ; if ( isUserHomeRelativePath ( localPath ) ) { resolvedFile = resolveAbsolutely ( prepareUserHomeRelativePath ( localPath ) , System . getProperty ( "user.home" ) ) ; } else { if ( ! baseDir . isAbsolute ( ) ) { throw new IllegalArgumentException ( "Base directory '" + baseDir + "' must be absolute." ) ; } resolvedFile = resolveAbsolutely ( localPath , baseDir . getAbsolutePath ( ) ) ; } try { localPath = resolvedFile . getCanonicalFile ( ) . getAbsolutePath ( ) ; } catch ( IOException e ) { throw new RuntimeException ( "Unable to canonicalize '" + resolvedFile + "'" ) ; } } if ( pathParts . length > 1 ) { pathParts [ 0 ] = localPath ; return join ( ":" , pathParts ) ; } return localPath ; }
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 ./}, {@code ../}, or
{@code ~}.  Relative paths beginning with {@code ./} or {@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 ./}, {@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/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 /home/user/reldir:/some/other/dir}
</p>
<p>
Given {@code baseDir} equal to "/path/to/basedir" and a {@code bindingString} equal to
"src/test/docker:/some/other/dir", this method returns {@code /path/to/basedir/src/test/docker:/some/other/dir}
</p>
<p>
Given a {@code bindingString} equal to "foo:/some/other/dir", this method returns {@code foo:/some/other/dir},
because {@code foo} is considered to be a <em>named volume</em>, not a relative path.
</p>

@param baseDir the base directory used to resolve relative paths (e.g. beginning with {@code ./}, {@code ../},
{@code ~}) present in the {@code bindingString}; <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