mirror of https://github.com/docker/compose.git
Handle windows volume paths
When a relative path is expanded and we're on a windows platform, it expands to include the drive, eg C:\ , which was causing a ConfigError as we split on ":" in parse_volume_spec and that was giving too many parts. Use os.path.splitdrive instead of manually calculating the drive. This should help us deal with windows drives as part of the volume path better than us doing it manually. Signed-off-by: Mazz Mosley <mazz@houseofmnowster.com>
This commit is contained in:
parent
c673ce37c7
commit
f4cd5b1d45
|
@ -526,12 +526,13 @@ def path_mappings_from_dict(d):
|
|||
return [join_path_mapping(v) for v in d.items()]
|
||||
|
||||
|
||||
def split_path_mapping(string):
|
||||
if ':' in string:
|
||||
(host, container) = string.split(':', 1)
|
||||
return (container, host)
|
||||
def split_path_mapping(volume_path):
|
||||
drive, volume_config = os.path.splitdrive(volume_path)
|
||||
if ':' in volume_config:
|
||||
(host, container) = volume_config.split(':', 1)
|
||||
return (container, drive + host)
|
||||
else:
|
||||
return (string, None)
|
||||
return (volume_path, None)
|
||||
|
||||
|
||||
def join_path_mapping(pair):
|
||||
|
|
|
@ -2,6 +2,7 @@ import os
|
|||
import sys
|
||||
|
||||
DEFAULT_TIMEOUT = 10
|
||||
IS_WINDOWS_PLATFORM = (sys.platform == "win32")
|
||||
LABEL_CONTAINER_NUMBER = 'com.docker.compose.container-number'
|
||||
LABEL_ONE_OFF = 'com.docker.compose.oneoff'
|
||||
LABEL_PROJECT = 'com.docker.compose.project'
|
||||
|
|
|
@ -20,6 +20,7 @@ from .config import DOCKER_CONFIG_KEYS
|
|||
from .config import merge_environment
|
||||
from .config.validation import VALID_NAME_CHARS
|
||||
from .const import DEFAULT_TIMEOUT
|
||||
from .const import IS_WINDOWS_PLATFORM
|
||||
from .const import LABEL_CONFIG_HASH
|
||||
from .const import LABEL_CONTAINER_NUMBER
|
||||
from .const import LABEL_ONE_OFF
|
||||
|
@ -937,7 +938,20 @@ def build_volume_binding(volume_spec):
|
|||
|
||||
|
||||
def parse_volume_spec(volume_config):
|
||||
"""
|
||||
A volume_config string, which is a path, split it into external:internal[:mode]
|
||||
parts to be returned as a valid VolumeSpec tuple.
|
||||
"""
|
||||
parts = volume_config.split(':')
|
||||
|
||||
if IS_WINDOWS_PLATFORM:
|
||||
# relative paths in windows expand to include the drive, eg C:\
|
||||
# so we join the first 2 parts back together to count as one
|
||||
drive, volume_path = os.path.splitdrive(volume_config)
|
||||
windows_parts = volume_path.split(":")
|
||||
windows_parts[0] = os.path.join(drive, windows_parts[0])
|
||||
parts = windows_parts
|
||||
|
||||
if len(parts) > 3:
|
||||
raise ConfigError("Volume %s has incorrect format, should be "
|
||||
"external:internal[:mode]" % volume_config)
|
||||
|
|
|
@ -1124,6 +1124,21 @@ class ExpandPathTest(unittest.TestCase):
|
|||
self.assertEqual(result, user_path + 'otherdir/somefile')
|
||||
|
||||
|
||||
class VolumePathTest(unittest.TestCase):
|
||||
|
||||
@pytest.mark.xfail((not IS_WINDOWS_PLATFORM), reason='does not have a drive')
|
||||
def test_split_path_mapping_with_windows_path(self):
|
||||
windows_volume_path = "c:\\Users\\msamblanet\\Documents\\anvil\\connect\\config:/opt/connect/config:ro"
|
||||
expected_mapping = (
|
||||
"/opt/connect/config:ro",
|
||||
"c:\\Users\\msamblanet\\Documents\\anvil\\connect\\config"
|
||||
)
|
||||
|
||||
mapping = config.split_path_mapping(windows_volume_path)
|
||||
|
||||
self.assertEqual(mapping, expected_mapping)
|
||||
|
||||
|
||||
@pytest.mark.xfail(IS_WINDOWS_PLATFORM, reason='paths use slash')
|
||||
class BuildPathTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
|
|
|
@ -466,6 +466,21 @@ class ServiceVolumesTest(unittest.TestCase):
|
|||
with self.assertRaises(ConfigError):
|
||||
parse_volume_spec('one:two:three:four')
|
||||
|
||||
@pytest.mark.xfail((not IS_WINDOWS_PLATFORM), reason='does not have a drive')
|
||||
def test_parse_volume_windows_relative_path(self):
|
||||
windows_relative_path = "c:\\Users\\msamblanet\\Documents\\anvil\\connect\\config:\\opt\\connect\\config:ro"
|
||||
|
||||
spec = parse_volume_spec(windows_relative_path)
|
||||
|
||||
self.assertEqual(
|
||||
spec,
|
||||
(
|
||||
"c:\\Users\\msamblanet\\Documents\\anvil\\connect\\config",
|
||||
"\\opt\\connect\\config",
|
||||
"ro"
|
||||
)
|
||||
)
|
||||
|
||||
def test_build_volume_binding(self):
|
||||
binding = build_volume_binding(parse_volume_spec('/outside:/inside'))
|
||||
self.assertEqual(binding, ('/inside', '/outside:/inside:rw'))
|
||||
|
|
Loading…
Reference in New Issue