summaryrefslogtreecommitdiffstats
path: root/third_party/python/atomicwrites
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/python/atomicwrites
parentInitial commit. (diff)
downloadfirefox-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/LICENSE19
-rw-r--r--third_party/python/atomicwrites/MANIFEST.in6
-rw-r--r--third_party/python/atomicwrites/PKG-INFO112
-rw-r--r--third_party/python/atomicwrites/README.rst102
-rw-r--r--third_party/python/atomicwrites/atomicwrites/__init__.py201
-rw-r--r--third_party/python/atomicwrites/setup.cfg8
-rw-r--r--third_party/python/atomicwrites/setup.py27
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,
+)