Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 6 additions & 15 deletions dvc/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,22 +102,13 @@ def _reflink_linux(src, dst):

FICLONE = 0x40049409

s = open(src, "r")
d = open(dst, "w+")

try:
ret = fcntl.ioctl(d.fileno(), FICLONE, s.fileno())
except IOError:
s.close()
d.close()
os.unlink(dst)
raise

s.close()
d.close()

if ret != 0:
os.unlink(dst)
ret = 255
with open(src, "r") as s, open(dst, "w+") as d:
ret = fcntl.ioctl(d.fileno(), FICLONE, s.fileno())
finally:
if ret != 0:
os.unlink(dst)

return ret

Expand Down
28 changes: 11 additions & 17 deletions dvc/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,28 +119,22 @@ def copyfile(src, dest, no_progress_bar=False, name=None):
name = name if name else os.path.basename(dest)
total = os.stat(src).st_size

fsrc = open(src, "rb")

if os.path.isdir(dest):
fdest = open(os.path.join(dest, os.path.basename(src)), "wb+")
else:
fdest = open(dest, "wb+")

while True:
buf = fsrc.read(LOCAL_CHUNK_SIZE)
if not buf:
break
fdest.write(buf)
copied += len(buf)
if not no_progress_bar:
progress.update_target(name, copied, total)
dest = os.path.join(dest, os.path.basename(src))

with open(src, "rb") as fsrc, open(dest, "wb+") as fdest:
while True:
buf = fsrc.read(LOCAL_CHUNK_SIZE)
if not buf:
break
fdest.write(buf)
copied += len(buf)
if not no_progress_bar:
progress.update_target(name, copied, total)

if not no_progress_bar:
progress.finish_target(name)

fsrc.close()
fdest.close()


def move(src, dst):
dst = os.path.abspath(dst)
Expand Down
28 changes: 27 additions & 1 deletion tests/basic_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import uuid
import tempfile
import logging
import warnings

from git import Repo
from git.exc import GitCommandNotFound
Expand Down Expand Up @@ -60,7 +61,8 @@ def __init__(self, root_dir=None):
self._root_dir = os.path.realpath(root_dir)

def _pushd(self, d):
self._saved_dir = os.path.realpath(os.curdir)
if not hasattr(self, "_saved_dir"):
self._saved_dir = os.path.realpath(os.curdir)
os.chdir(d)

def _popd(self):
Expand Down Expand Up @@ -98,6 +100,21 @@ def setUp(self):

def tearDown(self):
self._popd()
try:
shutil.rmtree(self._root_dir)
except OSError as exc:
# We ignore this under Windows with a warning because it happened
# to be really hard to trace all not properly closed files.
#
# Best guess so far is that gitpython is the culprit:
# it opens files and uses __del__ to close them, which can happen
# late in current pythons. TestGitFixture and TestDvcFixture try
# to close that and it works on most of the tests, but not all.
# Repos and thus git repos are created all over the dvc ;)
if os.name == "nt" and exc.winerror == 32:
warnings.warn("Failed to remove test dir: " + str(exc))
else:
raise


class TestGitFixture(TestDirFixture):
Expand All @@ -122,6 +139,9 @@ def setUp(self):
self.git.index.add([self.CODE])
self.git.index.commit("add code")

def tearDown(self):
self.git.close()


class TestGitSubmoduleFixture(TestGitFixture):
def __init__(self, root_dir=None):
Expand All @@ -145,6 +165,9 @@ def setUp(self):
self.dvc.scm.commit("init dvc")
logger.setLevel("DEBUG")

def tearDown(self):
self.dvc.scm.git.close()


class TestDvcGitInitializedFixture(TestDvcFixture):
def __init__(self, root_dir=None):
Expand Down Expand Up @@ -196,6 +219,9 @@ class MockConfig:
)
self.git.index.commit("Hello world commit")

# Return to the dir we started to not confuse parent fixture
os.chdir(self._saved_dir)


# NOTE: Inheritance order in the classes below is important.

Expand Down
18 changes: 12 additions & 6 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,19 @@ def git(repo_dir):
continue
break

git.index.add([repo_dir.CODE])
git.index.commit("add code")
return git
try:
git.index.add([repo_dir.CODE])
git.index.commit("add code")
yield git
finally:
git.close()


@pytest.fixture
def dvc(repo_dir, git):
dvc = DvcRepo.init(repo_dir._root_dir)
dvc.scm.commit("init dvc")
return dvc
try:
dvc = DvcRepo.init(repo_dir._root_dir)
dvc.scm.commit("init dvc")
yield dvc
finally:
dvc.scm.git.close()
5 changes: 2 additions & 3 deletions tests/func/test_checkout.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,8 @@ def commit_data_file(self, fname, content="random text"):
self.dvc.scm.commit("adding " + fname)

def read_ignored(self):
return list(
map(lambda s: s.strip("\n"), open(self.GIT_IGNORE).readlines())
)
with open(self.GIT_IGNORE) as f:
return [s.strip("\n") for s in f.readlines()]

def outs_info(self, stage):
FileInfo = collections.namedtuple("FileInfo", "path inode")
Expand Down
3 changes: 2 additions & 1 deletion tests/func/test_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ def test(self):
ret = main(["import", tmpfile])
self.assertEqual(ret, 0)
self.assertTrue(os.path.exists(filename))
self.assertEqual(open(filename).read(), "content")
with open(filename) as fd:
self.assertEqual(fd.read(), "content")


