Skip to content

Commit 6c8721a

Browse files
committed
Win32 compatability adjustments. One performance test fails during shutdown as python fails to delete a stream in time it seems, so the file cannot be deleted as it is still opened by someone. This is madness, raising the question how badly python truly fails to call the destructors of objects in order to allow them to release their resources
1 parent b76bac2 commit 6c8721a

File tree

5 files changed

+33
-5
lines changed

5 files changed

+33
-5
lines changed

db/loose.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
exists,
3131
chmod,
3232
isdir,
33+
isfile,
34+
remove,
3335
mkdir,
3436
rename,
3537
dirname,
@@ -60,6 +62,12 @@ class LooseObjectDB(FileDBBase, ObjectDBR, ObjectDBW):
6062
# chunks in which data will be copied between streams
6163
stream_chunk_size = chunk_size
6264

65+
# On windows we need to keep it writable, otherwise it cannot be removed
66+
# either
67+
new_objects_mode = 0444
68+
if os.name == 'nt':
69+
new_objects_mode = 0644
70+
6371

6472
def __init__(self, root_path):
6573
super(LooseObjectDB, self).__init__(root_path)
@@ -199,11 +207,15 @@ def store(self, istream):
199207
if not isdir(obj_dir):
200208
mkdir(obj_dir)
201209
# END handle destination directory
210+
# rename onto existing doesn't work on windows
211+
if os.name == 'nt' and isfile(obj_path):
212+
remove(obj_path)
213+
# END handle win322
202214
rename(tmp_path, obj_path)
203215

204216
# make sure its readable for all ! It started out as rw-- tmp file
205-
# but needs to be rrr
206-
chmod(obj_path, 0444)
217+
# but needs to be rwrr
218+
chmod(obj_path, self.new_objects_mode)
207219
# END handle dry_run
208220

209221
istream.binsha = hex_to_bin(hexsha)

test/lib.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import tempfile
2020
import shutil
2121
import os
22+
import gc
2223

2324

2425
#{ Bases
@@ -44,6 +45,11 @@ def wrapper(self):
4445
print >> sys.stderr, "Test %s.%s failed, output is at %r" % (type(self).__name__, func.__name__, path)
4546
raise
4647
finally:
48+
# Need to collect here to be sure all handles have been closed. It appears
49+
# a windows-only issue. In fact things should be deleted, as well as
50+
# memory maps closed, once objects go out of scope. For some reason
51+
# though this is not the case here unless we collect explicitly.
52+
gc.collect()
4753
shutil.rmtree(path)
4854
# END handle exception
4955
# END wrapper

test/test_example.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ def test_base(self):
2121
assert len(ostream.read()) == ostream.size
2222
assert ldb.has_object(oinfo.binsha)
2323
# END for each sha in database
24+
# assure we close all files
25+
del(ostream)
26+
del(oinfo)
2427

2528
data = "my data"
2629
istream = IStream("blob", len(data), StringIO(data))

test/test_stream.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
str_blob_type
2020
)
2121

22+
import time
2223
import tempfile
2324
import os
2425

@@ -125,12 +126,14 @@ def test_compressed_writer(self):
125126
# for now, just a single write, code doesn't care about chunking
126127
assert len(data) == ostream.write(data)
127128
ostream.close()
129+
128130
# its closed already
129131
self.failUnlessRaises(OSError, os.close, fd)
130132

131133
# read everything back, compare to data we zip
132-
fd = os.open(path, os.O_RDONLY)
134+
fd = os.open(path, os.O_RDONLY|getattr(os, 'O_BINARY', 0))
133135
written_data = os.read(fd, os.path.getsize(path))
136+
assert len(written_data) == os.path.getsize(path)
134137
os.close(fd)
135138
assert written_data == zlib.compress(data, 1) # best speed
136139

util.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,14 @@ def unpack_from(fmt, data, offset=0):
5858
isdir = os.path.isdir
5959
isfile = os.path.isfile
6060
rename = os.rename
61+
remove = os.remove
6162
dirname = os.path.dirname
6263
basename = os.path.basename
6364
join = os.path.join
6465
read = os.read
6566
write = os.write
6667
close = os.close
68+
fsync = os.fsync
6769

6870
# constants
6971
NULL_HEX_SHA = "0"*40
@@ -128,7 +130,7 @@ def file_contents_ro_filepath(filepath, stream=False, allow_mmap=True, flags=0):
128130
:note: for now we don't try to use O_NOATIME directly as the right value needs to be
129131
shared per database in fact. It only makes a real difference for loose object
130132
databases anyway, and they use it with the help of the ``flags`` parameter"""
131-
fd = os.open(filepath, os.O_RDONLY|flags)
133+
fd = os.open(filepath, os.O_RDONLY|getattr(os, 'O_BINARY', 0)|flags)
132134
try:
133135
return file_contents_ro(fd, stream, allow_mmap)
134136
finally:
@@ -300,7 +302,9 @@ def _end_writing(self, successful=True):
300302
os.rename(lockfile, self._filepath)
301303

302304
# assure others can at least read the file - the tmpfile left it at rw--
303-
chmod(self._filepath, 0444)
305+
# We may also write that file, on windows that boils down to a remove-
306+
# protection as well
307+
chmod(self._filepath, 0644)
304308
else:
305309
# just delete the file so far, we failed
306310
os.remove(lockfile)

0 commit comments

Comments
 (0)