Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit1d23075

Browse files
committed
Moved LockedFD and its test into the gitdb project
1 parent06590ae commit1d23075

File tree

3 files changed

+5
-214
lines changed

3 files changed

+5
-214
lines changed

‎lib/git/ext/gitdb

Submodule gitdb updated from 133988a to f50643f

‎lib/git/utils.py

Lines changed: 3 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111

1212
fromgitdb.utilimport (
1313
stream_copy,
14-
make_sha
14+
make_sha,
15+
FDStreamWrapper,
16+
LockedFD
1517
)
1618

1719

@@ -271,146 +273,6 @@ def _obtain_lock(self):
271273
break
272274
# END endless loop
273275

274-
275-
classFDStreamWrapper(object):
276-
"""A simple wrapper providing the most basic functions on a file descriptor
277-
with the fileobject interface. Cannot use os.fdopen as the resulting stream
278-
takes ownership"""
279-
__slots__= ("_fd",'_pos')
280-
def__init__(self,fd):
281-
self._fd=fd
282-
self._pos=0
283-
284-
defwrite(self,data):
285-
self._pos+=len(data)
286-
os.write(self._fd,data)
287-
288-
defread(self,count=0):
289-
ifcount==0:
290-
count=os.path.getsize(self._filepath)
291-
# END handle read everything
292-
293-
bytes=os.read(self._fd,count)
294-
self._pos+=len(bytes)
295-
returnbytes
296-
297-
deffileno(self):
298-
returnself._fd
299-
300-
deftell(self):
301-
returnself._pos
302-
303-
304-
classLockedFD(LockFile):
305-
"""This class facilitates a safe read and write operation to a file on disk.
306-
If we write to 'file', we obtain a lock file at 'file.lock' and write to
307-
that instead. If we succeed, the lock file will be renamed to overwrite
308-
the original file.
309-
310-
When reading, we obtain a lock file, but to prevent other writers from
311-
succeeding while we are reading the file.
312-
313-
This type handles error correctly in that it will assure a consistent state
314-
on destruction.
315-
316-
:note: with this setup, parallel reading is not possible"""
317-
__slots__= ("_filepath",'_fd','_write')
318-
319-
def__init__(self,filepath):
320-
"""Initialize an instance with the givne filepath"""
321-
self._filepath=filepath
322-
self._fd=None
323-
self._write=None# if True, we write a file
324-
325-
def__del__(self):
326-
# will do nothing if the file descriptor is already closed
327-
ifself._fdisnotNone:
328-
self.rollback()
329-
330-
def_lockfilepath(self):
331-
return"%s.lock"%self._filepath
332-
333-
defopen(self,write=False,stream=False):
334-
"""Open the file descriptor for reading or writing, both in binary mode.
335-
:param write: if True, the file descriptor will be opened for writing. Other
336-
wise it will be opened read-only.
337-
:param stream: if True, the file descriptor will be wrapped into a simple stream
338-
object which supports only reading or writing
339-
:return: fd to read from or write to. It is still maintained by this instance
340-
and must not be closed directly
341-
:raise IOError: if the lock could not be retrieved
342-
:raise OSError: If the actual file could not be opened for reading
343-
:note: must only be called once"""
344-
ifself._writeisnotNone:
345-
raiseAssertionError("Called %s multiple times"%self.open)
346-
347-
self._write=write
348-
349-
# try to open the lock file
350-
binary=getattr(os,'O_BINARY',0)
351-
lockmode=os.O_WRONLY|os.O_CREAT|os.O_EXCL|binary
352-
try:
353-
fd=os.open(self._lockfilepath(),lockmode)
354-
ifnotwrite:
355-
os.close(fd)
356-
else:
357-
self._fd=fd
358-
# END handle file descriptor
359-
exceptOSError:
360-
raiseIOError("Lock at %r could not be obtained"%self._lockfilepath())
361-
# END handle lock retrieval
362-
363-
# open actual file if required
364-
ifself._fdisNone:
365-
# we could specify exlusive here, as we obtained the lock anyway
366-
self._fd=os.open(self._filepath,os.O_RDONLY|binary)
367-
# END open descriptor for reading
368-
369-
ifstream:
370-
returnFDStreamWrapper(self._fd)
371-
else:
372-
returnself._fd
373-
# END handle stream
374-
375-
defcommit(self):
376-
"""When done writing, call this function to commit your changes into the
377-
actual file.
378-
The file descriptor will be closed, and the lockfile handled.
379-
:note: can be called multiple times"""
380-
self._end_writing(successful=True)
381-
382-
defrollback(self):
383-
"""Abort your operation without any changes. The file descriptor will be
384-
closed, and the lock released.
385-
:note: can be called multiple times"""
386-
self._end_writing(successful=False)
387-
388-
def_end_writing(self,successful=True):
389-
"""Handle the lock according to the write mode """
390-
ifself._writeisNone:
391-
raiseAssertionError("Cannot end operation if it wasn't started yet")
392-
393-
ifself._fdisNone:
394-
return
395-
396-
os.close(self._fd)
397-
self._fd=None
398-
399-
lockfile=self._lockfilepath()
400-
ifself._writeandsuccessful:
401-
# on windows, rename does not silently overwrite the existing one
402-
ifsys.platform=="win32":
403-
ifos.path.isfile(self._filepath):
404-
os.remove(self._filepath)
405-
# END remove if exists
406-
# END win32 special handling
407-
os.rename(lockfile,self._filepath)
408-
else:
409-
# just delete the file so far, we failed
410-
os.remove(lockfile)
411-
# END successful handling
412-
413-
414276

