Source code for timelinelib.wxgui.frames.mainframe.lockhandler

# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018  Rickard Lindberg, Roger Lindberg
#
# This file is part of Timeline.
#
# Timeline is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Timeline is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Timeline.  If not, see <http://www.gnu.org/licenses/>.


import getpass
import os

from timelinelib.wxgui.utils import display_warning_message


[docs]class LockedException(Exception): pass
[docs]class LockHandler: """ This class is a helper for handling locking of a timeline file. Whenever a timeline is edited, a lock is created so that no one else can edit the same timeline file at the same time. If you try to edit a timeline file that has a lock on it, a warning message will be displayed. When the edit is done, the lock is removed. The lock is accomplished by creating a file in the same directory and with the same name as the timeline file, byt with the extra extension '.lock'. The removal of this file releases the lock. The LockHandler is created and "owned" by the :class:`~timelinelib.wxgui.frames.mainframe.mainframecontroller.MainFrameController` class. """
[docs] def __init__(self, main_frame): self._main_frame = main_frame self._path = None self._pid = None
[docs] def locked(self, path): """Return True if there exists a lock for the given path (timeline).""" self._path = path return os.path.exists(self._get_lockpath())
[docs] def the_lock_is_mine(self, path): """Return True if you are the owner of the lock on path (timeline)""" self._path = path try: with open(self._get_lockpath(), "r") as fp: lines = fp.readlines() lines = [line.strip() for line in lines] return lines[0] == getpass.getuser() and lines[2] == f"{os.getpid()}" except: return False
[docs] def lock(self, path, timeline): """ Lock the timeline with the given path. The lock is accomplished by creating a file with the name path + '.lock'. Three lines of information is written to the file: * The user name * A timestamp when the lock was created * The id of the process in which Timeline is running """ self._path = path if not timeline.get_should_lock(): return try: ts = timeline.get_timestamp_string() self._pid = os.getpid() with open(self._get_lockpath(), "w") as fp: fp.write(f"{getpass.getuser()}\n{ts}\n{self._pid}") except Exception as ex: print(ex) msg = _( "Unable to take lock on %s\nThis means you can't edit the timeline.\nCheck if you have write access to this directory.") % self._path display_warning_message(msg, self._main_frame) raise LockedException()
[docs] def unlock(self, path): """ Remove the lock on the timeline pointed out by path. That is remove the lock file. """ self._path = path lockpath = self._get_lockpath() if os.path.exists(lockpath): try: os.remove(lockpath) self._path = None except WindowsError as ex: if ex.winerror == 32: self._report_other_process_uses_lockfile(lockpath) else: raise ex
def _get_lockpath(self): return f"{self._path}.lock" def _report_other_process_uses_lockfile(self, lockpath): message = _(f"""The lockfile used to protect the timeline from concurrent updates is opened by another program or process. This lockfile must be removed in order be able to continue editing the timeline! The lockfile is found at: {lockpath}""") display_warning_message(message, self._main_frame)