diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/python/atomicwrites | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/python/atomicwrites')
-rw-r--r-- | third_party/python/atomicwrites/LICENSE | 19 | ||||
-rw-r--r-- | third_party/python/atomicwrites/MANIFEST.in | 6 | ||||
-rw-r--r-- | third_party/python/atomicwrites/PKG-INFO | 112 | ||||
-rw-r--r-- | third_party/python/atomicwrites/README.rst | 102 | ||||
-rw-r--r-- | third_party/python/atomicwrites/atomicwrites/__init__.py | 201 | ||||
-rw-r--r-- | third_party/python/atomicwrites/setup.cfg | 8 | ||||
-rw-r--r-- | third_party/python/atomicwrites/setup.py | 27 |
7 files changed, 475 insertions, 0 deletions
diff --git a/third_party/python/atomicwrites/LICENSE b/third_party/python/atomicwrites/LICENSE new file mode 100644 index 0000000000..3bbadc3af2 --- /dev/null +++ b/third_party/python/atomicwrites/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015-2016 Markus Unterwaditzer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/third_party/python/atomicwrites/MANIFEST.in b/third_party/python/atomicwrites/MANIFEST.in new file mode 100644 index 0000000000..1b28469174 --- /dev/null +++ b/third_party/python/atomicwrites/MANIFEST.in @@ -0,0 +1,6 @@ +include LICENSE +include README.rst + +recursive-include docs * +recursive-include tests * +prune docs/_build diff --git a/third_party/python/atomicwrites/PKG-INFO b/third_party/python/atomicwrites/PKG-INFO new file mode 100644 index 0000000000..eec6b7c305 --- /dev/null +++ b/third_party/python/atomicwrites/PKG-INFO @@ -0,0 +1,112 @@ +Metadata-Version: 1.0 +Name: atomicwrites +Version: 1.1.5 +Summary: Atomic file writes. +Home-page: https://github.com/untitaker/python-atomicwrites +Author: Markus Unterwaditzer +Author-email: markus@unterwaditzer.net +License: MIT +Description: =================== + python-atomicwrites + =================== + + .. image:: https://travis-ci.org/untitaker/python-atomicwrites.svg?branch=master + :target: https://travis-ci.org/untitaker/python-atomicwrites + + .. image:: https://ci.appveyor.com/api/projects/status/vadc4le3c27to59x/branch/master?svg=true + :target: https://ci.appveyor.com/project/untitaker/python-atomicwrites/branch/master + + Atomic file writes. + + .. code-block:: python + + from atomicwrites import atomic_write + + with atomic_write('foo.txt', overwrite=True) as f: + f.write('Hello world.') + # "foo.txt" doesn't exist yet. + + # Now it does. + + + Features that distinguish it from other similar libraries (see `Alternatives and Credit`_): + + - Race-free assertion that the target file doesn't yet exist. This can be + controlled with the ``overwrite`` parameter. + + - Windows support, although not well-tested. The MSDN resources are not very + explicit about which operations are atomic. + + - Simple high-level API that wraps a very flexible class-based API. + + - Consistent error handling across platforms. + + + How it works + ============ + + It uses a temporary file in the same directory as the given path. This ensures + that the temporary file resides on the same filesystem. + + The temporary file will then be atomically moved to the target location: On + POSIX, it will use ``rename`` if files should be overwritten, otherwise a + combination of ``link`` and ``unlink``. On Windows, it uses MoveFileEx_ through + stdlib's ``ctypes`` with the appropriate flags. + + Note that with ``link`` and ``unlink``, there's a timewindow where the file + might be available under two entries in the filesystem: The name of the + temporary file, and the name of the target file. + + Also note that the permissions of the target file may change this way. In some + situations a ``chmod`` can be issued without any concurrency problems, but + since that is not always the case, this library doesn't do it by itself. + + .. _MoveFileEx: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365240%28v=vs.85%29.aspx + + fsync + ----- + + On POSIX, ``fsync`` is invoked on the temporary file after it is written (to + flush file content and metadata), and on the parent directory after the file is + moved (to flush filename). + + ``fsync`` does not take care of disks' internal buffers, but there don't seem + to be any standard POSIX APIs for that. On OS X, ``fcntl`` is used with + ``F_FULLFSYNC`` instead of ``fsync`` for that reason. + + On Windows, `_commit <https://msdn.microsoft.com/en-us/library/17618685.aspx>`_ + is used, but there are no guarantees about disk internal buffers. + + Alternatives and Credit + ======================= + + Atomicwrites is directly inspired by the following libraries (and shares a + minimal amount of code): + + - The Trac project's `utility functions + <http://www.edgewall.org/docs/tags-trac-0.11.7/epydoc/trac.util-pysrc.html>`_, + also used in `Werkzeug <http://werkzeug.pocoo.org/>`_ and + `mitsuhiko/python-atomicfile + <https://github.com/mitsuhiko/python-atomicfile>`_. The idea to use + ``ctypes`` instead of ``PyWin32`` originated there. + + - `abarnert/fatomic <https://github.com/abarnert/fatomic>`_. Windows support + (based on ``PyWin32``) was originally taken from there. + + Other alternatives to atomicwrites include: + + - `sashka/atomicfile <https://github.com/sashka/atomicfile>`_. Originally I + considered using that, but at the time it was lacking a lot of features I + needed (Windows support, overwrite-parameter, overriding behavior through + subclassing). + + - The `Boltons library collection <https://github.com/mahmoud/boltons>`_ + features a class for atomic file writes, which seems to have a very similar + ``overwrite`` parameter. It is lacking Windows support though. + + License + ======= + + Licensed under the MIT, see ``LICENSE``. + +Platform: UNKNOWN diff --git a/third_party/python/atomicwrites/README.rst b/third_party/python/atomicwrites/README.rst new file mode 100644 index 0000000000..3a5658cbd8 --- /dev/null +++ b/third_party/python/atomicwrites/README.rst @@ -0,0 +1,102 @@ +=================== +python-atomicwrites +=================== + +.. image:: https://travis-ci.org/untitaker/python-atomicwrites.svg?branch=master + :target: https://travis-ci.org/untitaker/python-atomicwrites + +.. image:: https://ci.appveyor.com/api/projects/status/vadc4le3c27to59x/branch/master?svg=true + :target: https://ci.appveyor.com/project/untitaker/python-atomicwrites/branch/master + +Atomic file writes. + +.. code-block:: python + + from atomicwrites import atomic_write + + with atomic_write('foo.txt', overwrite=True) as f: + f.write('Hello world.') + # "foo.txt" doesn't exist yet. + + # Now it does. + + +Features that distinguish it from other similar libraries (see `Alternatives and Credit`_): + +- Race-free assertion that the target file doesn't yet exist. This can be + controlled with the ``overwrite`` parameter. + +- Windows support, although not well-tested. The MSDN resources are not very + explicit about which operations are atomic. + +- Simple high-level API that wraps a very flexible class-based API. + +- Consistent error handling across platforms. + + +How it works +============ + +It uses a temporary file in the same directory as the given path. This ensures +that the temporary file resides on the same filesystem. + +The temporary file will then be atomically moved to the target location: On +POSIX, it will use ``rename`` if files should be overwritten, otherwise a +combination of ``link`` and ``unlink``. On Windows, it uses MoveFileEx_ through +stdlib's ``ctypes`` with the appropriate flags. + +Note that with ``link`` and ``unlink``, there's a timewindow where the file +might be available under two entries in the filesystem: The name of the +temporary file, and the name of the target file. + +Also note that the permissions of the target file may change this way. In some +situations a ``chmod`` can be issued without any concurrency problems, but +since that is not always the case, this library doesn't do it by itself. + +.. _MoveFileEx: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365240%28v=vs.85%29.aspx + +fsync +----- + +On POSIX, ``fsync`` is invoked on the temporary file after it is written (to +flush file content and metadata), and on the parent directory after the file is +moved (to flush filename). + +``fsync`` does not take care of disks' internal buffers, but there don't seem +to be any standard POSIX APIs for that. On OS X, ``fcntl`` is used with +``F_FULLFSYNC`` instead of ``fsync`` for that reason. + +On Windows, `_commit <https://msdn.microsoft.com/en-us/library/17618685.aspx>`_ +is used, but there are no guarantees about disk internal buffers. + +Alternatives and Credit +======================= + +Atomicwrites is directly inspired by the following libraries (and shares a +minimal amount of code): + +- The Trac project's `utility functions + <http://www.edgewall.org/docs/tags-trac-0.11.7/epydoc/trac.util-pysrc.html>`_, + also used in `Werkzeug <http://werkzeug.pocoo.org/>`_ and + `mitsuhiko/python-atomicfile + <https://github.com/mitsuhiko/python-atomicfile>`_. The idea to use + ``ctypes`` instead of ``PyWin32`` originated there. + +- `abarnert/fatomic <https://github.com/abarnert/fatomic>`_. Windows support + (based on ``PyWin32``) was originally taken from there. + +Other alternatives to atomicwrites include: + +- `sashka/atomicfile <https://github.com/sashka/atomicfile>`_. Originally I + considered using that, but at the time it was lacking a lot of features I + needed (Windows support, overwrite-parameter, overriding behavior through + subclassing). + +- The `Boltons library collection <https://github.com/mahmoud/boltons>`_ + features a class for atomic file writes, which seems to have a very similar + ``overwrite`` parameter. It is lacking Windows support though. + +License +======= + +Licensed under the MIT, see ``LICENSE``. diff --git a/third_party/python/atomicwrites/atomicwrites/__init__.py b/third_party/python/atomicwrites/atomicwrites/__init__.py new file mode 100644 index 0000000000..a182c07afd --- /dev/null +++ b/third_party/python/atomicwrites/atomicwrites/__init__.py @@ -0,0 +1,201 @@ +import contextlib +import os +import sys +import tempfile + +try: + import fcntl +except ImportError: + fcntl = None + +__version__ = '1.1.5' + + +PY2 = sys.version_info[0] == 2 + +text_type = unicode if PY2 else str # noqa + + +def _path_to_unicode(x): + if not isinstance(x, text_type): + return x.decode(sys.getfilesystemencoding()) + return x + + +_proper_fsync = os.fsync + + +if sys.platform != 'win32': + if hasattr(fcntl, 'F_FULLFSYNC'): + def _proper_fsync(fd): + # https://lists.apple.com/archives/darwin-dev/2005/Feb/msg00072.html + # https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/fsync.2.html + # https://github.com/untitaker/python-atomicwrites/issues/6 + fcntl.fcntl(fd, fcntl.F_FULLFSYNC) + + def _sync_directory(directory): + # Ensure that filenames are written to disk + fd = os.open(directory, 0) + try: + _proper_fsync(fd) + finally: + os.close(fd) + + def _replace_atomic(src, dst): + os.rename(src, dst) + _sync_directory(os.path.normpath(os.path.dirname(dst))) + + def _move_atomic(src, dst): + os.link(src, dst) + os.unlink(src) + + src_dir = os.path.normpath(os.path.dirname(src)) + dst_dir = os.path.normpath(os.path.dirname(dst)) + _sync_directory(dst_dir) + if src_dir != dst_dir: + _sync_directory(src_dir) +else: + from ctypes import windll, WinError + + _MOVEFILE_REPLACE_EXISTING = 0x1 + _MOVEFILE_WRITE_THROUGH = 0x8 + _windows_default_flags = _MOVEFILE_WRITE_THROUGH + + def _handle_errors(rv): + if not rv: + raise WinError() + + def _replace_atomic(src, dst): + _handle_errors(windll.kernel32.MoveFileExW( + _path_to_unicode(src), _path_to_unicode(dst), + _windows_default_flags | _MOVEFILE_REPLACE_EXISTING + )) + + def _move_atomic(src, dst): + _handle_errors(windll.kernel32.MoveFileExW( + _path_to_unicode(src), _path_to_unicode(dst), + _windows_default_flags + )) + + +def replace_atomic(src, dst): + ''' + Move ``src`` to ``dst``. If ``dst`` exists, it will be silently + overwritten. + + Both paths must reside on the same filesystem for the operation to be + atomic. + ''' + return _replace_atomic(src, dst) + + +def move_atomic(src, dst): + ''' + Move ``src`` to ``dst``. There might a timewindow where both filesystem + entries exist. If ``dst`` already exists, :py:exc:`FileExistsError` will be + raised. + + Both paths must reside on the same filesystem for the operation to be + atomic. + ''' + return _move_atomic(src, dst) + + +class AtomicWriter(object): + ''' + A helper class for performing atomic writes. Usage:: + + with AtomicWriter(path).open() as f: + f.write(...) + + :param path: The destination filepath. May or may not exist. + :param mode: The filemode for the temporary file. + :param overwrite: If set to false, an error is raised if ``path`` exists. + Errors are only raised after the file has been written to. Either way, + the operation is atomic. + + If you need further control over the exact behavior, you are encouraged to + subclass. + ''' + + def __init__(self, path, mode='w', overwrite=False): + if 'a' in mode: + raise ValueError( + 'Appending to an existing file is not supported, because that ' + 'would involve an expensive `copy`-operation to a temporary ' + 'file. Open the file in normal `w`-mode and copy explicitly ' + 'if that\'s what you\'re after.' + ) + if 'x' in mode: + raise ValueError('Use the `overwrite`-parameter instead.') + if 'w' not in mode: + raise ValueError('AtomicWriters can only be written to.') + + self._path = path + self._mode = mode + self._overwrite = overwrite + + def open(self): + ''' + Open the temporary file. + ''' + return self._open(self.get_fileobject) + + @contextlib.contextmanager + def _open(self, get_fileobject): + f = None # make sure f exists even if get_fileobject() fails + try: + success = False + with get_fileobject() as f: + yield f + self.sync(f) + self.commit(f) + success = True + finally: + if not success: + try: + self.rollback(f) + except Exception: + pass + + def get_fileobject(self, dir=None, **kwargs): + '''Return the temporary file to use.''' + if dir is None: + dir = os.path.normpath(os.path.dirname(self._path)) + return tempfile.NamedTemporaryFile(mode=self._mode, dir=dir, + delete=False, **kwargs) + + def sync(self, f): + '''responsible for clearing as many file caches as possible before + commit''' + f.flush() + _proper_fsync(f.fileno()) + + def commit(self, f): + '''Move the temporary file to the target location.''' + if self._overwrite: + replace_atomic(f.name, self._path) + else: + move_atomic(f.name, self._path) + + def rollback(self, f): + '''Clean up all temporary resources.''' + os.unlink(f.name) + + +def atomic_write(path, writer_cls=AtomicWriter, **cls_kwargs): + ''' + Simple atomic writes. This wraps :py:class:`AtomicWriter`:: + + with atomic_write(path) as f: + f.write(...) + + :param path: The target path to write to. + :param writer_cls: The writer class to use. This parameter is useful if you + subclassed :py:class:`AtomicWriter` to change some behavior and want to + use that new subclass. + + Additional keyword arguments are passed to the writer class. See + :py:class:`AtomicWriter`. + ''' + return writer_cls(path, **cls_kwargs).open() diff --git a/third_party/python/atomicwrites/setup.cfg b/third_party/python/atomicwrites/setup.cfg new file mode 100644 index 0000000000..3e89eac2c0 --- /dev/null +++ b/third_party/python/atomicwrites/setup.cfg @@ -0,0 +1,8 @@ +[wheel] +universal = 1 + +[egg_info] +tag_date = 0 +tag_svn_revision = 0 +tag_build = + diff --git a/third_party/python/atomicwrites/setup.py b/third_party/python/atomicwrites/setup.py new file mode 100644 index 0000000000..98488e9b98 --- /dev/null +++ b/third_party/python/atomicwrites/setup.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- + +import ast +import re + +from setuptools import find_packages, setup + + +_version_re = re.compile(r'__version__\s+=\s+(.*)') + + +with open('atomicwrites/__init__.py', 'rb') as f: + version = str(ast.literal_eval(_version_re.search( + f.read().decode('utf-8')).group(1))) + +setup( + name='atomicwrites', + version=version, + author='Markus Unterwaditzer', + author_email='markus@unterwaditzer.net', + url='https://github.com/untitaker/python-atomicwrites', + description='Atomic file writes.', + license='MIT', + long_description=open('README.rst').read(), + packages=find_packages(exclude=['tests.*', 'tests']), + include_package_data=True, +) |