415277
classLazyMixin(object):
416278
"""

‎test/git/test_utils.py

Lines changed: 1 addition & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
fromgit.objects.utilsimport*
1313
fromgitimport*
1414
fromgit.cmdimportdashify
15+
1516
importtime
1617

1718

@@ -68,78 +69,6 @@ def test_blocking_lock_file(self):
6869
elapsed=time.time()-start
6970
assertelapsed<=wait_time+0.02# some extra time it may cost
7071

71-
def_cmp_contents(self,file_path,data):
72-
# raise if data from file at file_path
73-
# does not match data string
74-
fp=open(file_path,"rb")
75-
try:
76-
assertfp.read()==data
77-
finally:
78-
fp.close()
79-
80-
deftest_safe_operation(self):
81-
my_file=tempfile.mktemp()
82-
orig_data="hello"
83-
new_data="world"
84-
my_file_fp=open(my_file,"wb")
85-
my_file_fp.write(orig_data)
86-
my_file_fp.close()
87-
88-
try:
89-
lfd=LockedFD(my_file)
90-
lockfilepath=lfd._lockfilepath()
91-
92-
# cannot end before it was started
93-
self.failUnlessRaises(AssertionError,lfd.rollback)
94-
self.failUnlessRaises(AssertionError,lfd.commit)
95-
96-
# open for writing
97-
assertnotos.path.isfile(lockfilepath)
98-
wfd=lfd.open(write=True)
99-
assertlfd._fdiswfd
100-
assertos.path.isfile(lockfilepath)
101-
102-
# write data and fail
103-
os.write(wfd,new_data)
104-
lfd.rollback()
105-
assertlfd._fdisNone
106-
self._cmp_contents(my_file,orig_data)
107-
assertnotos.path.isfile(lockfilepath)
108-
109-
# additional call doesnt fail
110-
lfd.commit()
111-
lfd.rollback()
112-
113-
# test reading
114-
lfd=LockedFD(my_file)
115-
rfd=lfd.open(write=False)
116-
assertos.read(rfd,len(orig_data))==orig_data
117-
118-
assertos.path.isfile(lockfilepath)
119-
# deletion rolls back
120-
del(lfd)
121-
assertnotos.path.isfile(lockfilepath)
122-
123-
124-
# write data - concurrently
125-
lfd=LockedFD(my_file)
126-
olfd=LockedFD(my_file)
127-
assertnotos.path.isfile(lockfilepath)
128-
wfdstream=lfd.open(write=True,stream=True)# this time as stream
129-
assertos.path.isfile(lockfilepath)
130-
# another one fails
131-
self.failUnlessRaises(IOError,olfd.open)
132-
133-
wfdstream.write(new_data)
134-
lfd.commit()
135-
assertnotos.path.isfile(lockfilepath)
136-
self._cmp_contents(my_file,new_data)
137-
138-
# could test automatic _end_writing on destruction
139-
finally:
140-
os.remove(my_file)
141-
# END final cleanup
142-
14372
deftest_user_id(self):
14473
assert'@'inget_user_id()
14574

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp