Skip to content

Commit

Permalink
feat: add Windows support, use different mount source
Browse files Browse the repository at this point in the history
  • Loading branch information
Oleg Kainov committed Apr 27, 2021
1 parent 237334c commit 59676c0
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 59 deletions.
5 changes: 3 additions & 2 deletions pre_commit/languages/docker.py
Expand Up @@ -36,8 +36,9 @@ def _get_docker_path(path: str) -> str:
)

docker_output = json.loads(out)
for mount_path in docker_output[0]['HostConfig']['Binds']:
src_path, to_path, *_ = mount_path.split(':')
for mount in docker_output[0]['Mounts']:
src_path = mount['Source']
to_path = mount['Destination']
if os.path.commonpath((path, to_path)) == to_path:
# So there is something in common,
# and we can proceed remapping it
Expand Down
169 changes: 112 additions & 57 deletions tests/languages/docker_test.py
@@ -1,6 +1,8 @@
import builtins
import json
from typing import List
import ntpath
import os.path as path_module
import posixpath
from unittest import mock

import pytest
Expand Down Expand Up @@ -52,6 +54,29 @@ def in_docker(self):
with mock.patch.object(docker, '_is_in_docker', return_value=True):
yield

@pytest.fixture
def in_linux(self):
# We cannot yield directly because then it will make pytest crazy
return lambda: mock.patch.object(
path_module, 'commonpath',
wraps=posixpath.commonpath,
)

@pytest.fixture
def in_windows(self):
# We cannot yield directly because then it will make pytest crazy
return lambda: mock.patch.object(
path_module, 'commonpath',
wraps=ntpath.commonpath,
)

@pytest.fixture
def docker_output(self):
return lambda cmd: mock.patch.object(
docker, 'cmd_output_b',
return_value=(0, cmd, b''),
)

@pytest.fixture
def not_in_docker(self):
with mock.patch.object(docker, '_is_in_docker', return_value=False):
Expand All @@ -60,85 +85,115 @@ def not_in_docker(self):
def test_not_in_docker_returns_same(self, not_in_docker):
assert docker._get_docker_path('abc') == 'abc'

def test_in_docker_no_binds_same_path(self, in_docker):
binds_list: List[str] = []
def test_in_docker_no_binds_same_path(self, in_docker, docker_output):
output_string = json.dumps(
[{'HostConfig': {'Binds': binds_list}}],
[{'Mounts': []}],
).encode('utf-8')
with mock.patch.object(
docker, 'cmd_output_b',
return_value=(0, output_string, b''),
):

with docker_output(output_string):
assert docker._get_docker_path('abc') == 'abc'

def test_in_docker_binds_path_equal(self, in_docker):
def test_in_docker_binds_path_equal(
self,
in_docker,
in_linux,
docker_output,
):
binds_list = [
'/opt/my_code:/project',
{
'Source': '/opt/my_code',
'Destination': '/project',
},
]
output_string = json.dumps(
[{'HostConfig': {'Binds': binds_list}}],
[{'Mounts': binds_list}],
).encode('utf-8')
with mock.patch.object(
docker, 'cmd_output_b',
return_value=(0, output_string, b''),
):
assert docker._get_docker_path('/project') == '/opt/my_code'

def test_in_docker_binds_path_complex(self, in_docker):
with in_linux():
with docker_output(output_string):
path = '/project'
expected = '/opt/my_code'
assert docker._get_docker_path(path) == expected

def test_in_docker_binds_path_complex(
self,
in_docker,
in_linux,
docker_output,
):
binds_list = [
'/opt/my_code:/project',
{
'Source': '/opt/my_code',
'Destination': '/project',
},
]
output_string = json.dumps(
[{'HostConfig': {'Binds': binds_list}}],
[{'Mounts': binds_list}],
).encode('utf-8')
with mock.patch.object(
docker, 'cmd_output_b',
return_value=(0, output_string, b''),
):
path = '/project/test/something'
expected = '/opt/my_code/test/something'
assert docker._get_docker_path(path) == expected

def test_in_docker_no_substring(self, in_docker):

with in_linux():
with docker_output(output_string):
path = '/project/test/something'
expected = '/opt/my_code/test/something'
assert docker._get_docker_path(path) == expected

def test_in_docker_no_substring(self, in_docker, in_linux, docker_output):
binds_list = [
'/opt/my_code:/project',
{
'Source': '/opt/my_code',
'Destination': '/project',
},
]
output_string = json.dumps(
[{'HostConfig': {'Binds': binds_list}}],
[{'Mounts': binds_list}],
).encode('utf-8')
with mock.patch.object(
docker, 'cmd_output_b',
return_value=(0, output_string, b''),
):
path = '/projectSUffix/test/something'
assert docker._get_docker_path(path) == path

def test_in_docker_binds_path_many_binds(self, in_docker):

with in_linux():
with docker_output(output_string):
path = '/projectSUffix/test/something'
assert docker._get_docker_path(path) == path

def test_in_docker_binds_path_many_binds(
self,
in_docker,
in_linux,
docker_output,
):
binds_list = [
'/something_random:/not_related',
'/opt/my_code:/project',
'/something_random2:/not_related2',
{
'Source': '/something_random',
'Destination': '/not-related',
},
{
'Source': '/opt/my_code',
'Destination': '/project',
},
{
'Source': '/something-random-2',
'Destination': '/not-related-2',
},
]
output_string = json.dumps(
[{'HostConfig': {'Binds': binds_list}}],
[{'Mounts': binds_list}],
).encode('utf-8')
with mock.patch.object(
docker, 'cmd_output_b',
return_value=(0, output_string, b''),
):
assert docker._get_docker_path('/project') == '/opt/my_code'

def test_in_docker_two_colons(self, in_docker):
with in_linux():
with docker_output(output_string):
assert docker._get_docker_path('/project') == '/opt/my_code'

def test_in_docker_windows(self, in_docker, in_windows, docker_output):
binds_list = [
'/opt/my_code:/project:qqqrandom',
{
'Source': r'c:\users\user',
'Destination': r'c:\folder',
},
]
output_string = json.dumps(
[{'HostConfig': {'Binds': binds_list}}],
[{'Mounts': binds_list}],
).encode('utf-8')
with mock.patch.object(
docker, 'cmd_output_b',
return_value=(0, output_string, b''),
):
path = '/project/test/something'
expected = '/opt/my_code/test/something'
assert docker._get_docker_path(path) == expected

with in_windows():
with docker_output(output_string):
path = r'c:\folder\test\something'
expected = r'c:\users\user\test\something'
assert docker._get_docker_path(path) == expected

0 comments on commit 59676c0

Please sign in to comment.