summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulien Jehannet <julien.jehannet@logilab.fr>2009-01-20 17:29:44 +0100
committerJulien Jehannet <julien.jehannet@logilab.fr>2009-01-20 17:29:44 +0100
commit58833108d4c5dcb14079102f4d62e8d8f68588f4 (patch)
tree604352392018c0d7993d32bdbb1d9eb382455f8a
parentc1d4b31c38ff7d61966477d0656d2eef69a4a86d (diff)
parentac5caf4deba1db3c848cb85f1f2fc08cd9999273 (diff)
downloadlogilab-common-58833108d4c5dcb14079102f4d62e8d8f68588f4.tar.gz
(merge)
-rw-r--r--shellutils.py30
-rw-r--r--test/unittest_shellutils.py16
2 files changed, 36 insertions, 10 deletions
diff --git a/shellutils.py b/shellutils.py
index d964705..337a9dc 100644
--- a/shellutils.py
+++ b/shellutils.py
@@ -11,6 +11,7 @@ __docformat__ = "restructuredtext en"
import os
import glob
import shutil
+import stat
import sys
import tempfile
import time
@@ -201,8 +202,13 @@ class Execute:
os.remove(outfile)
os.remove(errfile)
-def acquire_lock(lock_file, max_try=10, delay=10):
- """Acquire a lock represented by a file on the file system."""
+def acquire_lock(lock_file, max_try=10, delay=10, max_delay=3600):
+ """Acquire a lock represented by a file on the file system
+
+ If the process written in lock file doesn't exist anymore, we remove the
+ lock file immediately
+ If age of the lock_file is greater than max_delay, then we raise a UserWarning
+ """
count = abs(max_try)
while count:
try:
@@ -216,14 +222,20 @@ def acquire_lock(lock_file, max_try=10, delay=10):
fd = open(lock_file, "r")
pid = int(fd.readline())
pi = ProcInfo(pid)
- # only print the message one time
- if count == max_try:
- diff = (int(time.time()) - pi.age()) / 60
- print("Command '%s' (pid %s) has locked the file '%s' for %s minutes.\nWaiting..." % (pi.name(), pid, lock_file, diff))
+ age = (time.time() - os.stat(lock_file)[stat.ST_MTIME])
+ if age / max_delay > 1 :
+ raise UserWarning("Command '%s' (pid %s) has locked the "
+ "file '%s' for %s minutes"
+ % (pi.name(), pid, lock_file, age/60))
+ except UserWarning:
+ raise
except NoSuchProcess:
- raise NoSuchProcess('You can delete the lock file "%s" safely' % lock_file)
- except:
- # process information are not accessible
+ os.remove(lock_file)
+ except Exception:
+ # The try block is not essential. can be skipped.
+ # Note: ProcInfo object is only available for linux
+ # process information are not accessible...
+ # or lock_file is no more present...
pass
else:
raise
diff --git a/test/unittest_shellutils.py b/test/unittest_shellutils.py
index 903312d..17bc0e0 100644
--- a/test/unittest_shellutils.py
+++ b/test/unittest_shellutils.py
@@ -2,6 +2,7 @@
import sys, os, tempfile, shutil
from os.path import join
+import datetime, time
from logilab.common.testlib import TestCase, unittest_main
@@ -147,7 +148,20 @@ class AcquireLockTC(TestCase):
os.write(fd, '1111111111')
os.close(fd)
self.assertTrue(os.path.exists(self.lock))
- self.assertRaises(NoSuchProcess, acquire_lock, self.lock)
+ self.assertRaises(Exception, acquire_lock, self.lock, 1, 1)
+
+ def test_wrong_process_and_continue(self):
+ fd = os.open(self.lock, os.O_EXCL | os.O_RDWR | os.O_CREAT)
+ os.write(fd, '1111111111')
+ os.close(fd)
+ self.assertTrue(os.path.exists(self.lock))
+ self.assertTrue(acquire_lock(self.lock))
+
+ def test_locked_for_one_hour(self):
+ self.assertTrue(acquire_lock(self.lock))
+ touch = datetime.datetime.fromtimestamp(time.time() - 3601).strftime("%m%d%H%M")
+ os.system("touch -t %s %s" % (touch, self.lock))
+ self.assertRaises(UserWarning, acquire_lock, self.lock, max_try=2, delay=1)
if __name__ == '__main__':