Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
D
docker-py
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
docker-py
Commits
088094c6
Kaydet (Commit)
088094c6
authored
Haz 28, 2018
tarafından
Joffrey F
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
On Windows, convert paths to use forward slashes before fnmatch call
Signed-off-by:
Joffrey F
<
joffrey@docker.com
>
üst
5017de49
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
511 additions
and
490 deletions
+511
-490
build.py
docker/utils/build.py
+13
-5
utils_build_test.py
tests/unit/utils_build_test.py
+493
-0
utils_test.py
tests/unit/utils_test.py
+5
-485
No files found.
docker/utils/build.py
Dosyayı görüntüle @
088094c6
import
io
import
os
import
re
import
six
import
tarfile
import
tempfile
from
..constants
import
IS_WINDOWS_PLATFORM
import
six
from
.fnmatch
import
fnmatch
from
..constants
import
IS_WINDOWS_PLATFORM
_SEP
=
re
.
compile
(
'/|
\\\\
'
)
if
IS_WINDOWS_PLATFORM
else
re
.
compile
(
'/'
)
...
...
@@ -139,6 +140,12 @@ def split_path(p):
return
[
pt
for
pt
in
re
.
split
(
_SEP
,
p
)
if
pt
and
pt
!=
'.'
]
def
normalize_slashes
(
p
):
if
IS_WINDOWS_PLATFORM
:
return
'/'
.
join
(
split_path
(
p
))
return
p
# Heavily based on
# https://github.com/moby/moby/blob/master/pkg/fileutils/fileutils.go
class
PatternMatcher
(
object
):
...
...
@@ -184,7 +191,7 @@ class PatternMatcher(object):
continue
if
match
:
# If we want to skip this file and its a directory
# If we want to skip this file and it
'
s a directory
# then we should first check to see if there's an
# excludes pattern (e.g. !dir/file) that starts with this
# dir. If so then we can't skip this dir.
...
...
@@ -193,7 +200,8 @@ class PatternMatcher(object):
for
pat
in
self
.
patterns
:
if
not
pat
.
exclusion
:
continue
if
pat
.
cleaned_pattern
.
startswith
(
fpath
):
if
pat
.
cleaned_pattern
.
startswith
(
normalize_slashes
(
fpath
)):
skip
=
False
break
if
skip
:
...
...
@@ -239,4 +247,4 @@ class Pattern(object):
return
split
def
match
(
self
,
filepath
):
return
fnmatch
(
filepath
,
self
.
cleaned_pattern
)
return
fnmatch
(
normalize_slashes
(
filepath
)
,
self
.
cleaned_pattern
)
tests/unit/utils_build_test.py
0 → 100644
Dosyayı görüntüle @
088094c6
# -*- coding: utf-8 -*-
import
os
import
os.path
import
shutil
import
socket
import
tarfile
import
tempfile
import
unittest
from
docker.constants
import
IS_WINDOWS_PLATFORM
from
docker.utils
import
exclude_paths
,
tar
import
pytest
from
..helpers
import
make_tree
def
convert_paths
(
collection
):
return
set
(
map
(
convert_path
,
collection
))
def
convert_path
(
path
):
return
path
.
replace
(
'/'
,
os
.
path
.
sep
)
class
ExcludePathsTest
(
unittest
.
TestCase
):
dirs
=
[
'foo'
,
'foo/bar'
,
'bar'
,
'target'
,
'target/subdir'
,
'subdir'
,
'subdir/target'
,
'subdir/target/subdir'
,
'subdir/subdir2'
,
'subdir/subdir2/target'
,
'subdir/subdir2/target/subdir'
]
files
=
[
'Dockerfile'
,
'Dockerfile.alt'
,
'.dockerignore'
,
'a.py'
,
'a.go'
,
'b.py'
,
'cde.py'
,
'foo/a.py'
,
'foo/b.py'
,
'foo/bar/a.py'
,
'bar/a.py'
,
'foo/Dockerfile3'
,
'target/file.txt'
,
'target/subdir/file.txt'
,
'subdir/file.txt'
,
'subdir/target/file.txt'
,
'subdir/target/subdir/file.txt'
,
'subdir/subdir2/file.txt'
,
'subdir/subdir2/target/file.txt'
,
'subdir/subdir2/target/subdir/file.txt'
,
]
all_paths
=
set
(
dirs
+
files
)
def
setUp
(
self
):
self
.
base
=
make_tree
(
self
.
dirs
,
self
.
files
)
def
tearDown
(
self
):
shutil
.
rmtree
(
self
.
base
)
def
exclude
(
self
,
patterns
,
dockerfile
=
None
):
return
set
(
exclude_paths
(
self
.
base
,
patterns
,
dockerfile
=
dockerfile
))
def
test_no_excludes
(
self
):
assert
self
.
exclude
([
''
])
==
convert_paths
(
self
.
all_paths
)
def
test_no_dupes
(
self
):
paths
=
exclude_paths
(
self
.
base
,
[
'!a.py'
])
assert
sorted
(
paths
)
==
sorted
(
set
(
paths
))
def
test_wildcard_exclude
(
self
):
assert
self
.
exclude
([
'*'
])
==
set
([
'Dockerfile'
,
'.dockerignore'
])
def
test_exclude_dockerfile_dockerignore
(
self
):
"""
Even if the .dockerignore file explicitly says to exclude
Dockerfile and/or .dockerignore, don't exclude them from
the actual tar file.
"""
assert
self
.
exclude
([
'Dockerfile'
,
'.dockerignore'
])
==
convert_paths
(
self
.
all_paths
)
def
test_exclude_custom_dockerfile
(
self
):
"""
If we're using a custom Dockerfile, make sure that's not
excluded.
"""
assert
self
.
exclude
([
'*'
],
dockerfile
=
'Dockerfile.alt'
)
==
set
(
[
'Dockerfile.alt'
,
'.dockerignore'
]
)
assert
self
.
exclude
(
[
'*'
],
dockerfile
=
'foo/Dockerfile3'
)
==
convert_paths
(
set
([
'foo/Dockerfile3'
,
'.dockerignore'
]))
# https://github.com/docker/docker-py/issues/1956
assert
self
.
exclude
(
[
'*'
],
dockerfile
=
'./foo/Dockerfile3'
)
==
convert_paths
(
set
([
'foo/Dockerfile3'
,
'.dockerignore'
]))
def
test_exclude_dockerfile_child
(
self
):
includes
=
self
.
exclude
([
'foo/'
],
dockerfile
=
'foo/Dockerfile3'
)
assert
convert_path
(
'foo/Dockerfile3'
)
in
includes
assert
convert_path
(
'foo/a.py'
)
not
in
includes
def
test_single_filename
(
self
):
assert
self
.
exclude
([
'a.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'a.py'
])
)
def
test_single_filename_leading_dot_slash
(
self
):
assert
self
.
exclude
([
'./a.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'a.py'
])
)
# As odd as it sounds, a filename pattern with a trailing slash on the
# end *will* result in that file being excluded.
def
test_single_filename_trailing_slash
(
self
):
assert
self
.
exclude
([
'a.py/'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'a.py'
])
)
def
test_wildcard_filename_start
(
self
):
assert
self
.
exclude
([
'*.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'a.py'
,
'b.py'
,
'cde.py'
])
)
def
test_wildcard_with_exception
(
self
):
assert
self
.
exclude
([
'*.py'
,
'!b.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'a.py'
,
'cde.py'
])
)
def
test_wildcard_with_wildcard_exception
(
self
):
assert
self
.
exclude
([
'*.*'
,
'!*.go'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'a.py'
,
'b.py'
,
'cde.py'
,
'Dockerfile.alt'
,
])
)
def
test_wildcard_filename_end
(
self
):
assert
self
.
exclude
([
'a.*'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'a.py'
,
'a.go'
])
)
def
test_question_mark
(
self
):
assert
self
.
exclude
([
'?.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'a.py'
,
'b.py'
])
)
def
test_single_subdir_single_filename
(
self
):
assert
self
.
exclude
([
'foo/a.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/a.py'
])
)
def
test_single_subdir_single_filename_leading_slash
(
self
):
assert
self
.
exclude
([
'/foo/a.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/a.py'
])
)
def
test_exclude_include_absolute_path
(
self
):
base
=
make_tree
([],
[
'a.py'
,
'b.py'
])
assert
exclude_paths
(
base
,
[
'/*'
,
'!/*.py'
]
)
==
set
([
'a.py'
,
'b.py'
])
def
test_single_subdir_with_path_traversal
(
self
):
assert
self
.
exclude
([
'foo/whoops/../a.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/a.py'
])
)
def
test_single_subdir_wildcard_filename
(
self
):
assert
self
.
exclude
([
'foo/*.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/a.py'
,
'foo/b.py'
])
)
def
test_wildcard_subdir_single_filename
(
self
):
assert
self
.
exclude
([
'*/a.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/a.py'
,
'bar/a.py'
])
)
def
test_wildcard_subdir_wildcard_filename
(
self
):
assert
self
.
exclude
([
'*/*.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/a.py'
,
'foo/b.py'
,
'bar/a.py'
])
)
def
test_directory
(
self
):
assert
self
.
exclude
([
'foo'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo'
,
'foo/a.py'
,
'foo/b.py'
,
'foo/bar'
,
'foo/bar/a.py'
,
'foo/Dockerfile3'
])
)
def
test_directory_with_trailing_slash
(
self
):
assert
self
.
exclude
([
'foo'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo'
,
'foo/a.py'
,
'foo/b.py'
,
'foo/bar'
,
'foo/bar/a.py'
,
'foo/Dockerfile3'
])
)
def
test_directory_with_single_exception
(
self
):
assert
self
.
exclude
([
'foo'
,
'!foo/bar/a.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/a.py'
,
'foo/b.py'
,
'foo'
,
'foo/bar'
,
'foo/Dockerfile3'
])
)
def
test_directory_with_subdir_exception
(
self
):
assert
self
.
exclude
([
'foo'
,
'!foo/bar'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/a.py'
,
'foo/b.py'
,
'foo'
,
'foo/Dockerfile3'
])
)
@pytest.mark.skipif
(
not
IS_WINDOWS_PLATFORM
,
reason
=
'Backslash patterns only on Windows'
)
def
test_directory_with_subdir_exception_win32_pathsep
(
self
):
assert
self
.
exclude
([
'foo'
,
'!foo
\\
bar'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/a.py'
,
'foo/b.py'
,
'foo'
,
'foo/Dockerfile3'
])
)
def
test_directory_with_wildcard_exception
(
self
):
assert
self
.
exclude
([
'foo'
,
'!foo/*.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/bar'
,
'foo/bar/a.py'
,
'foo'
,
'foo/Dockerfile3'
])
)
def
test_subdirectory
(
self
):
assert
self
.
exclude
([
'foo/bar'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/bar'
,
'foo/bar/a.py'
])
)
@pytest.mark.skipif
(
not
IS_WINDOWS_PLATFORM
,
reason
=
'Backslash patterns only on Windows'
)
def
test_subdirectory_win32_pathsep
(
self
):
assert
self
.
exclude
([
'foo
\\
bar'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/bar'
,
'foo/bar/a.py'
])
)
def
test_double_wildcard
(
self
):
assert
self
.
exclude
([
'**/a.py'
])
==
convert_paths
(
self
.
all_paths
-
set
(
[
'a.py'
,
'foo/a.py'
,
'foo/bar/a.py'
,
'bar/a.py'
]
)
)
assert
self
.
exclude
([
'foo/**/bar'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/bar'
,
'foo/bar/a.py'
])
)
def
test_single_and_double_wildcard
(
self
):
assert
self
.
exclude
([
'**/target/*/*'
])
==
convert_paths
(
self
.
all_paths
-
set
(
[
'target/subdir/file.txt'
,
'subdir/target/subdir/file.txt'
,
'subdir/subdir2/target/subdir/file.txt'
]
)
)
def
test_trailing_double_wildcard
(
self
):
assert
self
.
exclude
([
'subdir/**'
])
==
convert_paths
(
self
.
all_paths
-
set
(
[
'subdir/file.txt'
,
'subdir/target/file.txt'
,
'subdir/target/subdir/file.txt'
,
'subdir/subdir2/file.txt'
,
'subdir/subdir2/target/file.txt'
,
'subdir/subdir2/target/subdir/file.txt'
,
'subdir/target'
,
'subdir/target/subdir'
,
'subdir/subdir2'
,
'subdir/subdir2/target'
,
'subdir/subdir2/target/subdir'
]
)
)
def
test_double_wildcard_with_exception
(
self
):
assert
self
.
exclude
([
'**'
,
'!bar'
,
'!foo/bar'
])
==
convert_paths
(
set
([
'foo/bar'
,
'foo/bar/a.py'
,
'bar'
,
'bar/a.py'
,
'Dockerfile'
,
'.dockerignore'
,
])
)
def
test_include_wildcard
(
self
):
# This may be surprising but it matches the CLI's behavior
# (tested with 18.05.0-ce on linux)
base
=
make_tree
([
'a'
],
[
'a/b.py'
])
assert
exclude_paths
(
base
,
[
'*'
,
'!*/b.py'
]
)
==
set
()
def
test_last_line_precedence
(
self
):
base
=
make_tree
(
[],
[
'garbage.md'
,
'trash.md'
,
'README.md'
,
'README-bis.md'
,
'README-secret.md'
])
assert
exclude_paths
(
base
,
[
'*.md'
,
'!README*.md'
,
'README-secret.md'
]
)
==
set
([
'README.md'
,
'README-bis.md'
])
def
test_parent_directory
(
self
):
base
=
make_tree
(
[],
[
'a.py'
,
'b.py'
,
'c.py'
])
# Dockerignore reference stipulates that absolute paths are
# equivalent to relative paths, hence /../foo should be
# equivalent to ../foo. It also stipulates that paths are run
# through Go's filepath.Clean, which explicitely "replace
# "/.." by "/" at the beginning of a path".
assert
exclude_paths
(
base
,
[
'../a.py'
,
'/../b.py'
]
)
==
set
([
'c.py'
])
class
TarTest
(
unittest
.
TestCase
):
def
test_tar_with_excludes
(
self
):
dirs
=
[
'foo'
,
'foo/bar'
,
'bar'
,
]
files
=
[
'Dockerfile'
,
'Dockerfile.alt'
,
'.dockerignore'
,
'a.py'
,
'a.go'
,
'b.py'
,
'cde.py'
,
'foo/a.py'
,
'foo/b.py'
,
'foo/bar/a.py'
,
'bar/a.py'
,
]
exclude
=
[
'*.py'
,
'!b.py'
,
'!a.go'
,
'foo'
,
'Dockerfile*'
,
'.dockerignore'
,
]
expected_names
=
set
([
'Dockerfile'
,
'.dockerignore'
,
'a.go'
,
'b.py'
,
'bar'
,
'bar/a.py'
,
])
base
=
make_tree
(
dirs
,
files
)
self
.
addCleanup
(
shutil
.
rmtree
,
base
)
with
tar
(
base
,
exclude
=
exclude
)
as
archive
:
tar_data
=
tarfile
.
open
(
fileobj
=
archive
)
assert
sorted
(
tar_data
.
getnames
())
==
sorted
(
expected_names
)
def
test_tar_with_empty_directory
(
self
):
base
=
tempfile
.
mkdtemp
()
self
.
addCleanup
(
shutil
.
rmtree
,
base
)
for
d
in
[
'foo'
,
'bar'
]:
os
.
makedirs
(
os
.
path
.
join
(
base
,
d
))
with
tar
(
base
)
as
archive
:
tar_data
=
tarfile
.
open
(
fileobj
=
archive
)
assert
sorted
(
tar_data
.
getnames
())
==
[
'bar'
,
'foo'
]
@pytest.mark.skipif
(
IS_WINDOWS_PLATFORM
or
os
.
geteuid
()
==
0
,
reason
=
'root user always has access ; no chmod on Windows'
)
def
test_tar_with_inaccessible_file
(
self
):
base
=
tempfile
.
mkdtemp
()
full_path
=
os
.
path
.
join
(
base
,
'foo'
)
self
.
addCleanup
(
shutil
.
rmtree
,
base
)
with
open
(
full_path
,
'w'
)
as
f
:
f
.
write
(
'content'
)
os
.
chmod
(
full_path
,
0
o222
)
with
pytest
.
raises
(
IOError
)
as
ei
:
tar
(
base
)
assert
'Can not read file in context: {}'
.
format
(
full_path
)
in
(
ei
.
exconly
()
)
@pytest.mark.skipif
(
IS_WINDOWS_PLATFORM
,
reason
=
'No symlinks on Windows'
)
def
test_tar_with_file_symlinks
(
self
):
base
=
tempfile
.
mkdtemp
()
self
.
addCleanup
(
shutil
.
rmtree
,
base
)
with
open
(
os
.
path
.
join
(
base
,
'foo'
),
'w'
)
as
f
:
f
.
write
(
"content"
)
os
.
makedirs
(
os
.
path
.
join
(
base
,
'bar'
))
os
.
symlink
(
'../foo'
,
os
.
path
.
join
(
base
,
'bar/foo'
))
with
tar
(
base
)
as
archive
:
tar_data
=
tarfile
.
open
(
fileobj
=
archive
)
assert
sorted
(
tar_data
.
getnames
())
==
[
'bar'
,
'bar/foo'
,
'foo'
]
@pytest.mark.skipif
(
IS_WINDOWS_PLATFORM
,
reason
=
'No symlinks on Windows'
)
def
test_tar_with_directory_symlinks
(
self
):
base
=
tempfile
.
mkdtemp
()
self
.
addCleanup
(
shutil
.
rmtree
,
base
)
for
d
in
[
'foo'
,
'bar'
]:
os
.
makedirs
(
os
.
path
.
join
(
base
,
d
))
os
.
symlink
(
'../foo'
,
os
.
path
.
join
(
base
,
'bar/foo'
))
with
tar
(
base
)
as
archive
:
tar_data
=
tarfile
.
open
(
fileobj
=
archive
)
assert
sorted
(
tar_data
.
getnames
())
==
[
'bar'
,
'bar/foo'
,
'foo'
]
@pytest.mark.skipif
(
IS_WINDOWS_PLATFORM
,
reason
=
'No symlinks on Windows'
)
def
test_tar_with_broken_symlinks
(
self
):
base
=
tempfile
.
mkdtemp
()
self
.
addCleanup
(
shutil
.
rmtree
,
base
)
for
d
in
[
'foo'
,
'bar'
]:
os
.
makedirs
(
os
.
path
.
join
(
base
,
d
))
os
.
symlink
(
'../baz'
,
os
.
path
.
join
(
base
,
'bar/foo'
))
with
tar
(
base
)
as
archive
:
tar_data
=
tarfile
.
open
(
fileobj
=
archive
)
assert
sorted
(
tar_data
.
getnames
())
==
[
'bar'
,
'bar/foo'
,
'foo'
]
@pytest.mark.skipif
(
IS_WINDOWS_PLATFORM
,
reason
=
'No UNIX sockets on Win32'
)
def
test_tar_socket_file
(
self
):
base
=
tempfile
.
mkdtemp
()
self
.
addCleanup
(
shutil
.
rmtree
,
base
)
for
d
in
[
'foo'
,
'bar'
]:
os
.
makedirs
(
os
.
path
.
join
(
base
,
d
))
sock
=
socket
.
socket
(
socket
.
AF_UNIX
)
self
.
addCleanup
(
sock
.
close
)
sock
.
bind
(
os
.
path
.
join
(
base
,
'test.sock'
))
with
tar
(
base
)
as
archive
:
tar_data
=
tarfile
.
open
(
fileobj
=
archive
)
assert
sorted
(
tar_data
.
getnames
())
==
[
'bar'
,
'foo'
]
def
tar_test_negative_mtime_bug
(
self
):
base
=
tempfile
.
mkdtemp
()
filename
=
os
.
path
.
join
(
base
,
'th.txt'
)
self
.
addCleanup
(
shutil
.
rmtree
,
base
)
with
open
(
filename
,
'w'
)
as
f
:
f
.
write
(
'Invisible Full Moon'
)
os
.
utime
(
filename
,
(
12345
,
-
3600.0
))
with
tar
(
base
)
as
archive
:
tar_data
=
tarfile
.
open
(
fileobj
=
archive
)
assert
tar_data
.
getnames
()
==
[
'th.txt'
]
assert
tar_data
.
getmember
(
'th.txt'
)
.
mtime
==
-
3600
@pytest.mark.skipif
(
IS_WINDOWS_PLATFORM
,
reason
=
'No symlinks on Windows'
)
def
test_tar_directory_link
(
self
):
dirs
=
[
'a'
,
'b'
,
'a/c'
]
files
=
[
'a/hello.py'
,
'b/utils.py'
,
'a/c/descend.py'
]
base
=
make_tree
(
dirs
,
files
)
self
.
addCleanup
(
shutil
.
rmtree
,
base
)
os
.
symlink
(
os
.
path
.
join
(
base
,
'b'
),
os
.
path
.
join
(
base
,
'a/c/b'
))
with
tar
(
base
)
as
archive
:
tar_data
=
tarfile
.
open
(
fileobj
=
archive
)
names
=
tar_data
.
getnames
()
for
member
in
dirs
+
files
:
assert
member
in
names
assert
'a/c/b'
in
names
assert
'a/c/b/utils.py'
not
in
names
tests/unit/utils_test.py
Dosyayı görüntüle @
088094c6
...
...
@@ -5,29 +5,25 @@ import json
import
os
import
os.path
import
shutil
import
socket
import
sys
import
tarfile
import
tempfile
import
unittest
import
pytest
import
six
from
docker.api.client
import
APIClient
from
docker.constants
import
IS_WINDOWS_PLATFORM
from
docker.errors
import
DockerException
from
docker.utils
import
(
parse_repository_tag
,
parse_host
,
convert_filters
,
kwargs_from_env
,
parse_bytes
,
parse_
env_file
,
exclude_paths
,
convert_volume_binds
,
decode_json_header
,
tar
,
split_command
,
parse_devices
,
update_headers
,
convert_filters
,
convert_volume_binds
,
decode_json_header
,
kwargs_from_env
,
parse_bytes
,
parse_
devices
,
parse_env_file
,
parse_host
,
parse_repository_tag
,
split_command
,
update_headers
,
)
from
docker.utils.ports
import
build_port_bindings
,
split_port
from
docker.utils.utils
import
format_environment
from
..helpers
import
make_tree
import
pytest
import
six
TEST_CERT_DIR
=
os
.
path
.
join
(
os
.
path
.
dirname
(
__file__
),
...
...
@@ -608,482 +604,6 @@ class PortsTest(unittest.TestCase):
assert
port_bindings
[
"2000"
]
==
[(
"127.0.0.1"
,
"2000"
)]
def
convert_paths
(
collection
):
return
set
(
map
(
convert_path
,
collection
))
def
convert_path
(
path
):
return
path
.
replace
(
'/'
,
os
.
path
.
sep
)
class
ExcludePathsTest
(
unittest
.
TestCase
):
dirs
=
[
'foo'
,
'foo/bar'
,
'bar'
,
'target'
,
'target/subdir'
,
'subdir'
,
'subdir/target'
,
'subdir/target/subdir'
,
'subdir/subdir2'
,
'subdir/subdir2/target'
,
'subdir/subdir2/target/subdir'
]
files
=
[
'Dockerfile'
,
'Dockerfile.alt'
,
'.dockerignore'
,
'a.py'
,
'a.go'
,
'b.py'
,
'cde.py'
,
'foo/a.py'
,
'foo/b.py'
,
'foo/bar/a.py'
,
'bar/a.py'
,
'foo/Dockerfile3'
,
'target/file.txt'
,
'target/subdir/file.txt'
,
'subdir/file.txt'
,
'subdir/target/file.txt'
,
'subdir/target/subdir/file.txt'
,
'subdir/subdir2/file.txt'
,
'subdir/subdir2/target/file.txt'
,
'subdir/subdir2/target/subdir/file.txt'
,
]
all_paths
=
set
(
dirs
+
files
)
def
setUp
(
self
):
self
.
base
=
make_tree
(
self
.
dirs
,
self
.
files
)
def
tearDown
(
self
):
shutil
.
rmtree
(
self
.
base
)
def
exclude
(
self
,
patterns
,
dockerfile
=
None
):
return
set
(
exclude_paths
(
self
.
base
,
patterns
,
dockerfile
=
dockerfile
))
def
test_no_excludes
(
self
):
assert
self
.
exclude
([
''
])
==
convert_paths
(
self
.
all_paths
)
def
test_no_dupes
(
self
):
paths
=
exclude_paths
(
self
.
base
,
[
'!a.py'
])
assert
sorted
(
paths
)
==
sorted
(
set
(
paths
))
def
test_wildcard_exclude
(
self
):
assert
self
.
exclude
([
'*'
])
==
set
([
'Dockerfile'
,
'.dockerignore'
])
def
test_exclude_dockerfile_dockerignore
(
self
):
"""
Even if the .dockerignore file explicitly says to exclude
Dockerfile and/or .dockerignore, don't exclude them from
the actual tar file.
"""
assert
self
.
exclude
([
'Dockerfile'
,
'.dockerignore'
])
==
convert_paths
(
self
.
all_paths
)
def
test_exclude_custom_dockerfile
(
self
):
"""
If we're using a custom Dockerfile, make sure that's not
excluded.
"""
assert
self
.
exclude
([
'*'
],
dockerfile
=
'Dockerfile.alt'
)
==
set
(
[
'Dockerfile.alt'
,
'.dockerignore'
]
)
assert
self
.
exclude
(
[
'*'
],
dockerfile
=
'foo/Dockerfile3'
)
==
convert_paths
(
set
([
'foo/Dockerfile3'
,
'.dockerignore'
]))
# https://github.com/docker/docker-py/issues/1956
assert
self
.
exclude
(
[
'*'
],
dockerfile
=
'./foo/Dockerfile3'
)
==
convert_paths
(
set
([
'foo/Dockerfile3'
,
'.dockerignore'
]))
def
test_exclude_dockerfile_child
(
self
):
includes
=
self
.
exclude
([
'foo/'
],
dockerfile
=
'foo/Dockerfile3'
)
assert
convert_path
(
'foo/Dockerfile3'
)
in
includes
assert
convert_path
(
'foo/a.py'
)
not
in
includes
def
test_single_filename
(
self
):
assert
self
.
exclude
([
'a.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'a.py'
])
)
def
test_single_filename_leading_dot_slash
(
self
):
assert
self
.
exclude
([
'./a.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'a.py'
])
)
# As odd as it sounds, a filename pattern with a trailing slash on the
# end *will* result in that file being excluded.
def
test_single_filename_trailing_slash
(
self
):
assert
self
.
exclude
([
'a.py/'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'a.py'
])
)
def
test_wildcard_filename_start
(
self
):
assert
self
.
exclude
([
'*.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'a.py'
,
'b.py'
,
'cde.py'
])
)
def
test_wildcard_with_exception
(
self
):
assert
self
.
exclude
([
'*.py'
,
'!b.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'a.py'
,
'cde.py'
])
)
def
test_wildcard_with_wildcard_exception
(
self
):
assert
self
.
exclude
([
'*.*'
,
'!*.go'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'a.py'
,
'b.py'
,
'cde.py'
,
'Dockerfile.alt'
,
])
)
def
test_wildcard_filename_end
(
self
):
assert
self
.
exclude
([
'a.*'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'a.py'
,
'a.go'
])
)
def
test_question_mark
(
self
):
assert
self
.
exclude
([
'?.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'a.py'
,
'b.py'
])
)
def
test_single_subdir_single_filename
(
self
):
assert
self
.
exclude
([
'foo/a.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/a.py'
])
)
def
test_single_subdir_single_filename_leading_slash
(
self
):
assert
self
.
exclude
([
'/foo/a.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/a.py'
])
)
def
test_exclude_include_absolute_path
(
self
):
base
=
make_tree
([],
[
'a.py'
,
'b.py'
])
assert
exclude_paths
(
base
,
[
'/*'
,
'!/*.py'
]
)
==
set
([
'a.py'
,
'b.py'
])
def
test_single_subdir_with_path_traversal
(
self
):
assert
self
.
exclude
([
'foo/whoops/../a.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/a.py'
])
)
def
test_single_subdir_wildcard_filename
(
self
):
assert
self
.
exclude
([
'foo/*.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/a.py'
,
'foo/b.py'
])
)
def
test_wildcard_subdir_single_filename
(
self
):
assert
self
.
exclude
([
'*/a.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/a.py'
,
'bar/a.py'
])
)
def
test_wildcard_subdir_wildcard_filename
(
self
):
assert
self
.
exclude
([
'*/*.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/a.py'
,
'foo/b.py'
,
'bar/a.py'
])
)
def
test_directory
(
self
):
assert
self
.
exclude
([
'foo'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo'
,
'foo/a.py'
,
'foo/b.py'
,
'foo/bar'
,
'foo/bar/a.py'
,
'foo/Dockerfile3'
])
)
def
test_directory_with_trailing_slash
(
self
):
assert
self
.
exclude
([
'foo'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo'
,
'foo/a.py'
,
'foo/b.py'
,
'foo/bar'
,
'foo/bar/a.py'
,
'foo/Dockerfile3'
])
)
def
test_directory_with_single_exception
(
self
):
assert
self
.
exclude
([
'foo'
,
'!foo/bar/a.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/a.py'
,
'foo/b.py'
,
'foo'
,
'foo/bar'
,
'foo/Dockerfile3'
])
)
def
test_directory_with_subdir_exception
(
self
):
assert
self
.
exclude
([
'foo'
,
'!foo/bar'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/a.py'
,
'foo/b.py'
,
'foo'
,
'foo/Dockerfile3'
])
)
@pytest.mark.skipif
(
not
IS_WINDOWS_PLATFORM
,
reason
=
'Backslash patterns only on Windows'
)
def
test_directory_with_subdir_exception_win32_pathsep
(
self
):
assert
self
.
exclude
([
'foo'
,
'!foo
\\
bar'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/a.py'
,
'foo/b.py'
,
'foo'
,
'foo/Dockerfile3'
])
)
def
test_directory_with_wildcard_exception
(
self
):
assert
self
.
exclude
([
'foo'
,
'!foo/*.py'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/bar'
,
'foo/bar/a.py'
,
'foo'
,
'foo/Dockerfile3'
])
)
def
test_subdirectory
(
self
):
assert
self
.
exclude
([
'foo/bar'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/bar'
,
'foo/bar/a.py'
])
)
@pytest.mark.skipif
(
not
IS_WINDOWS_PLATFORM
,
reason
=
'Backslash patterns only on Windows'
)
def
test_subdirectory_win32_pathsep
(
self
):
assert
self
.
exclude
([
'foo
\\
bar'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/bar'
,
'foo/bar/a.py'
])
)
def
test_double_wildcard
(
self
):
assert
self
.
exclude
([
'**/a.py'
])
==
convert_paths
(
self
.
all_paths
-
set
(
[
'a.py'
,
'foo/a.py'
,
'foo/bar/a.py'
,
'bar/a.py'
]
)
)
assert
self
.
exclude
([
'foo/**/bar'
])
==
convert_paths
(
self
.
all_paths
-
set
([
'foo/bar'
,
'foo/bar/a.py'
])
)
def
test_single_and_double_wildcard
(
self
):
assert
self
.
exclude
([
'**/target/*/*'
])
==
convert_paths
(
self
.
all_paths
-
set
(
[
'target/subdir/file.txt'
,
'subdir/target/subdir/file.txt'
,
'subdir/subdir2/target/subdir/file.txt'
]
)
)
def
test_trailing_double_wildcard
(
self
):
assert
self
.
exclude
([
'subdir/**'
])
==
convert_paths
(
self
.
all_paths
-
set
(
[
'subdir/file.txt'
,
'subdir/target/file.txt'
,
'subdir/target/subdir/file.txt'
,
'subdir/subdir2/file.txt'
,
'subdir/subdir2/target/file.txt'
,
'subdir/subdir2/target/subdir/file.txt'
,
'subdir/target'
,
'subdir/target/subdir'
,
'subdir/subdir2'
,
'subdir/subdir2/target'
,
'subdir/subdir2/target/subdir'
]
)
)
def
test_double_wildcard_with_exception
(
self
):
assert
self
.
exclude
([
'**'
,
'!bar'
,
'!foo/bar'
])
==
convert_paths
(
set
([
'foo/bar'
,
'foo/bar/a.py'
,
'bar'
,
'bar/a.py'
,
'Dockerfile'
,
'.dockerignore'
,
])
)
def
test_include_wildcard
(
self
):
# This may be surprising but it matches the CLI's behavior
# (tested with 18.05.0-ce on linux)
base
=
make_tree
([
'a'
],
[
'a/b.py'
])
assert
exclude_paths
(
base
,
[
'*'
,
'!*/b.py'
]
)
==
set
()
def
test_last_line_precedence
(
self
):
base
=
make_tree
(
[],
[
'garbage.md'
,
'thrash.md'
,
'README.md'
,
'README-bis.md'
,
'README-secret.md'
])
assert
exclude_paths
(
base
,
[
'*.md'
,
'!README*.md'
,
'README-secret.md'
]
)
==
set
([
'README.md'
,
'README-bis.md'
])
def
test_parent_directory
(
self
):
base
=
make_tree
(
[],
[
'a.py'
,
'b.py'
,
'c.py'
])
# Dockerignore reference stipulates that absolute paths are
# equivalent to relative paths, hence /../foo should be
# equivalent to ../foo. It also stipulates that paths are run
# through Go's filepath.Clean, which explicitely "replace
# "/.." by "/" at the beginning of a path".
assert
exclude_paths
(
base
,
[
'../a.py'
,
'/../b.py'
]
)
==
set
([
'c.py'
])
class
TarTest
(
unittest
.
TestCase
):
def
test_tar_with_excludes
(
self
):
dirs
=
[
'foo'
,
'foo/bar'
,
'bar'
,
]
files
=
[
'Dockerfile'
,
'Dockerfile.alt'
,
'.dockerignore'
,
'a.py'
,
'a.go'
,
'b.py'
,
'cde.py'
,
'foo/a.py'
,
'foo/b.py'
,
'foo/bar/a.py'
,
'bar/a.py'
,
]
exclude
=
[
'*.py'
,
'!b.py'
,
'!a.go'
,
'foo'
,
'Dockerfile*'
,
'.dockerignore'
,
]
expected_names
=
set
([
'Dockerfile'
,
'.dockerignore'
,
'a.go'
,
'b.py'
,
'bar'
,
'bar/a.py'
,
])
base
=
make_tree
(
dirs
,
files
)
self
.
addCleanup
(
shutil
.
rmtree
,
base
)
with
tar
(
base
,
exclude
=
exclude
)
as
archive
:
tar_data
=
tarfile
.
open
(
fileobj
=
archive
)
assert
sorted
(
tar_data
.
getnames
())
==
sorted
(
expected_names
)
def
test_tar_with_empty_directory
(
self
):
base
=
tempfile
.
mkdtemp
()
self
.
addCleanup
(
shutil
.
rmtree
,
base
)
for
d
in
[
'foo'
,
'bar'
]:
os
.
makedirs
(
os
.
path
.
join
(
base
,
d
))
with
tar
(
base
)
as
archive
:
tar_data
=
tarfile
.
open
(
fileobj
=
archive
)
assert
sorted
(
tar_data
.
getnames
())
==
[
'bar'
,
'foo'
]
@pytest.mark.skipif
(
IS_WINDOWS_PLATFORM
or
os
.
geteuid
()
==
0
,
reason
=
'root user always has access ; no chmod on Windows'
)
def
test_tar_with_inaccessible_file
(
self
):
base
=
tempfile
.
mkdtemp
()
full_path
=
os
.
path
.
join
(
base
,
'foo'
)
self
.
addCleanup
(
shutil
.
rmtree
,
base
)
with
open
(
full_path
,
'w'
)
as
f
:
f
.
write
(
'content'
)
os
.
chmod
(
full_path
,
0
o222
)
with
pytest
.
raises
(
IOError
)
as
ei
:
tar
(
base
)
assert
'Can not read file in context: {}'
.
format
(
full_path
)
in
(
ei
.
exconly
()
)
@pytest.mark.skipif
(
IS_WINDOWS_PLATFORM
,
reason
=
'No symlinks on Windows'
)
def
test_tar_with_file_symlinks
(
self
):
base
=
tempfile
.
mkdtemp
()
self
.
addCleanup
(
shutil
.
rmtree
,
base
)
with
open
(
os
.
path
.
join
(
base
,
'foo'
),
'w'
)
as
f
:
f
.
write
(
"content"
)
os
.
makedirs
(
os
.
path
.
join
(
base
,
'bar'
))
os
.
symlink
(
'../foo'
,
os
.
path
.
join
(
base
,
'bar/foo'
))
with
tar
(
base
)
as
archive
:
tar_data
=
tarfile
.
open
(
fileobj
=
archive
)
assert
sorted
(
tar_data
.
getnames
())
==
[
'bar'
,
'bar/foo'
,
'foo'
]
@pytest.mark.skipif
(
IS_WINDOWS_PLATFORM
,
reason
=
'No symlinks on Windows'
)
def
test_tar_with_directory_symlinks
(
self
):
base
=
tempfile
.
mkdtemp
()
self
.
addCleanup
(
shutil
.
rmtree
,
base
)
for
d
in
[
'foo'
,
'bar'
]:
os
.
makedirs
(
os
.
path
.
join
(
base
,
d
))
os
.
symlink
(
'../foo'
,
os
.
path
.
join
(
base
,
'bar/foo'
))
with
tar
(
base
)
as
archive
:
tar_data
=
tarfile
.
open
(
fileobj
=
archive
)
assert
sorted
(
tar_data
.
getnames
())
==
[
'bar'
,
'bar/foo'
,
'foo'
]
@pytest.mark.skipif
(
IS_WINDOWS_PLATFORM
,
reason
=
'No symlinks on Windows'
)
def
test_tar_with_broken_symlinks
(
self
):
base
=
tempfile
.
mkdtemp
()
self
.
addCleanup
(
shutil
.
rmtree
,
base
)
for
d
in
[
'foo'
,
'bar'
]:
os
.
makedirs
(
os
.
path
.
join
(
base
,
d
))
os
.
symlink
(
'../baz'
,
os
.
path
.
join
(
base
,
'bar/foo'
))
with
tar
(
base
)
as
archive
:
tar_data
=
tarfile
.
open
(
fileobj
=
archive
)
assert
sorted
(
tar_data
.
getnames
())
==
[
'bar'
,
'bar/foo'
,
'foo'
]
@pytest.mark.skipif
(
IS_WINDOWS_PLATFORM
,
reason
=
'No UNIX sockets on Win32'
)
def
test_tar_socket_file
(
self
):
base
=
tempfile
.
mkdtemp
()
self
.
addCleanup
(
shutil
.
rmtree
,
base
)
for
d
in
[
'foo'
,
'bar'
]:
os
.
makedirs
(
os
.
path
.
join
(
base
,
d
))
sock
=
socket
.
socket
(
socket
.
AF_UNIX
)
self
.
addCleanup
(
sock
.
close
)
sock
.
bind
(
os
.
path
.
join
(
base
,
'test.sock'
))
with
tar
(
base
)
as
archive
:
tar_data
=
tarfile
.
open
(
fileobj
=
archive
)
assert
sorted
(
tar_data
.
getnames
())
==
[
'bar'
,
'foo'
]
def
tar_test_negative_mtime_bug
(
self
):
base
=
tempfile
.
mkdtemp
()
filename
=
os
.
path
.
join
(
base
,
'th.txt'
)
self
.
addCleanup
(
shutil
.
rmtree
,
base
)
with
open
(
filename
,
'w'
)
as
f
:
f
.
write
(
'Invisible Full Moon'
)
os
.
utime
(
filename
,
(
12345
,
-
3600.0
))
with
tar
(
base
)
as
archive
:
tar_data
=
tarfile
.
open
(
fileobj
=
archive
)
assert
tar_data
.
getnames
()
==
[
'th.txt'
]
assert
tar_data
.
getmember
(
'th.txt'
)
.
mtime
==
-
3600
@pytest.mark.skipif
(
IS_WINDOWS_PLATFORM
,
reason
=
'No symlinks on Windows'
)
def
test_tar_directory_link
(
self
):
dirs
=
[
'a'
,
'b'
,
'a/c'
]
files
=
[
'a/hello.py'
,
'b/utils.py'
,
'a/c/descend.py'
]
base
=
make_tree
(
dirs
,
files
)
self
.
addCleanup
(
shutil
.
rmtree
,
base
)
os
.
symlink
(
os
.
path
.
join
(
base
,
'b'
),
os
.
path
.
join
(
base
,
'a/c/b'
))
with
tar
(
base
)
as
archive
:
tar_data
=
tarfile
.
open
(
fileobj
=
archive
)
names
=
tar_data
.
getnames
()
for
member
in
dirs
+
files
:
assert
member
in
names
assert
'a/c/b'
in
names
assert
'a/c/b/utils.py'
not
in
names
class
FormatEnvironmentTest
(
unittest
.
TestCase
):
def
test_format_env_binary_unicode_value
(
self
):
env_dict
=
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment