Skip to content
Permalink
Browse files
[webkitcorepy] Move FileLock from webkitpy
https://bugs.webkit.org/show_bug.cgi?id=230320
<rdar://problem/83168826>

Reviewed by Dewei Zhu.

Move FileLock from webkitpy into webkitcorepy, implement FileLock as a more
modern Python API.

* Scripts/libraries/webkitcorepy/setup.py: Bump version.
* Scripts/libraries/webkitcorepy/webkitcorepy/__init__.py: Ditto.
* Scripts/libraries/webkitcorepy/webkitcorepy/file_lock.py: Added.
(FileLock):
(FileLock.__init__):
(FileLock.acquired): Check if the current process has acquired the lock.
(FileLock.acquire): Attempt to acquire lockfile.
(FileLock.release): Release lockfile, if this process owns the lock.
(FileLock.__enter__): Invoke acquire.
(FileLock.__exit__): Invoke release.
* Scripts/libraries/webkitcorepy/webkitcorepy/mocks/__init__.py:
* Scripts/libraries/webkitcorepy/webkitcorepy/mocks/file_lock.py: Copied from Tools/Scripts/libraries/webkitcorepy/webkitcorepy/mocks/__init__.py.
(FileLock): Single-thread stub implementation of FileLock for testing without a filesystem.
* Scripts/libraries/webkitcorepy/webkitcorepy/tests/file_lock_unittest.py: Added.
(FileLockTestCase):
(FileLockTestCase.__init__):
(FileLockTestCase.setUp):
(FileLockTestCase.tearDown):
(FileLockTestCase.test_basic):
(FileLockTestCase.test_locked):
(FileLockTestCase.test_locked_timeout):
(FileLockTestCase.test_double):
* Scripts/webkitpy/common/system/file_lock.py: Removed.
* Scripts/webkitpy/common/system/file_lock_integrationtest.py: Removed.
* Scripts/webkitpy/common/system/systemhost.py:
(SystemHost.make_file_lock): Use webkitcorepy's FileLock.
* Scripts/webkitpy/common/system/systemhost_mock.py:
(MockSystemHost.make_file_lock): Use webkitcorepy's mocks.FileLock.
* Scripts/webkitpy/tool/commands/rebaseline.py:
(RebaselineTest._update_expectations_file): Use webkitcorepy's FileLock.


Canonical link: https://commits.webkit.org/241905@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@282770 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
JonWBedard committed Sep 20, 2021
1 parent cdd2107 commit d70bb966e4f5d7fa40ca913716d97fa981fdcb7f
@@ -1,3 +1,45 @@
2021-09-20 Jonathan Bedard <jbedard@apple.com>

[webkitcorepy] Move FileLock from webkitpy
https://bugs.webkit.org/show_bug.cgi?id=230320
<rdar://problem/83168826>

Reviewed by Dewei Zhu.

Move FileLock from webkitpy into webkitcorepy, implement FileLock as a more
modern Python API.

* Scripts/libraries/webkitcorepy/setup.py: Bump version.
* Scripts/libraries/webkitcorepy/webkitcorepy/__init__.py: Ditto.
* Scripts/libraries/webkitcorepy/webkitcorepy/file_lock.py: Added.
(FileLock):
(FileLock.__init__):
(FileLock.acquired): Check if the current process has acquired the lock.
(FileLock.acquire): Attempt to acquire lockfile.
(FileLock.release): Release lockfile, if this process owns the lock.
(FileLock.__enter__): Invoke acquire.
(FileLock.__exit__): Invoke release.
* Scripts/libraries/webkitcorepy/webkitcorepy/mocks/__init__.py:
* Scripts/libraries/webkitcorepy/webkitcorepy/mocks/file_lock.py: Copied from Tools/Scripts/libraries/webkitcorepy/webkitcorepy/mocks/__init__.py.
(FileLock): Single-thread stub implementation of FileLock for testing without a filesystem.
* Scripts/libraries/webkitcorepy/webkitcorepy/tests/file_lock_unittest.py: Added.
(FileLockTestCase):
(FileLockTestCase.__init__):
(FileLockTestCase.setUp):
(FileLockTestCase.tearDown):
(FileLockTestCase.test_basic):
(FileLockTestCase.test_locked):
(FileLockTestCase.test_locked_timeout):
(FileLockTestCase.test_double):
* Scripts/webkitpy/common/system/file_lock.py: Removed.
* Scripts/webkitpy/common/system/file_lock_integrationtest.py: Removed.
* Scripts/webkitpy/common/system/systemhost.py:
(SystemHost.make_file_lock): Use webkitcorepy's FileLock.
* Scripts/webkitpy/common/system/systemhost_mock.py:
(MockSystemHost.make_file_lock): Use webkitcorepy's mocks.FileLock.
* Scripts/webkitpy/tool/commands/rebaseline.py:
(RebaselineTest._update_expectations_file): Use webkitcorepy's FileLock.

2021-09-20 Brent Fulgham <bfulgham@apple.com>

Remove XSS Auditor: Part 1 (Turn off by default)
@@ -30,7 +30,7 @@ def readme():

setup(
name='webkitcorepy',
version='0.10.3',
version='0.11.0',
description='Library containing various Python support classes and functions.',
long_description=readme(),
classifiers=[
@@ -41,8 +41,9 @@
from webkitcorepy.nested_fuzzy_dict import NestedFuzzyDict
from webkitcorepy.call_by_need import CallByNeed
from webkitcorepy.editor import Editor
from webkitcorepy.file_lock import FileLock

version = Version(0, 10, 3)
version = Version(0, 11, 0)

from webkitcorepy.autoinstall import Package, AutoInstall
if sys.version_info > (3, 0):
@@ -0,0 +1,85 @@
# Copyright (C) 2010 Gabor Rapcsanyi (rgabor@inf.u-szeged.hu), University of Szeged
# Copyright (C) 2021 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import os
import sys
import time

if sys.platform.startswith('win'):
import msvcrt
else:
import fcntl


class FileLock(object):

def __init__(self, path, timeout=20):
self.path = path
self.timeout = timeout
self._descriptor = None

@property
def acquired(self):
return bool(self._descriptor)

def acquire(self):
if self._descriptor:
return True

descriptor = os.open(self.path, os.O_TRUNC | os.O_CREAT)
start_time = time.time()
while True:
try:
if sys.platform.startswith('win'):
msvcrt.locking(descriptor, msvcrt.LK_NBLCK, 32)
else:
fcntl.flock(descriptor, fcntl.LOCK_EX | fcntl.LOCK_NB)
self._descriptor = descriptor
return True

except IOError:
if time.time() - start_time > self.timeout:
os.close(descriptor)
self._descriptor = None
return False
time.sleep(0.01)

def release(self):
try:
if self._descriptor:
if sys.platform.startswith('win'):
msvcrt.locking(self._descriptor, msvcrt.LK_UNLCK, 32)
else:
fcntl.flock(self._descriptor, fcntl.LOCK_UN)
os.close(self._descriptor)
self._descriptor = None
os.unlink(self.path)
except (IOError, OSError):
pass

def __enter__(self):
self.acquire()
return self

def __exit__(self, *args, **kwargs):
self.release()
@@ -26,3 +26,4 @@

from webkitcorepy.mocks.requests_ import Response, Requests
from webkitcorepy.mocks.terminal import Terminal
from webkitcorepy.mocks.file_lock import FileLock
@@ -0,0 +1,46 @@
# Copyright (C) 2021 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


class FileLock(object):
def __init__(self, path, timeout=20):
self.path = path
self.timeout = timeout
self._acquired = False

@property
def acquired(self):
return self._acquired

def acquire(self):
self._acquired = True
return True

def release(self):
self._acquired = False

def __enter__(self):
self.acquire()
return self

def __exit__(self, *args, **kwargs):
self.release()
@@ -0,0 +1,115 @@
# Copyright (C) 2021 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import os
import shutil
import tempfile
import time
import unittest

from webkitcorepy import FileLock, mocks


class FileLockTestCase(unittest.TestCase):

def __init__(self, *args, **kwargs):
super(FileLockTestCase, self).__init__(*args, **kwargs)
self.path = None

def setUp(self):
self.path = tempfile.mkdtemp()

def tearDown(self):
shutil.rmtree(self.path, ignore_errors=True)

def test_basic(self):
path = os.path.join(self.path, 'example-{}.lock'.format(os.getpid()))
lock = FileLock(path, timeout=0)

self.assertFalse(lock.acquired)
with lock:
self.assertTrue(lock.acquired)
self.assertFalse(lock.acquired)

with lock:
self.assertTrue(lock.acquired)
self.assertFalse(lock.acquired)

def test_locked(self):
path = os.path.join(self.path, 'example-{}.lock'.format(os.getpid()))
lock_a = FileLock(path, timeout=0)
lock_b = FileLock(path, timeout=0)

self.assertFalse(lock_a.acquired)
self.assertFalse(lock_b.acquired)

with lock_a:
self.assertTrue(lock_a.acquired)
self.assertFalse(lock_b.acquired)

with lock_b:
self.assertTrue(lock_a.acquired)
self.assertFalse(lock_b.acquired)

self.assertTrue(lock_a.acquired)
self.assertFalse(lock_b.acquired)

self.assertFalse(lock_a.acquired)
self.assertFalse(lock_b.acquired)

def test_locked_timeout(self):
with mocks.Time:
path = os.path.join(self.path, 'example-{}.lock'.format(os.getpid()))
lock_a = FileLock(path, timeout=0)
lock_b = FileLock(path, timeout=30)

self.assertFalse(lock_a.acquired)
self.assertFalse(lock_b.acquired)

start_time = int(time.time())
with lock_a:
self.assertEqual(start_time, int(time.time()))
self.assertTrue(lock_a.acquired)
self.assertFalse(lock_b.acquired)

with lock_b:
self.assertEqual(start_time + 30, int(time.time()))
self.assertTrue(lock_a.acquired)
self.assertFalse(lock_b.acquired)

self.assertTrue(lock_a.acquired)
self.assertFalse(lock_b.acquired)

self.assertFalse(lock_a.acquired)
self.assertFalse(lock_b.acquired)

def test_double(self):
path = os.path.join(self.path, 'example-{}.lock'.format(os.getpid()))
lock = FileLock(path, timeout=0)

self.assertFalse(lock.acquired)
with lock:
self.assertTrue(lock.acquired)
with lock:
self.assertTrue(lock.acquired)
self.assertFalse(lock.acquired)
self.assertFalse(lock.acquired)

0 comments on commit d70bb96

Please sign in to comment.