class TestFailedImportMessage(TestDvc):
Expand Down
24 changes: 16 additions & 8 deletions tests/func/test_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,8 @@ def test(self):
)
self.assertEqual(ret, 0)
self.assertFalse(os.access(self.FOO, os.W_OK))
self.assertEqual(open(self.FOO, "r").read(), "foo")
with open(self.FOO, "r") as fd:
self.assertEqual(fd.read(), "foo")

ret = main(
[
Expand All @@ -398,7 +399,8 @@ def test(self):
)
self.assertEqual(ret, 0)
self.assertFalse(os.access(self.FOO, os.W_OK))
self.assertEqual(open(self.FOO, "r").read(), "foo")
with open(self.FOO, "r") as fd:
self.assertEqual(fd.read(), "foo")


class TestRunUnprotectOutsSymlink(TestDvc):
Expand Down Expand Up @@ -431,7 +433,8 @@ def test(self):
self.assertEqual(ret, 0)
self.assertFalse(os.access(self.FOO, os.W_OK))
self.assertTrue(System.is_symlink(self.FOO))
self.assertEqual(open(self.FOO, "r").read(), "foo")
with open(self.FOO, "r") as fd:
self.assertEqual(fd.read(), "foo")

ret = main(
[
Expand All @@ -450,7 +453,8 @@ def test(self):
self.assertEqual(ret, 0)
self.assertFalse(os.access(self.FOO, os.W_OK))
self.assertTrue(System.is_symlink(self.FOO))
self.assertEqual(open(self.FOO, "r").read(), "foo")
with open(self.FOO, "r") as fd:
self.assertEqual(fd.read(), "foo")


class TestRunUnprotectOutsHardlink(TestDvc):
Expand Down Expand Up @@ -483,7 +487,8 @@ def test(self):
self.assertEqual(ret, 0)
self.assertFalse(os.access(self.FOO, os.W_OK))
self.assertTrue(System.is_hardlink(self.FOO))
self.assertEqual(open(self.FOO, "r").read(), "foo")
with open(self.FOO, "r") as fd:
self.assertEqual(fd.read(), "foo")

ret = main(
[
Expand All @@ -502,7 +507,8 @@ def test(self):
self.assertEqual(ret, 0)
self.assertFalse(os.access(self.FOO, os.W_OK))
self.assertTrue(System.is_hardlink(self.FOO))
self.assertEqual(open(self.FOO, "r").read(), "foo")
with open(self.FOO, "r") as fd:
self.assertEqual(fd.read(), "foo")


class TestCmdRunOverwrite(TestDvc):
Expand Down Expand Up @@ -602,12 +608,14 @@ class TestCmdRunCliMetrics(TestDvc):
def test_cached(self):
ret = main(["run", "-m", "metrics.txt", "echo test > metrics.txt"])
self.assertEqual(ret, 0)
self.assertEqual(open("metrics.txt", "r").read().rstrip(), "test")
with open("metrics.txt", "r") as fd:
self.assertEqual(fd.read().rstrip(), "test")

def test_not_cached(self):
ret = main(["run", "-M", "metrics.txt", "echo test > metrics.txt"])
self.assertEqual(ret, 0)
self.assertEqual(open("metrics.txt", "r").read().rstrip(), "test")
with open("metrics.txt", "r") as fd:
self.assertEqual(fd.read().rstrip(), "test")


class TestCmdRunWorkingDirectory(TestDvc):
Expand Down
19 changes: 8 additions & 11 deletions tests/func/test_system.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
import os
import pytest

from dvc.system import System
from tests.basic_env import TestDir


class TestSystem(TestDir):
def test_getdirinfo(self):
if os.name != "nt":
return

# simulate someone holding an exclussive access
locked = "locked"
fd = os.open(locked, os.O_WRONLY | os.O_CREAT | os.O_EXCL)

@pytest.mark.skipif(os.name != "nt", reason="Windows specific")
def test_getdirinfo(tmp_path):
# simulate someone holding an exclussive access
locked = str(tmp_path / "locked")
fd = os.open(locked, os.O_WRONLY | os.O_CREAT | os.O_EXCL)
try:
# should not raise WinError
System.getdirinfo(locked)

finally:
os.close(fd)
16 changes: 8 additions & 8 deletions tests/func/test_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ def setUp(self):
self.tree = WorkingTree()

def test_open(self):
self.assertEqual(self.tree.open(self.FOO).read(), self.FOO_CONTENTS)
self.assertEqual(
self.tree.open(self.UNICODE).read(), self.UNICODE_CONTENTS
)
with self.tree.open(self.FOO) as fd:
self.assertEqual(fd.read(), self.FOO_CONTENTS)
with self.tree.open(self.UNICODE) as fd:
self.assertEqual(fd.read(), self.UNICODE_CONTENTS)

def test_exists(self):
self.assertTrue(self.tree.exists(self.FOO))
Expand All @@ -47,10 +47,10 @@ def setUp(self):
def test_open(self):
self.scm.add([self.FOO, self.UNICODE, self.DATA_DIR])
self.scm.commit("add")
self.assertEqual(self.tree.open(self.FOO).read(), self.FOO_CONTENTS)
self.assertEqual(
self.tree.open(self.UNICODE).read(), self.UNICODE_CONTENTS
)
with self.tree.open(self.FOO) as fd:
self.assertEqual(fd.read(), self.FOO_CONTENTS)
with self.tree.open(self.UNICODE) as fd:
self.assertEqual(fd.read(), self.UNICODE_CONTENTS)
with self.assertRaises(IOError):
self.tree.open("not-existing-file")
with self.assertRaises(IOError):
Expand Down