re-format with black

This commit is contained in:
2021-05-03 17:24:04 -04:00
parent 4d7442d70c
commit 62ef10620f
12 changed files with 564 additions and 528 deletions
+2 -2
View File
@@ -37,11 +37,11 @@
"""
from __future__ import (absolute_import, unicode_literals)
from __future__ import absolute_import, unicode_literals
from .daemon import DaemonContext
# Local variables:
# coding: utf-8
# mode: python
+21 -18
View File
@@ -12,7 +12,7 @@
""" Package metadata for the python-daemon distribution. """
from __future__ import (absolute_import, unicode_literals)
from __future__ import absolute_import, unicode_literals
import json
import re
@@ -21,10 +21,11 @@ import datetime
import pkg_resources
distribution_name = "python-daemon"
version_info_filename = "version_info.json"
def get_distribution_version_info(filename=version_info_filename):
""" Get the version info from the installed distribution.
@@ -37,10 +38,10 @@ def get_distribution_version_info(filename=version_info_filename):
"""
version_info = {
'release_date': "UNKNOWN",
'version': "UNKNOWN",
'maintainer': "UNKNOWN",
}
"release_date": "UNKNOWN",
"version": "UNKNOWN",
"maintainer": "UNKNOWN",
}
try:
distribution = pkg_resources.get_distribution(distribution_name)
@@ -54,15 +55,16 @@ def get_distribution_version_info(filename=version_info_filename):
return version_info
version_info = get_distribution_version_info()
version_installed = version_info['version']
version_installed = version_info["version"]
rfc822_person_regex = re.compile(
"^(?P<name>[^<]+) <(?P<email>[^>]+)>$")
ParsedPerson = collections.namedtuple('ParsedPerson', ['name', 'email'])
rfc822_person_regex = re.compile("^(?P<name>[^<]+) <(?P<email>[^>]+)>$")
ParsedPerson = collections.namedtuple("ParsedPerson", ["name", "email"])
def parse_person_field(value):
""" Parse a person field into name and email address.
@@ -79,19 +81,18 @@ def parse_person_field(value):
match = rfc822_person_regex.match(value)
if len(value):
if match is not None:
result = ParsedPerson(
name=match.group('name'),
email=match.group('email'))
result = ParsedPerson(name=match.group("name"), email=match.group("email"))
else:
result = ParsedPerson(name=value, email=None)
return result
author_name = "Ben Finney"
author_email = "ben+python@benfinney.id.au"
author = "{name} <{email}>".format(name=author_name, email=author_email)
class YearRange:
""" A range of years spanning a period. """
@@ -135,16 +136,18 @@ def make_year_range(begin_year, end_date=None):
return year_range
copyright_year_begin = "2001"
build_date = version_info['release_date']
build_date = version_info["release_date"]
copyright_year_range = make_year_range(copyright_year_begin, build_date)
copyright = "Copyright © {year_range} {author} and others".format(
year_range=copyright_year_range, author=author)
year_range=copyright_year_range, author=author
)
license = "Apache-2"
url = "https://alioth.debian.org/projects/python-daemon/"
# Local variables:
# coding: utf-8
# mode: python
+68 -54
View File
@@ -18,7 +18,7 @@
""" Daemon process behaviour.
"""
from __future__ import (absolute_import, unicode_literals)
from __future__ import absolute_import, unicode_literals
import os
import sys
@@ -27,6 +27,7 @@ import errno
import signal
import socket
import atexit
try:
# Python 2 has both str (bytes) and unicode (text).
basestring = basestring
@@ -36,7 +37,7 @@ except NameError:
basestring = str
unicode = str
class DaemonError(Exception):
""" Base exception class for errors from this module. """
@@ -56,7 +57,7 @@ class DaemonOSEnvironmentError(DaemonError, OSError):
class DaemonProcessDetachError(DaemonError, OSError):
""" Exception raised when process detach fails. """
class DaemonContext:
""" Context for turning the current program into a daemon process.
@@ -231,21 +232,21 @@ class DaemonContext:
__metaclass__ = type
def __init__(
self,
chroot_directory=None,
working_directory="/",
umask=0,
uid=None,
gid=None,
prevent_core=True,
detach_process=None,
files_preserve=None,
pidfile=None,
stdin=None,
stdout=None,
stderr=None,
signal_map=None,
):
self,
chroot_directory=None,
working_directory="/",
umask=0,
uid=None,
gid=None,
prevent_core=True,
detach_process=None,
files_preserve=None,
pidfile=None,
stdin=None,
stdout=None,
stderr=None,
signal_map=None,
):
""" Set up a new instance. """
self.chroot_directory = chroot_directory
self.working_directory = working_directory
@@ -427,8 +428,10 @@ class DaemonContext:
"""
exception = SystemExit(
"Terminating on signal {signal_number!r}".format(
signal_number=signal_number))
"Terminating on signal {signal_number!r}".format(
signal_number=signal_number
)
)
raise exception
def _get_exclude_file_descriptors(self):
@@ -454,8 +457,10 @@ class DaemonContext:
if files_preserve is None:
files_preserve = []
files_preserve.extend(
item for item in [self.stdin, self.stdout, self.stderr]
if hasattr(item, 'fileno'))
item
for item in [self.stdin, self.stdout, self.stderr]
if hasattr(item, "fileno")
)
exclude_descriptors = set()
for item in files_preserve:
@@ -502,8 +507,9 @@ class DaemonContext:
"""
signal_handler_map = dict(
(signal_number, self._make_signal_handler(target))
for (signal_number, target) in self.signal_map.items())
(signal_number, self._make_signal_handler(target))
for (signal_number, target) in self.signal_map.items()
)
return signal_handler_map
@@ -520,7 +526,7 @@ def _get_file_descriptor(obj):
"""
file_descriptor = None
if hasattr(obj, 'fileno'):
if hasattr(obj, "fileno"):
try:
file_descriptor = obj.fileno()
except ValueError:
@@ -529,7 +535,7 @@ def _get_file_descriptor(obj):
return file_descriptor
def change_working_directory(directory):
""" Change the working directory of this process.
@@ -541,7 +547,8 @@ def change_working_directory(directory):
os.chdir(directory)
except Exception as exc:
error = DaemonOSEnvironmentError(
"Unable to change working directory ({exc})".format(exc=exc))
"Unable to change working directory ({exc})".format(exc=exc)
)
raise error
@@ -561,7 +568,8 @@ def change_root_directory(directory):
os.chroot(directory)
except Exception as exc:
error = DaemonOSEnvironmentError(
"Unable to change root directory ({exc})".format(exc=exc))
"Unable to change root directory ({exc})".format(exc=exc)
)
raise error
@@ -576,7 +584,8 @@ def change_file_creation_mask(mask):
os.umask(mask)
except Exception as exc:
error = DaemonOSEnvironmentError(
"Unable to change file creation mask ({exc})".format(exc=exc))
"Unable to change file creation mask ({exc})".format(exc=exc)
)
raise error
@@ -597,10 +606,11 @@ def change_process_owner(uid, gid):
os.setuid(uid)
except Exception as exc:
error = DaemonOSEnvironmentError(
"Unable to change process owner ({exc})".format(exc=exc))
"Unable to change process owner ({exc})".format(exc=exc)
)
raise error
def prevent_core_dump():
""" Prevent this process from generating a core dump.
@@ -618,15 +628,16 @@ def prevent_core_dump():
core_limit_prev = resource.getrlimit(core_resource)
except ValueError as exc:
error = DaemonOSEnvironmentError(
"System does not support RLIMIT_CORE resource limit"
" ({exc})".format(exc=exc))
"System does not support RLIMIT_CORE resource limit"
" ({exc})".format(exc=exc)
)
raise error
# Set hard and soft limits to zero, i.e. no core dump at all.
core_limit = (0, 0)
resource.setrlimit(core_resource, core_limit)
def detach_process_context():
""" Detach the process context from parent and session.
@@ -656,15 +667,17 @@ def detach_process_context():
os._exit(0)
except OSError as exc:
error = DaemonProcessDetachError(
"{message}: [{exc.errno:d}] {exc.strerror}".format(
message=error_message, exc=exc))
"{message}: [{exc.errno:d}] {exc.strerror}".format(
message=error_message, exc=exc
)
)
raise error
fork_then_exit_parent(error_message="Failed first fork")
os.setsid()
fork_then_exit_parent(error_message="Failed second fork")
def is_process_started_by_init():
""" Determine whether the current process is started by `init`.
@@ -699,8 +712,7 @@ def is_socket(fd):
file_socket = socket.fromfd(fd, socket.AF_INET, socket.SOCK_RAW)
try:
socket_type = file_socket.getsockopt(
socket.SOL_SOCKET, socket.SO_TYPE)
socket_type = file_socket.getsockopt(socket.SOL_SOCKET, socket.SO_TYPE)
except socket.error as exc:
exc_errno = exc.args[0]
if exc_errno == errno.ENOTSOCK:
@@ -759,7 +771,7 @@ def is_detach_process_context_required():
return result
def close_file_descriptor_if_open(fd):
""" Close a file descriptor if already open.
@@ -778,13 +790,14 @@ def close_file_descriptor_if_open(fd):
pass
else:
error = DaemonOSEnvironmentError(
"Failed to close file descriptor {fd:d} ({exc})".format(
fd=fd, exc=exc))
"Failed to close file descriptor {fd:d} ({exc})".format(fd=fd, exc=exc)
)
raise error
MAXFD = 2048
def get_maximum_file_descriptors():
""" Get the maximum number of open file descriptors for this process.
@@ -820,7 +833,7 @@ def close_all_open_files(exclude=set()):
if fd not in exclude:
close_file_descriptor_if_open(fd)
def redirect_stream(system_stream, target_stream):
""" Redirect a system stream to a specified file.
@@ -844,7 +857,7 @@ def redirect_stream(system_stream, target_stream):
target_fd = target_stream.fileno()
os.dup2(target_fd, system_stream.fileno())
def make_default_signal_map():
""" Make the default signal map for this system.
@@ -855,15 +868,16 @@ def make_default_signal_map():
"""
name_map = {
'SIGTSTP': None,
'SIGTTIN': None,
'SIGTTOU': None,
'SIGTERM': 'terminate',
}
"SIGTSTP": None,
"SIGTTIN": None,
"SIGTTOU": None,
"SIGTERM": "terminate",
}
signal_map = dict(
(getattr(signal, name), target)
for (name, target) in name_map.items()
if hasattr(signal, name))
(getattr(signal, name), target)
for (name, target) in name_map.items()
if hasattr(signal, name)
)
return signal_map
@@ -895,7 +909,7 @@ def register_atexit_function(func):
"""
atexit.register(func)
def _chain_exception_from_existing_exception_context(exc, as_cause=False):
""" Decorate the specified exception with the existing exception context.
@@ -918,7 +932,7 @@ def _chain_exception_from_existing_exception_context(exc, as_cause=False):
exc.__context__ = existing_exc
exc.__traceback__ = existing_traceback
# Local variables:
# coding: utf-8
# mode: python
+3 -3
View File
@@ -13,11 +13,11 @@
""" Lockfile behaviour implemented via Unix PID files.
"""
from __future__ import (absolute_import, unicode_literals)
from __future__ import absolute_import, unicode_literals
from lockfile.pidlockfile import PIDLockFile
class TimeoutPIDLockFile(PIDLockFile, object):
""" Lockfile with default timeout, implemented as a Unix PID file.
@@ -59,7 +59,7 @@ class TimeoutPIDLockFile(PIDLockFile, object):
timeout = self.acquire_timeout
super(TimeoutPIDLockFile, self).acquire(timeout, *args, **kwargs)
# Local variables:
# coding: utf-8
# mode: python
+26 -28
View File
@@ -17,12 +17,13 @@
""" Daemon runner library.
"""
from __future__ import (absolute_import, unicode_literals)
from __future__ import absolute_import, unicode_literals
import sys
import os
import signal
import errno
try:
# Python 3 standard library.
ProcessLookupError
@@ -33,11 +34,11 @@ except NameError:
import lockfile
from . import pidfile
from .daemon import (basestring, unicode)
from .daemon import basestring, unicode
from .daemon import DaemonContext
from .daemon import _chain_exception_from_existing_exception_context
class DaemonRunnerError(Exception):
""" Abstract base class for errors from DaemonRunner. """
@@ -65,7 +66,7 @@ class DaemonRunnerStartFailureError(DaemonRunnerError, RuntimeError):
class DaemonRunnerStopFailureError(DaemonRunnerError, RuntimeError):
""" Raised when failure stopping DaemonRunner. """
class DaemonRunner:
""" Controller for a callable running in a separate background process.
@@ -107,15 +108,13 @@ class DaemonRunner:
self.parse_args()
self.app = app
self.daemon_context = DaemonContext()
self.daemon_context.stdin = open(app.stdin_path, 'rt')
self.daemon_context.stdout = open(app.stdout_path, 'w+t')
self.daemon_context.stderr = open(
app.stderr_path, 'w+t', buffering=0)
self.daemon_context.stdin = open(app.stdin_path, "rt")
self.daemon_context.stdout = open(app.stdout_path, "w+t")
self.daemon_context.stderr = open(app.stderr_path, "w+t", buffering=0)
self.pidfile = None
if app.pidfile_path is not None:
self.pidfile = make_pidlockfile(
app.pidfile_path, app.pidfile_timeout)
self.pidfile = make_pidlockfile(app.pidfile_path, app.pidfile_timeout)
self.daemon_context.pidfile = self.pidfile
def _usage_exit(self, argv):
@@ -130,7 +129,8 @@ class DaemonRunner:
usage_exit_code = 2
action_usage = "|".join(self.action_funcs.keys())
message = "usage: {progname} {usage}".format(
progname=progname, usage=action_usage)
progname=progname, usage=action_usage
)
emit_message(message)
sys.exit(usage_exit_code)
@@ -175,8 +175,8 @@ class DaemonRunner:
self.daemon_context.open()
except lockfile.AlreadyLocked:
error = DaemonRunnerStartFailureError(
"PID file {pidfile.path!r} already locked".format(
pidfile=self.pidfile))
"PID file {pidfile.path!r} already locked".format(pidfile=self.pidfile)
)
raise error
pid = os.getpid()
@@ -198,8 +198,8 @@ class DaemonRunner:
os.kill(pid, signal.SIGTERM)
except OSError as exc:
error = DaemonRunnerStopFailureError(
"Failed to terminate {pid:d}: {exc}".format(
pid=pid, exc=exc))
"Failed to terminate {pid:d}: {exc}".format(pid=pid, exc=exc)
)
raise error
def _stop(self):
@@ -212,8 +212,8 @@ class DaemonRunner:
"""
if not self.pidfile.is_locked():
error = DaemonRunnerStopFailureError(
"PID file {pidfile.path!r} not locked".format(
pidfile=self.pidfile))
"PID file {pidfile.path!r} not locked".format(pidfile=self.pidfile)
)
raise error
if is_pidfile_stale(self.pidfile):
@@ -228,10 +228,10 @@ class DaemonRunner:
self._start()
action_funcs = {
'start': _start,
'stop': _stop,
'restart': _restart,
}
"start": _start,
"stop": _stop,
"restart": _restart,
}
def _get_action_func(self):
""" Get the function for the specified action.
@@ -249,8 +249,8 @@ class DaemonRunner:
func = self.action_funcs[self.action]
except KeyError:
error = DaemonRunnerInvalidActionError(
"Unknown action: {action!r}".format(
action=self.action))
"Unknown action: {action!r}".format(action=self.action)
)
raise error
return func
@@ -278,12 +278,10 @@ def emit_message(message, stream=None):
def make_pidlockfile(path, acquire_timeout):
""" Make a PIDLockFile instance with the given filesystem path. """
if not isinstance(path, basestring):
error = ValueError("Not a filesystem path: {path!r}".format(
path=path))
error = ValueError("Not a filesystem path: {path!r}".format(path=path))
raise error
if not os.path.isabs(path):
error = ValueError("Not an absolute path: {path!r}".format(
path=path))
error = ValueError("Not an absolute path: {path!r}".format(path=path))
raise error
lockfile = pidfile.TimeoutPIDLockFile(path, acquire_timeout)
@@ -316,7 +314,7 @@ def is_pidfile_stale(pidfile):
return result
# Local variables:
# coding: utf-8
# mode: python
+298 -308
View File
@@ -1,4 +1,3 @@
"""
host and connection class shared between hbd and
the websit's heartbeat.py
@@ -13,358 +12,349 @@ num = 0
MAXRTTS = 10
DEBUG=2
DEBUG = 2
def log(host, m):
if DEBUG:
print("class log: %s %s" % (host, m))
if DEBUG:
print("class log: %s %s" % (host, m))
class Connection:
# map of addrs to names
# map of addrs to names
htab = {}
unknown = "unknown"
up = "up"
down = "down"
overdue = "overdue"
htab = {}
unknown = "unknown"
up = "up"
down = "down"
overdue = "overdue"
def __init__(self, host, cid, addr, afam):
self.host = host
self.cid = cid
self.addr = addr
self.afam = afam
self.rtts = [0]
self.lastbeat = time.time()
self.statetime = self.lastbeat
self.deltastatetime = 'computed'
self.state = Connection.unknown
def __init__(self, host, cid, addr, afam):
self.host = host
self.cid = cid
self.addr = addr
self.afam = afam
self.rtts = [0]
self.lastbeat = time.time()
self.statetime = self.lastbeat
self.deltastatetime = "computed"
self.state = Connection.unknown
if host:
r = "new addr %s" % (addr)
Connection.htab[addr] = self.host.name
if self.host.isDynDns():
log(self.host.name, "dns update %s" % self.addr)
Host.dnsQ.put((self.host.name, self.addr))
if host:
r = "new addr %s" % (addr)
Connection.htab[addr] = self.host.name
if self.host.isDynDns():
log(self.host.name, "dns update %s" % self.addr)
Host.dnsQ.put((self.host.name, self.addr))
def registerDns(self):
Host.dnsQ.put((self.host.name, self.addr))
def registerDns(self):
Host.dnsQ.put((self.host.name, self.addr))
def statedict(self, Null=False):
d = {}
now = time.time()
if not Null:
d["addr"] = self.addr
if self.rtts[-1]:
d["rtt"] = "%0.1f" % self.rtts[-1]
elif self.state == Connection.unknown:
d["rtt"] = ""
else:
d["rtt"] = "?"
d["lastbeat"] = self.lastbeat
if self.state == Connection.overdue:
d["state"] = "<b>%s</b>" % self.state
else:
d["state"] = self.state
if self.state == Connection.up:
d["rttstate"] = d["rtt"]
elif self.state == Connection.overdue:
d["rttstate"] = ""
else:
d["rttstate"] = d["state"]
d["statetime"] = time.strftime(
"%Y-%m-%d %H:%M:%S", time.localtime(self.statetime)
)
delta = now - self.statetime
def statedict(self, Null=False):
d = {}
now = time.time()
if not Null:
d['addr'] = self.addr
if self.rtts[-1]:
d['rtt'] = "%0.1f" % self.rtts[-1]
elif self.state == Connection.unknown:
d['rtt'] = ""
else:
d['rtt'] = "?"
d['lastbeat'] = self.lastbeat
if self.state == Connection.overdue:
d['state'] = "<b>%s</b>" % self.state
else:
d['state'] = self.state
if self.state == Connection.up:
d['rttstate'] = d['rtt']
elif self.state == Connection.overdue:
d['rttstate'] = ''
else:
d['rttstate'] = d['state']
d['statetime'] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(self.statetime))
delta = now - self.statetime
if self.state == Connection.unknown:
d["deltastatetime"] = ""
elif delta > 86400:
# d['deltastatetime'] = time.strftime("%d %H:%M:%S", time.gmtime(delta))
d["deltastatetime"] = "%0.1f days" % (delta / 86400.0)
elif delta > 3600:
# d['deltastatetime'] = time.strftime("%H:%M:%S", time.gmtime(delta))
d["deltastatetime"] = time.strftime("%k:%M hrs", time.gmtime(delta))
# d['deltastatetime'] = "%0.1f hrs" % (delta / 3600.)
elif delta > 60:
# d['deltastatetime'] = time.strftime("%M:%S", time.gmtime(delta))
d["deltastatetime"] = time.strftime("%M:%S mins", time.gmtime(delta))
# d['deltastatetime'] = "%0.1f mins" % (delta / 60.)
else:
# d['deltastatetime'] = time.strftime("%S", time.gmtime(delta))
d["deltastatetime"] = "%i secs" % (delta)
if self.state == Connection.unknown:
d['deltastatetime'] = ''
elif delta > 86400:
# d['deltastatetime'] = time.strftime("%d %H:%M:%S", time.gmtime(delta))
d['deltastatetime'] = "%0.1f days" % (delta / 86400.)
elif delta > 3600:
# d['deltastatetime'] = time.strftime("%H:%M:%S", time.gmtime(delta))
d['deltastatetime'] = time.strftime("%k:%M hrs", time.gmtime(delta))
# d['deltastatetime'] = "%0.1f hrs" % (delta / 3600.)
elif delta > 60:
# d['deltastatetime'] = time.strftime("%M:%S", time.gmtime(delta))
d['deltastatetime'] = time.strftime("%M:%S mins", time.gmtime(delta))
# d['deltastatetime'] = "%0.1f mins" % (delta / 60.)
else:
# d['deltastatetime'] = time.strftime("%S", time.gmtime(delta))
d['deltastatetime'] = "%i secs" % (delta)
else:
d["addr"] = ""
d["rtt"] = ""
d["lastbeat"] = ""
d["state"] = ""
d["statetime"] = ""
d["deltastatetime"] = ""
d["rttstate"] = ""
return d
else:
d['addr'] = ''
d['rtt'] = ""
d['lastbeat'] = ''
d['state'] = ''
d['statetime'] = ''
d['deltastatetime'] = ''
d['rttstate'] = ''
return d
def headerdict(self, afam):
d = {}
d["addr"] = "%s Addr" % afam
d["rtt"] = "Latencey"
d["lastbeat"] = "Last Contact"
d["state"] = "State"
d["statetime"] = "Last State"
d["rttstate"] = "Reach"
d["deltastatetime"] = "Last State"
return d
def jsons(self):
return json.dumps(self.__dict__)
def headerdict(self, afam):
d = {}
d['addr'] = '%s Addr' % afam
d['rtt'] = 'Latencey'
d['lastbeat'] = 'Last Contact'
d['state'] = 'State'
d['statetime'] = 'Last State'
d['rttstate'] = 'Reach'
d['deltastatetime'] = 'Last State'
return d
# set new state, return number of secs in previous state
def newstate(self, state, now, when=0):
self.state = state
delta = now - when
s = delta - self.statetime
self.statetime = delta
return s
def getstate(self):
return self.state
def jsons(self):
return(json.dumps(self.__dict__))
def newaddr(self, addr, rtt, now):
self.lastbeat = now
self.rtts.append(rtt)
if len(self.rtts) > MAXRTTS:
del self.rtts[0]
# set new state, return number of secs in previous state
def newstate(self, state, now, when=0):
self.state = state
delta = now - when
s = delta - self.statetime
self.statetime = delta
return s
def getstate(self):
return self.state
def newaddr(self, addr, rtt, now):
self.lastbeat = now
self.rtts.append(rtt)
if len(self.rtts) > MAXRTTS:
del self.rtts[0]
if self.addr == addr:
r = None
else:
r = "changed from %s to %s" % (self.addr, addr)
try:
del Connection.htab[self.addr]
except:
pass
self.addr = addr
Connection.htab[addr] = self.host.name
if self.host.isDynDns():
Host.dnsQ.put((self.host.name, self.addr))
return r
if self.addr == addr:
r = None
else:
r = "changed from %s to %s" % (self.addr, addr)
try:
del Connection.htab[self.addr]
except:
pass
self.addr = addr
Connection.htab[addr] = self.host.name
if self.host.isDynDns():
Host.dnsQ.put((self.host.name, self.addr))
return r
#
class Host:
# Table of Hosts
hosts = {}
# Table of Hosts
hosts = {}
def __init__(self, name):
global num
self.name = name
if name:
num += 1
Host.hosts[name] = self
self.num = num
self.dyn = False
self.watched = False
self.upcount = 0
self.interval = 0
self.doesack = -1
self.cmds = []
self.cver = 0
self.connections = {}
self.hdwcounts = [[0,0],[0,0],[0,0]]
def __init__(self, name):
global num
self.name = name
if name:
num += 1
Host.hosts[name] = self
self.num = num
self.dyn = False
self.watched = False
self.upcount = 0
self.interval = 0
self.doesack = -1
self.cmds = []
self.cver = 0
self.connections = {}
self.hdwcounts = [[0, 0], [0, 0], [0, 0]]
def statedict(self):
d = {}
d["name"] = self.name
if self.dyn:
d["name"] += "*"
if self.watched:
d["name"] = "<b>%s</b>" % d["name"]
d["dyn"] = str(self.dyn)
d["ver"] = str(self.cver)
d["num"] = self.num
for c in ["IPv4", "IPv6"]:
if c in self.connections:
cs = self.connections[c].statedict()
else:
cs = ubConnection.statedict(True)
for csv in cs:
d["%s.%s" % (c, csv)] = cs[csv]
def statedict(self):
d = {}
d['name'] = self.name
if self.dyn:
d['name'] += "*"
if self.watched:
d['name'] = "<b>%s</b>" % d['name']
d['dyn'] = str(self.dyn)
d['ver'] = str(self.cver)
d['num'] = self.num
for c in ['IPv4', 'IPv6']:
if c in self.connections:
cs = self.connections[c].statedict()
else:
cs = ubConnection.statedict(True)
for csv in cs:
d['%s.%s' % (c, csv) ] = cs[csv]
return d
return d
def headerdict(self):
d = {}
d["name"] = "Name"
d["dyn"] = "Dyn"
d["ver"] = "Ver"
d["num"] = "??"
for c in ["IPv4", "IPv6"]:
cs = ubConnection.headerdict(c)
for csv in cs:
d["%s.%s" % (c, csv)] = cs[csv]
return d
def registerDns(self):
for af in self.connections:
self.connections[af].registerDns()
def headerdict(self):
d = {}
d['name'] = 'Name'
d['dyn'] = 'Dyn'
d['ver'] = 'Ver'
d['num'] = '??'
for c in ['IPv4', 'IPv6']:
cs = ubConnection.headerdict(c)
for csv in cs:
d['%s.%s' % (c, csv) ] = cs[csv]
return d
def jsons(self):
ddict = {}
for d in self.__dict__:
if d == "connections":
cl = []
for c in self.connections:
# dirty ugly hack: fix conn to host backpointer
cld = copy.deepcopy(self.connections[c].__dict__)
cld["host"] = cld["host"].name
cl.append(cld)
ddict[d] = cl
else:
ddict[d] = self.__dict__[d]
return json.dumps(ddict)
def setcver(self, cver):
self.cver = cver
def registerDns(self):
for af in self.connections:
self.connections[af].registerDns()
def isDynDns(self):
return self.dyn
def isIPv4(self, addr):
if type(addr) == type(()):
return addr[0].find(".") > 0
else:
return addr.find(".") > 0
def jsons(self):
ddict = {}
for d in self.__dict__:
if d == 'connections':
cl = []
for c in self.connections:
# dirty ugly hack: fix conn to host backpointer
cld = copy.deepcopy(self.connections[c].__dict__)
cld['host'] = cld['host'].name
cl.append(cld)
ddict[d] = cl
else:
ddict[d] = self.__dict__[d]
return json.dumps(ddict)
def conndata(self, cid, addr, rtt, now):
if self.isIPv4(addr):
afam = "IPv4"
else:
afam = "IPv6"
if afam not in self.connections:
self.connections[afam] = Connection(self, cid, addr, afam)
def setcver(self, cver):
self.cver = cver
conn = self.connections[afam]
res = conn.newaddr(addr, rtt, now)
return conn, res
# called when reloading class from pickle, add new fields here
def fixup(self):
pass
def isDynDns(self):
return self.dyn
def dispstate(self):
if self.state in ["down", "overdue"]:
state = "<b>%s</b>" % self.state
elif self.state in ["up", "UP"]:
state = ""
for x in list(self.connections.keys()):
try:
state += " %5.1f" % (self.connections[x].rtts[-1])
except:
state += " %5s" % (self.connections[x].rtts[-1])
elif self.state in ["unknown", "UNKNOWN"]:
state = ""
else:
state = "%s" % self.state
return state
def dispstats(self):
if self.doesack != -1:
if self.upcount > 0:
# return "(%0.1f%%) %s %s %s " % ((self.doesack * 100.0) / self.upcount, self.doesack, self.upcount, self.hdwcounts)
r = ""
for v in range(3):
a, u = self.hdwcounts[v]
if (self.upcount - u) != 0:
vs = "%0.0f" % (
100.0 - (((self.doesack - a) * 100.0) / (self.upcount - u))
)
if vs == "0":
vs = ""
else:
vs = "-"
r += '<td align="right">%s</td>' % vs
return r
else:
return "<td>(%s)</td><td></td><td></td>" % (self.doesack)
return '<td align="right">N/A</td><td></td<td></td>>'
def isIPv4(self, addr):
if type(addr) == type(()):
return addr[0].find('.') > 0
else:
return addr.find('.') > 0
hostfields_long = [
"name",
"IPv4.addr",
"IPv4.state",
("IPv4.rtt", 'style="text-align: right;"'),
("IPv4.statetime", 'style="text-align: right;"'),
"IPv6.addr",
"IPv6.state",
("IPv6.rtt", 'style="text-align: right;"'),
("IPv6.statetime", 'style="text-align: right;"'),
"ver",
]
hostfields_short = [
"name",
("IPv4.rttstate", 'style="text-align: right;"'),
("IPv4.deltastatetime", 'style="text-align: right;"'),
("IPv6.rttstate", 'style="text-align: right;"'),
("IPv6.deltastatetime", 'style="text-align: right;"'),
]
def conndata(self, cid, addr, rtt, now):
if self.isIPv4(addr):
afam = "IPv4"
else:
afam = "IPv6"
def gene(self, tag, v, attrib=None):
if attrib:
a = " %s" % attrib
else:
a = ""
return "<%s%s>%s</%s>" % (tag, a, v, tag)
if afam not in self.connections:
self.connections[afam] = Connection(self, cid, addr, afam)
def htmltable(self, tag, hd, short):
if short:
hostfields = Host.hostfields_short
else:
hostfields = Host.hostfields_long
h = []
for f in hostfields:
if type(f) == type(()):
h.append(self.gene(tag, hd[f[0]], f[1]))
else:
h.append(self.gene(tag, hd[f]))
return self.gene("tr", "\n".join(h))
conn = self.connections[afam]
res = conn.newaddr(addr, rtt, now)
return conn, res
# called when reloading class from pickle, add new fields here
def fixup(self):
pass
def dispstate(self):
if self.state in ["down", "overdue"]:
state = "<b>%s</b>" % self.state
elif self.state in ["up", "UP"]:
state = ""
for x in list(self.connections.keys()):
try:
state += " %5.1f" % (self.connections[x].rtts[-1])
except:
state += " %5s" % (self.connections[x].rtts[-1])
elif self.state in ["unknown", "UNKNOWN"]:
state = ""
else:
state = "%s" % self.state
return state
def dispstats(self):
if self.doesack != -1:
if self.upcount > 0:
# return "(%0.1f%%) %s %s %s " % ((self.doesack * 100.0) / self.upcount, self.doesack, self.upcount, self.hdwcounts)
r = ""
for v in range(3):
a,u = self.hdwcounts[v]
if (self.upcount - u) != 0:
vs = "%0.0f" % (100.0 - (((self.doesack - a) * 100.0) / (self.upcount - u)))
if vs == "0":
vs=""
else:
vs="-"
r+= '<td align="right">%s</td>' % vs
return r
else:
return "<td>(%s)</td><td></td><td></td>" % (self.doesack)
return '<td align="right">N/A</td><td></td<td></td>>'
hostfields_long = ['name', 'IPv4.addr',
'IPv4.state', ('IPv4.rtt','style="text-align: right;"'),
('IPv4.statetime','style="text-align: right;"'), 'IPv6.addr',
'IPv6.state', ('IPv6.rtt', 'style="text-align: right;"'),
('IPv6.statetime','style="text-align: right;"'), 'ver']
hostfields_short = ['name',
('IPv4.rttstate','style="text-align: right;"'),
('IPv4.deltastatetime','style="text-align: right;"'),
('IPv6.rttstate','style="text-align: right;"'),
('IPv6.deltastatetime','style="text-align: right;"')]
def gene(self, tag, v, attrib=None):
if attrib:
a=" %s" % attrib
else:
a=""
return "<%s%s>%s</%s>" % (tag, a, v, tag)
def htmltable(self, tag, hd, short):
if short:
hostfields = Host.hostfields_short
else:
hostfields = Host.hostfields_long
h = []
for f in hostfields:
if type(f) == type(()):
h.append(self.gene(tag, hd[f[0]], f[1]))
else:
h.append(self.gene(tag, hd[f]))
return self.gene("tr", "\n".join(h))
def buildhosttable(self, short=False):
if DEBUG > 1:
print("DBG buildhosttable: start")
res = []
res.append('<table id="ntable" class="sortable">')
res.append(ubHost.htmltable('th', ubHost.headerdict(), short))
hosts_sorted = list(Host.hosts.keys())
if len(hosts_sorted):
hosts_sorted.sort()
for h in hosts_sorted:
res.append(ubHost.htmltable('td', Host.hosts[h].statedict(), short))
res.append("</table>")
if DEBUG > 1:
print("DBG buildhosttable: %s" % res)
return res
def buildmsgtable(self, msgs):
res = []
le = max(40 - len(Host.hosts), 3)
res.append("<h4>Log of Events</h4>")
for m in msgs[len(msgs)-le:]:
res.append("%s<BR>" % m)
return res
def buildhosttable(self, short=False):
if DEBUG > 1:
print("DBG buildhosttable: start")
res = []
res.append('<table id="ntable" class="sortable">')
res.append(ubHost.htmltable("th", ubHost.headerdict(), short))
hosts_sorted = list(Host.hosts.keys())
if len(hosts_sorted):
hosts_sorted.sort()
for h in hosts_sorted:
res.append(ubHost.htmltable("td", Host.hosts[h].statedict(), short))
res.append("</table>")
if DEBUG > 1:
print("DBG buildhosttable: %s" % res)
return res
def buildmsgtable(self, msgs):
res = []
le = max(40 - len(Host.hosts), 3)
res.append("<h4>Log of Events</h4>")
for m in msgs[len(msgs) - le :]:
res.append("%s<BR>" % m)
return res
# create fake "unbound objects", remove in Python 3.0
ubHost = Host(None)
ubConnection = Connection(None, "", "", "")
+50 -20
View File
@@ -65,10 +65,21 @@ if not hasattr(threading, "current_thread"):
if not hasattr(threading.Thread, "get_name"):
threading.Thread.get_name = threading.Thread.getName
__all__ = ['Error', 'LockError', 'LockTimeout', 'AlreadyLocked',
'LockFailed', 'UnlockError', 'NotLocked', 'NotMyLock',
'LinkFileLock', 'MkdirFileLock', 'SQLiteFileLock',
'LockBase', 'locked']
__all__ = [
"Error",
"LockError",
"LockTimeout",
"AlreadyLocked",
"LockFailed",
"UnlockError",
"NotLocked",
"NotMyLock",
"LinkFileLock",
"MkdirFileLock",
"SQLiteFileLock",
"LockBase",
"locked",
]
class Error(Exception):
@@ -80,6 +91,7 @@ class Error(Exception):
... except Exception:
... pass
"""
pass
@@ -92,6 +104,7 @@ class LockError(Error):
... except Error:
... pass
"""
pass
@@ -103,6 +116,7 @@ class LockTimeout(LockError):
... except LockError:
... pass
"""
pass
@@ -114,6 +128,7 @@ class AlreadyLocked(LockError):
... except LockError:
... pass
"""
pass
@@ -125,6 +140,7 @@ class LockFailed(LockError):
... except LockError:
... pass
"""
pass
@@ -137,6 +153,7 @@ class UnlockError(Error):
... except Error:
... pass
"""
pass
@@ -148,6 +165,7 @@ class NotLocked(UnlockError):
... except UnlockError:
... pass
"""
pass
@@ -159,6 +177,7 @@ class NotMyLock(UnlockError):
... except UnlockError:
... pass
"""
pass
@@ -209,6 +228,7 @@ class _SharedBase(object):
class LockBase(_SharedBase):
"""Base class for platform-specific lock classes."""
def __init__(self, path, threaded=True, timeout=None):
"""
>>> lock = LockBase('somefile')
@@ -223,7 +243,7 @@ class LockBase(_SharedBase):
# Thread objects in Python 2.4 and earlier do not have ident
# attrs. Worm around that.
ident = getattr(t, "ident", hash(t))
self.tname = "-%x" % (ident & 0xffffffff)
self.tname = "-%x" % (ident & 0xFFFFFFFF)
else:
self.tname = ""
dirname = os.path.dirname(self.lock_file)
@@ -235,11 +255,10 @@ class LockBase(_SharedBase):
# and overwriting the already existing lock-file, then one
# gets unlocked, deleting both lock-file and unique file,
# finally the last lock errors out upon releasing.
self.unique_name = os.path.join(dirname,
"%s%s.%s%s" % (self.hostname,
self.tname,
self.pid,
hash(self.path)))
self.unique_name = os.path.join(
dirname,
"%s%s.%s%s" % (self.hostname, self.tname, self.pid, hash(self.path)),
)
self.timeout = timeout
def is_locked(self):
@@ -261,13 +280,15 @@ class LockBase(_SharedBase):
raise NotImplemented("implement in subclass")
def __repr__(self):
return "<%s: %r -- %r>" % (self.__class__.__name__, self.unique_name,
self.path)
return "<%s: %r -- %r>" % (self.__class__.__name__, self.unique_name, self.path)
def _fl_helper(cls, mod, *args, **kwds):
warnings.warn("Import from %s module instead of lockfile package" % mod,
DeprecationWarning, stacklevel=2)
warnings.warn(
"Import from %s module instead of lockfile package" % mod,
DeprecationWarning,
stacklevel=2,
)
# This is a bit funky, but it's only for awhile. The way the unit tests
# are constructed this function winds up as an unbound method, so it
# actually takes three args, not two. We want to toss out self.
@@ -286,8 +307,8 @@ def LinkFileLock(*args, **kwds):
lockfile.linklockfile module.
"""
from . import linklockfile
return _fl_helper(linklockfile.LinkLockFile, "lockfile.linklockfile",
*args, **kwds)
return _fl_helper(linklockfile.LinkLockFile, "lockfile.linklockfile", *args, **kwds)
def MkdirFileLock(*args, **kwds):
@@ -297,8 +318,10 @@ def MkdirFileLock(*args, **kwds):
lockfile.mkdirlockfile module.
"""
from . import mkdirlockfile
return _fl_helper(mkdirlockfile.MkdirLockFile, "lockfile.mkdirlockfile",
*args, **kwds)
return _fl_helper(
mkdirlockfile.MkdirLockFile, "lockfile.mkdirlockfile", *args, **kwds
)
def SQLiteFileLock(*args, **kwds):
@@ -308,8 +331,10 @@ def SQLiteFileLock(*args, **kwds):
lockfile.mkdirlockfile module.
"""
from . import sqlitelockfile
return _fl_helper(sqlitelockfile.SQLiteLockFile, "lockfile.sqlitelockfile",
*args, **kwds)
return _fl_helper(
sqlitelockfile.SQLiteLockFile, "lockfile.sqlitelockfile", *args, **kwds
)
def locked(path, timeout=None):
@@ -324,6 +349,7 @@ def locked(path, timeout=None):
def myname(...):
...
"""
def decor(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
@@ -333,15 +359,19 @@ def locked(path, timeout=None):
return func(*args, **kwargs)
finally:
lock.release()
return wrapper
return decor
if hasattr(os, "link"):
from . import linklockfile as _llf
LockFile = _llf.LinkLockFile
else:
from . import mkdirlockfile as _mlf
LockFile = _mlf.MkdirLockFile
FileLock = LockFile
+10 -10
View File
@@ -3,8 +3,7 @@ from __future__ import absolute_import
import time
import os
from . import (LockBase, LockFailed, NotLocked, NotMyLock, LockTimeout,
AlreadyLocked)
from . import LockBase, LockFailed, NotLocked, NotMyLock, LockTimeout, AlreadyLocked
class LinkLockFile(LockBase):
@@ -41,12 +40,11 @@ class LinkLockFile(LockBase):
if timeout is not None and time.time() > end_time:
os.unlink(self.unique_name)
if timeout > 0:
raise LockTimeout("Timeout waiting to acquire"
" lock for %s" %
self.path)
raise LockTimeout(
"Timeout waiting to acquire" " lock for %s" % self.path
)
else:
raise AlreadyLocked("%s is already locked" %
self.path)
raise AlreadyLocked("%s is already locked" % self.path)
time.sleep(timeout is not None and timeout / 10 or 0.1)
else:
# Link creation succeeded. We're good to go.
@@ -64,9 +62,11 @@ class LinkLockFile(LockBase):
return os.path.exists(self.lock_file)
def i_am_locking(self):
return (self.is_locked() and
os.path.exists(self.unique_name) and
os.stat(self.unique_name).st_nlink == 2)
return (
self.is_locked()
and os.path.exists(self.unique_name)
and os.stat(self.unique_name).st_nlink == 2
)
def break_lock(self):
if os.path.exists(self.lock_file):
+10 -13
View File
@@ -5,12 +5,12 @@ import os
import sys
import errno
from . import (LockBase, LockFailed, NotLocked, NotMyLock, LockTimeout,
AlreadyLocked)
from . import LockBase, LockFailed, NotLocked, NotMyLock, LockTimeout, AlreadyLocked
class MkdirLockFile(LockBase):
"""Lock file by creating a directory."""
def __init__(self, path, threaded=True, timeout=None):
"""
>>> lock = MkdirLockFile('somefile')
@@ -19,10 +19,9 @@ class MkdirLockFile(LockBase):
LockBase.__init__(self, path, threaded, timeout)
# Lock file itself is a directory. Place the unique file name into
# it.
self.unique_name = os.path.join(self.lock_file,
"%s.%s%s" % (self.hostname,
self.tname,
self.pid))
self.unique_name = os.path.join(
self.lock_file, "%s.%s%s" % (self.hostname, self.tname, self.pid)
)
def acquire(self, timeout=None):
timeout = timeout if timeout is not None else self.timeout
@@ -47,13 +46,12 @@ class MkdirLockFile(LockBase):
return
if timeout is not None and time.time() > end_time:
if timeout > 0:
raise LockTimeout("Timeout waiting to acquire"
" lock for %s" %
self.path)
raise LockTimeout(
"Timeout waiting to acquire" " lock for %s" % self.path
)
else:
# Someone else has the lock.
raise AlreadyLocked("%s is already locked" %
self.path)
raise AlreadyLocked("%s is already locked" % self.path)
time.sleep(wait)
else:
# Couldn't create the lock for some other reason
@@ -74,8 +72,7 @@ class MkdirLockFile(LockBase):
return os.path.exists(self.lock_file)
def i_am_locking(self):
return (self.is_locked() and
os.path.exists(self.unique_name))
return self.is_locked() and os.path.exists(self.unique_name)
def break_lock(self):
if os.path.exists(self.lock_file):
+9 -11
View File
@@ -18,10 +18,9 @@ import errno
import os
import time
from . import (LockBase, AlreadyLocked, LockFailed, NotLocked, NotMyLock,
LockTimeout)
from . import LockBase, AlreadyLocked, LockFailed, NotLocked, NotMyLock, LockTimeout
class PIDLockFile(LockBase):
""" Lockfile implemented as a Unix PID file.
@@ -80,12 +79,11 @@ class PIDLockFile(LockBase):
# The lock creation failed. Maybe sleep a bit.
if time.time() > end_time:
if timeout is not None and timeout > 0:
raise LockTimeout("Timeout waiting to acquire"
" lock for %s" %
self.path)
raise LockTimeout(
"Timeout waiting to acquire" " lock for %s" % self.path
)
else:
raise AlreadyLocked("%s is already locked" %
self.path)
raise AlreadyLocked("%s is already locked" % self.path)
time.sleep(timeout is not None and timeout / 10 or 0.1)
else:
raise LockFailed("failed to create %s" % self.path)
@@ -125,7 +123,7 @@ def read_pid_from_pidfile(pidfile_path):
"""
pid = None
try:
pidfile = open(pidfile_path, 'r')
pidfile = open(pidfile_path, "r")
except IOError:
pass
else:
@@ -156,10 +154,10 @@ def write_pid_to_pidfile(pidfile_path):
and write it to the named file as a line of text.
"""
open_flags = (os.O_CREAT | os.O_EXCL | os.O_WRONLY)
open_flags = os.O_CREAT | os.O_EXCL | os.O_WRONLY
open_mode = 0o644
pidfile_fd = os.open(pidfile_path, open_flags, open_mode)
pidfile = os.fdopen(pidfile_fd, 'w')
pidfile = os.fdopen(pidfile_fd, "w")
# According to the FHS 2.3 section on PID files in /var/run:
#
+46 -40
View File
@@ -27,6 +27,7 @@ class SQLiteLockFile(LockBase):
if SQLiteLockFile.testdb is None:
import tempfile
_fd, testdb = tempfile.mkstemp()
os.close(_fd)
os.unlink(testdb)
@@ -34,20 +35,24 @@ class SQLiteLockFile(LockBase):
SQLiteLockFile.testdb = testdb
import sqlite3
self.connection = sqlite3.connect(SQLiteLockFile.testdb)
c = self.connection.cursor()
try:
c.execute("create table locks"
"("
" lock_file varchar(32),"
" unique_name varchar(32)"
")")
c.execute(
"create table locks"
"("
" lock_file varchar(32),"
" unique_name varchar(32)"
")"
)
except sqlite3.OperationalError:
pass
else:
self.connection.commit()
import atexit
atexit.register(os.unlink, SQLiteLockFile.testdb)
def acquire(self, timeout=None):
@@ -68,32 +73,35 @@ class SQLiteLockFile(LockBase):
while True:
if not self.is_locked():
# Not locked. Try to lock it.
cursor.execute("insert into locks"
" (lock_file, unique_name)"
" values"
" (?, ?)",
(self.lock_file, self.unique_name))
cursor.execute(
"insert into locks"
" (lock_file, unique_name)"
" values"
" (?, ?)",
(self.lock_file, self.unique_name),
)
self.connection.commit()
# Check to see if we are the only lock holder.
cursor.execute("select * from locks"
" where unique_name = ?",
(self.unique_name,))
cursor.execute(
"select * from locks" " where unique_name = ?", (self.unique_name,)
)
rows = cursor.fetchall()
if len(rows) > 1:
# Nope. Someone else got there. Remove our lock.
cursor.execute("delete from locks"
" where unique_name = ?",
(self.unique_name,))
cursor.execute(
"delete from locks" " where unique_name = ?",
(self.unique_name,),
)
self.connection.commit()
else:
# Yup. We're done, so go home.
return
else:
# Check to see if we are the only lock holder.
cursor.execute("select * from locks"
" where unique_name = ?",
(self.unique_name,))
cursor.execute(
"select * from locks" " where unique_name = ?", (self.unique_name,)
)
rows = cursor.fetchall()
if len(rows) == 1:
# We're the locker, so go home.
@@ -103,9 +111,9 @@ class SQLiteLockFile(LockBase):
if timeout is not None and time.time() > end_time:
if timeout > 0:
# No more waiting.
raise LockTimeout("Timeout waiting to acquire"
" lock for %s" %
self.path)
raise LockTimeout(
"Timeout waiting to acquire" " lock for %s" % self.path
)
else:
# Someone else has the lock and we are impatient..
raise AlreadyLocked("%s is already locked" % self.path)
@@ -117,40 +125,38 @@ class SQLiteLockFile(LockBase):
if not self.is_locked():
raise NotLocked("%s is not locked" % self.path)
if not self.i_am_locking():
raise NotMyLock("%s is locked, but not by me (by %s)" %
(self.unique_name, self._who_is_locking()))
raise NotMyLock(
"%s is locked, but not by me (by %s)"
% (self.unique_name, self._who_is_locking())
)
cursor = self.connection.cursor()
cursor.execute("delete from locks"
" where unique_name = ?",
(self.unique_name,))
cursor.execute(
"delete from locks" " where unique_name = ?", (self.unique_name,)
)
self.connection.commit()
def _who_is_locking(self):
cursor = self.connection.cursor()
cursor.execute("select unique_name from locks"
" where lock_file = ?",
(self.lock_file,))
cursor.execute(
"select unique_name from locks" " where lock_file = ?", (self.lock_file,)
)
return cursor.fetchone()[0]
def is_locked(self):
cursor = self.connection.cursor()
cursor.execute("select * from locks"
" where lock_file = ?",
(self.lock_file,))
cursor.execute("select * from locks" " where lock_file = ?", (self.lock_file,))
rows = cursor.fetchall()
return not not rows
def i_am_locking(self):
cursor = self.connection.cursor()
cursor.execute("select * from locks"
" where lock_file = ?"
" and unique_name = ?",
(self.lock_file, self.unique_name))
cursor.execute(
"select * from locks" " where lock_file = ?" " and unique_name = ?",
(self.lock_file, self.unique_name),
)
return not not cursor.fetchall()
def break_lock(self):
cursor = self.connection.cursor()
cursor.execute("delete from locks"
" where lock_file = ?",
(self.lock_file,))
cursor.execute("delete from locks" " where lock_file = ?", (self.lock_file,))
self.connection.commit()
+9 -9
View File
@@ -3,8 +3,7 @@ from __future__ import absolute_import
import os
import time
from . import (LockBase, NotLocked, NotMyLock, LockTimeout,
AlreadyLocked)
from . import LockBase, NotLocked, NotMyLock, LockTimeout, AlreadyLocked
class SymlinkLockFile(LockBase):
@@ -40,12 +39,11 @@ class SymlinkLockFile(LockBase):
# Otherwise the lock creation failed.
if timeout is not None and time.time() > end_time:
if timeout > 0:
raise LockTimeout("Timeout waiting to acquire"
" lock for %s" %
self.path)
raise LockTimeout(
"Timeout waiting to acquire" " lock for %s" % self.path
)
else:
raise AlreadyLocked("%s is already locked" %
self.path)
raise AlreadyLocked("%s is already locked" % self.path)
time.sleep(timeout / 10 if timeout is not None else 0.1)
else:
# Link creation succeeded. We're good to go.
@@ -62,8 +60,10 @@ class SymlinkLockFile(LockBase):
return os.path.islink(self.lock_file)
def i_am_locking(self):
return (os.path.islink(self.lock_file)
and os.readlink(self.lock_file) == self.unique_name)
return (
os.path.islink(self.lock_file)
and os.readlink(self.lock_file) == self.unique_name
)
def break_lock(self):
if os.path.islink(self.lock_file): # exists && link