diff --git a/docker/utils/utils.py b/docker/utils/utils.py index fb05a1ea..cab44a41 100644 --- a/docker/utils/utils.py +++ b/docker/utils/utils.py @@ -72,6 +72,9 @@ def tar(path, exclude=None): for name in fnames: arcname = os.path.join(relpath, name) t.add(os.path.join(path, arcname), arcname=arcname) + for name in dirnames: + arcname = os.path.join(relpath, name) + t.add(os.path.join(path, arcname), arcname=arcname, recursive=False) t.close() f.seek(0) return f diff --git a/tests/integration_test.py b/tests/integration_test.py index d4900b7f..6d77b1d8 100644 --- a/tests/integration_test.py +++ b/tests/integration_test.py @@ -882,6 +882,43 @@ class TestBuildWithDockerignore(Cleanup, BaseTestCase): self.assertFalse('node_modules' in logs) self.assertTrue('not-ignored' in logs) +class TestBuildWithSymlinks(Cleanup, BaseTestCase): + def runTest(self): + if self.client._version < 1.8: + return + + base_dir = tempfile.mkdtemp() + self.addCleanup(shutil.rmtree, base_dir) + + with open(os.path.join(base_dir, 'Dockerfile'), 'w') as f: + f.write("\n".join([ + 'FROM busybox', + 'MAINTAINER docker-py', + 'ADD . /test', + 'RUN ls -A /test', + ])) + + with open(os.path.join(base_dir, '.dockerignore'), 'w') as f: + f.write("\n".join([ + 'node_modules', + '', # empty line + ])) + + with open(os.path.join(base_dir, 'not-ignored'), 'w') as f: + f.write("this file should not be ignored") + + subdir = os.path.join(base_dir, 'node_modules', 'grunt-cli') + os.makedirs(subdir) + with open(os.path.join(subdir, 'grunt'), 'w') as f: + f.write("grunt") + + stream = self.client.build(path=base_dir, stream=True) + logs = '' + for chunk in stream: + logs += chunk + self.assertFalse('node_modules' in logs) + self.assertTrue('not-ignoredx' in logs) + ####################### # PY SPECIFIC TESTS # ####################### diff --git a/tests/test.py b/tests/test.py index 984e350e..e02c487f 100644 --- a/tests/test.py +++ b/tests/test.py @@ -1615,16 +1615,47 @@ class DockerClientTest(Cleanup, unittest.TestCase): f.write("content") for exclude, names in ( - (['*.py'], ['bar/a.txt', 'bar/other.png', - 'test/foo/a.txt', 'test/foo/other.png']), - (['*.png', 'bar'], ['test/foo/a.txt', 'test/foo/b.py']), - (['test/foo', 'a.txt'], ['bar/a.txt', 'bar/b.py', - 'bar/other.png']), + (['*.py'], ['bar', 'bar/a.txt', 'bar/other.png', + 'test', 'test/foo', 'test/foo/a.txt', + 'test/foo/other.png']), + (['*.png', 'bar'], ['test', 'test/foo', 'test/foo/a.txt', + 'test/foo/b.py']), + (['test/foo', 'a.txt'], ['bar', 'bar/a.txt', 'bar/b.py', + 'bar/other.png', 'test']), ): archive = docker.utils.tar(base, exclude=exclude) tar = tarfile.open(fileobj=archive) self.assertEqual(sorted(tar.getnames()), 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)) + archive = docker.utils.tar(base) + tar = tarfile.open(fileobj=archive) + self.assertEqual(sorted(tar.getnames()), ['bar', 'foo']) + + 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')) + archive = docker.utils.tar(base) + tar = tarfile.open(fileobj=archive) + self.assertEqual(sorted(tar.getnames()), ['bar', 'bar/foo', 'foo']) + + 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')) + archive = docker.utils.tar(base) + tar = tarfile.open(fileobj=archive) + self.assertEqual(sorted(tar.getnames()), ['bar', 'bar/foo', 'foo']) if __name__ == '__main__': unittest.main()