[Git][debian-gis-team/mapproxy][master] 4 commits: New upstream version 3.1.1+dfsg

Bas Couwenberg (@sebastic) gitlab at salsa.debian.org
Fri Nov 15 12:02:01 GMT 2024



Bas Couwenberg pushed to branch master at Debian GIS Project / mapproxy


Commits:
c71966c6 by Bas Couwenberg at 2024-11-15T12:51:13+01:00
New upstream version 3.1.1+dfsg
- - - - -
73068f18 by Bas Couwenberg at 2024-11-15T12:51:16+01:00
Update upstream source from tag 'upstream/3.1.1+dfsg'

Update to upstream version '3.1.1+dfsg'
with Debian dir a7d2f31b26f71c239b76697264a8d5cd8f17fbf1
- - - - -
fb73a7e0 by Bas Couwenberg at 2024-11-15T12:51:33+01:00
New upstream release.

- - - - -
0cbe6ae2 by Bas Couwenberg at 2024-11-15T12:52:35+01:00
Set distribution to unstable.

- - - - -


14 changed files:

- CHANGES.txt
- RELEASE.txt
- debian/changelog
- doc/coverages.rst
- mapproxy/cache/base.py
- mapproxy/cache/compact.py
- mapproxy/cache/geopackage.py
- mapproxy/cache/mbtiles.py
- mapproxy/config/loader.py
- mapproxy/seed/config.py
- mapproxy/test/unit/test_utils.py
- mapproxy/util/ext/lockfile.py
- mapproxy/util/lock.py
- setup.py


Changes:

=====================================
CHANGES.txt
=====================================
@@ -1,3 +1,15 @@
+3.1.1 2024-11-15
+~~~~~~~~~~~~~~~~
+
+Maintenance:
+
+  - Werkzeug version is no longer pinned and can be chosen freely.
+
+Fixes:
+
+  - The permission handling for file locks now also sets permissions on the files not just on the directories.
+
+
 3.1.0 2024-10-22
 ~~~~~~~~~~~~~~~~
 


=====================================
RELEASE.txt
=====================================
@@ -4,16 +4,16 @@ Making a new MapProxy release
 Preparation
 -----------
 
+- Stash changes, checkout `master` and pull all changes (`git stash && git checkout master && git pull`)
 - Update CHANGES.txt with all important changes. Verify version and date in header line.
-  - You can use the git compare function for that, e.g.:
-    - https://github.com/mapproxy/mapproxy/compare/2.0.2...master
+  IMPORTANT: Be careful to have the proper amount of blank lines.
+  You can use the git compare function for that, e.g.: https://github.com/mapproxy/mapproxy/compare/2.0.2...master
 - Update version in `setup.py`.
-- Commit and push updates (`git commit -m 'dev: prepare 2.0.2 release'`, `git push`)
-- Create tag and push tag (`git tag 2.0.2`, `git push --tags`)
+- Commit and push updates (`git add -A && git commit -m 'dev: prepare 2.0.2 release' && git push`)
+- Create tag and push tag (`git tag 2.0.2 && git push --tags`)
 
 
 Build and upload
 ----------------
 
 - The release on PyPI and the docker images will be created automatically.
-


=====================================
debian/changelog
=====================================
@@ -1,3 +1,9 @@
+mapproxy (3.1.1+dfsg-1) unstable; urgency=medium
+
+  * New upstream release.
+
+ -- Bas Couwenberg <sebastic at debian.org>  Fri, 15 Nov 2024 12:52:24 +0100
+
 mapproxy (3.1.0+dfsg-1) unstable; urgency=medium
 
   * New upstream release.


=====================================
doc/coverages.rst
=====================================
@@ -41,7 +41,7 @@ All coverages are configured by defining the source of the coverage and the SRS.
 The configuration of the coverage depends on the type. The SRS can allways be configured with the ``srs`` option.
 
 .. versionadded:: 1.5.0
-    MapProxy can autodetect the type of the coverage. You can now use ``coverage`` instead of the ``bbox``, ``polygons`` or ``ogr_datasource`` option.
+    MapProxy can autodetect the type of the coverage. You can now use ``datasource`` instead of the ``bbox``, ``polygons`` or ``ogr_datasource`` option.
     The old options are still supported.
 
 Coverage Types


=====================================
mapproxy/cache/base.py
=====================================
@@ -98,11 +98,12 @@ if sys.platform == 'win32':
 
 
 class TileLocker(object):
-    def __init__(self, lock_dir, lock_timeout, lock_cache_id, directory_permissions=None):
+    def __init__(self, lock_dir, lock_timeout, lock_cache_id, directory_permissions=None, file_permissions=None):
         self.lock_dir = lock_dir
         self.lock_timeout = lock_timeout
         self.lock_cache_id = lock_cache_id
         self.directory_permissions = directory_permissions
+        self.file_permissions = file_permissions
 
     def lock_filename(self, tile):
         return os.path.join(self.lock_dir, self.lock_cache_id + '-' +
@@ -118,4 +119,5 @@ class TileLocker(object):
         cleanup_lockdir(self.lock_dir, max_lock_time=self.lock_timeout + 10,
                         force=False)
         return FileLock(lock_filename, timeout=self.lock_timeout,
-                        remove_on_unlock=REMOVE_ON_UNLOCK, directory_permissions=self.directory_permissions)
+                        remove_on_unlock=REMOVE_ON_UNLOCK, directory_permissions=self.directory_permissions,
+                        file_permissions=self.file_permissions)


=====================================
mapproxy/cache/compact.py
=====================================
@@ -192,7 +192,8 @@ class BundleV1(object):
                 data = buf.read()
             tiles_data.append((t.coord, data))
 
-        with FileLock(self.lock_filename, directory_permissions=self.directory_permissions, remove_on_unlock=True):
+        with FileLock(self.lock_filename, directory_permissions=self.directory_permissions,
+                      file_permissions=self.file_permissions, remove_on_unlock=True):
             with self.data().readwrite() as bundle:
                 with self.index().readwrite() as idx:
                     for tile_coord, data in tiles_data:
@@ -236,7 +237,8 @@ class BundleV1(object):
         if tile.coord is None:
             return True
 
-        with FileLock(self.lock_filename, directory_permissions=self.directory_permissions, remove_on_unlock=True):
+        with FileLock(self.lock_filename, directory_permissions=self.directory_permissions,
+                      file_permissions=self.file_permissions, remove_on_unlock=True):
             with self.index().readwrite() as idx:
                 x, y = self._rel_tile_coord(tile.coord)
                 idx.remove_tile_offset(x, y)
@@ -634,7 +636,8 @@ class BundleV2(object):
                 data = buf.read()
             tiles_data.append((t.coord, data))
 
-        with FileLock(self.lock_filename, directory_permissions=self.directory_permissions, remove_on_unlock=True):
+        with FileLock(self.lock_filename, directory_permissions=self.directory_permissions,
+                      file_permissions=self.file_permissions, remove_on_unlock=True):
             with self._readwrite() as fh:
                 for tile_coord, data in tiles_data:
                     self._store_tile(fh, tile_coord, data, dimensions=dimensions)
@@ -646,7 +649,8 @@ class BundleV2(object):
             return True
 
         self._init_index()
-        with FileLock(self.lock_filename, directory_permissions=self.directory_permissions, remove_on_unlock=True):
+        with FileLock(self.lock_filename, directory_permissions=self.directory_permissions,
+                      file_permissions=self.file_permissions, remove_on_unlock=True):
             with self._readwrite() as fh:
                 x, y = self._rel_tile_coord(tile.coord)
                 self._update_tile_offset(fh, x, y, 0, 0)


=====================================
mapproxy/cache/geopackage.py
=====================================
@@ -112,8 +112,8 @@ class GeopackageCache(TileCacheBase):
 
     def ensure_gpkg(self):
         if not os.path.isfile(self.geopackage_file):
-            with FileLock(self.geopackage_file + '.init.lck',
-                          remove_on_unlock=REMOVE_ON_UNLOCK, directory_permissions=self.directory_permissions):
+            with FileLock(self.geopackage_file + '.init.lck', remove_on_unlock=REMOVE_ON_UNLOCK,
+                          directory_permissions=self.directory_permissions, file_permissions=self.file_permissions):
                 ensure_directory(self.geopackage_file, self.directory_permissions)
                 self._initialize_gpkg()
         else:


=====================================
mapproxy/cache/mbtiles.py
=====================================
@@ -77,8 +77,8 @@ class MBTilesCache(TileCacheBase):
 
     def ensure_mbtile(self):
         if not os.path.exists(self.mbtile_file):
-            with FileLock(self.mbtile_file + '.init.lck',
-                          remove_on_unlock=REMOVE_ON_UNLOCK, directory_permissions=self.directory_permissions):
+            with FileLock(self.mbtile_file + '.init.lck', remove_on_unlock=REMOVE_ON_UNLOCK,
+                          directory_permissions=self.directory_permissions, file_permissions=self.file_permissions):
                 if not os.path.exists(self.mbtile_file):
                     ensure_directory(self.mbtile_file, self.directory_permissions)
                     self._initialize_mbtile()


=====================================
mapproxy/config/loader.py
=====================================
@@ -802,9 +802,24 @@ class WMSSourceConfiguration(SourceConfiguration):
             lock_dir = self.context.globals.get_path('cache.lock_dir', self.conf)
             lock_timeout = self.context.globals.get_value('http.client_timeout', self.conf)
             url = urlparse(self.conf['req']['url'])
+
+            global_directory_permissions = self.context.globals.get_value('directory_permissions', self.conf,
+                                                                          global_key='cache.directory_permissions')
+            if global_directory_permissions:
+                log.info(f'Using global directory permission configuration for concurrent file locks:'
+                         f' {global_directory_permissions}')
+
+            global_file_permissions = self.context.globals.get_value('file_permissions', self.conf,
+                                                                     global_key='cache.file_permissions')
+            if global_file_permissions:
+                log.info(f'Using global file permission configuration for concurrent file locks:'
+                         f' {global_file_permissions}')
+
             md5 = hashlib.new('md5', url.netloc.encode('ascii'), usedforsecurity=False)
             lock_file = os.path.join(lock_dir, md5.hexdigest() + '.lck')
-            lock = lambda: SemLock(lock_file, concurrent_requests, timeout=lock_timeout)  # noqa
+            lock = lambda: SemLock(lock_file, concurrent_requests, timeout=lock_timeout,  # noqa
+                                   directory_permissions=global_directory_permissions,
+                                   file_permissions=global_file_permissions)
 
         coverage = self.coverage()
         res_range = resolution_range(self.conf)
@@ -963,9 +978,24 @@ class MapnikSourceConfiguration(SourceConfiguration):
             from mapproxy.util.lock import SemLock
             lock_dir = self.context.globals.get_path('cache.lock_dir', self.conf)
             mapfile = self.conf['mapfile']
+
+            global_directory_permissions = self.context.globals.get_value('directory_permissions', self.conf,
+                                                                          global_key='cache.directory_permissions')
+            if global_directory_permissions:
+                log.info(f'Using global directory permission configuration for concurrent file locks:'
+                         f' {global_directory_permissions}')
+
+            global_file_permissions = self.context.globals.get_value('file_permissions', self.conf,
+                                                                     global_key='cache.file_permissions')
+            if global_file_permissions:
+                log.info(f'Using global file permission configuration for concurrent file locks:'
+                         f' {global_file_permissions}')
+
             md5 = hashlib.new('md5', mapfile.encode('utf-8'), usedforsecurity=False)
             lock_file = os.path.join(lock_dir, md5.hexdigest() + '.lck')
-            lock = lambda: SemLock(lock_file, concurrent_requests)  # noqa
+            lock = lambda: SemLock(lock_file, concurrent_requests, # noqa
+                                   directory_permissions=global_directory_permissions,
+                                   file_permissions=global_file_permissions)
 
         coverage = self.coverage()
         res_range = resolution_range(self.conf)
@@ -1761,9 +1791,16 @@ class CacheConfiguration(ConfigurationBase):
                     log.info(f'Using global directory permission configuration for tile locks:'
                              f' {global_directory_permissions}')
 
+                global_file_permissions = self.context.globals.get_value('file_permissions', self.conf,
+                                                                         global_key='cache.file_permissions')
+                if global_file_permissions:
+                    log.info(f'Using global file permission configuration for tile locks:'
+                             f' {global_file_permissions}')
+
                 lock_timeout = self.context.globals.get_value('http.client_timeout', {})
                 locker = TileLocker(lock_dir, lock_timeout, identifier + '_renderd',
-                                    global_directory_permissions)
+                                    directory_permissions=global_directory_permissions,
+                                    file_permissions=global_file_permissions)
                 # TODO band_merger
                 tile_creator_class = partial(RenderdTileCreator, renderd_address,
                                              priority=priority, tile_locker=locker)
@@ -1781,11 +1818,18 @@ class CacheConfiguration(ConfigurationBase):
                     log.info(f'Using global directory permission configuration for tile locks:'
                              f' {global_directory_permissions}')
 
+                global_file_permissions = self.context.globals.get_value('file_permissions', self.conf,
+                                                                         global_key='cache.file_permissions')
+                if global_file_permissions:
+                    log.info(f'Using global file permission configuration for tile locks:'
+                             f' {global_file_permissions}')
+
                 locker = TileLocker(
                     lock_dir=self.lock_dir(),
                     lock_timeout=self.context.globals.get_value('http.client_timeout', {}),
                     lock_cache_id=cache.lock_cache_id,
-                    directory_permissions=global_directory_permissions
+                    directory_permissions=global_directory_permissions,
+                    file_permissions=global_file_permissions
                 )
 
             mgr = TileManager(tile_grid, cache, sources, image_opts.format.ext,


=====================================
mapproxy/seed/config.py
=====================================
@@ -163,6 +163,8 @@ class SeedingConfiguration(object):
             raise SeedConfigurationError("invalid geometry in coverage '%s'. %s" % (name, ex))
         except EmptyGeometryError as ex:
             raise EmptyCoverageError("coverage '%s' contains no geometries. %s" % (name, ex))
+        except Exception:
+            raise Exception(f"can't load coverage '{name}'")
 
         # without extend we have an empty coverage
         if not coverage.extent.llbbox:


=====================================
mapproxy/test/unit/test_utils.py
=====================================
@@ -32,8 +32,7 @@ from mapproxy.util.fs import (
 )
 from mapproxy.util.py import reraise_exception
 from mapproxy.util.times import timestamp_before
-from mapproxy.test.helper import Mocker
-
+from mapproxy.test.helper import Mocker, assert_permissions
 
 is_win = sys.platform == "win32"
 
@@ -156,6 +155,35 @@ class TestFileLock(Mocker):
             x.unlock()
             assert not os.path.exists(self.lock_file)
 
+    def test_file_lock_permissions(self):
+        file_permissions = '775'
+
+        # Test a lock that becomes free during a waiting lock() call.
+        class Lock(threading.Thread):
+
+            def __init__(self, lock_file):
+                threading.Thread.__init__(self)
+                self.lock_file = lock_file
+                self.lock = FileLock(self.lock_file, file_permissions=file_permissions)
+
+            def run(self):
+                self.lock.lock()
+                time.sleep(0.2)
+                self.lock.unlock()
+
+        lock_thread = Lock(self.lock_file)
+        lock_thread.start()
+
+        # wait until thread got the locked
+        while not lock_thread.lock._locked:
+            time.sleep(0.001)
+
+        # one lock that times out
+        assert_locked(self.lock_file)
+        assert_permissions(self.lock_file, file_permissions)
+
+        lock_thread.join()
+
     def _create_lock(self):
         lock = FileLock(self.lock_file)
         lock.lock()


=====================================
mapproxy/util/ext/lockfile.py
=====================================
@@ -115,10 +115,13 @@ class LockFile:
 
     _fp = None
 
-    def __init__(self, path):
+    def __init__(self, path, file_permissions):
         self._path = path
         try:
             fp = open(path, 'w+')
+            if file_permissions:
+                permission = int(file_permissions, base=8)
+                os.chmod(path, permission)
         except IOError:
             raise Exception('Could not create Lock-file, wrong permissions on lock directory?')
 


=====================================
mapproxy/util/lock.py
=====================================
@@ -36,13 +36,15 @@ class LockTimeout(Exception):
 
 
 class FileLock(object):
-    def __init__(self, lock_file, timeout=60.0, step=0.01, remove_on_unlock=False, directory_permissions=None):
+    def __init__(self, lock_file, timeout=60.0, step=0.01, remove_on_unlock=False, directory_permissions=None,
+                 file_permissions=None):
         self.lock_file = lock_file
         self.timeout = timeout
         self.step = step
         self.remove_on_unlock = remove_on_unlock
         self._locked = False
         self.directory_permissions = directory_permissions
+        self.file_permissions = file_permissions
 
     def __enter__(self):
         self.lock()
@@ -51,7 +53,7 @@ class FileLock(object):
         self.unlock()
 
     def _try_lock(self):
-        return LockFile(self.lock_file)
+        return LockFile(self.lock_file, self.file_permissions)
 
     def lock(self):
         ensure_directory(self.lock_file, self.directory_permissions)
@@ -116,11 +118,10 @@ def cleanup_lockdir(lockdir, suffix='.lck', max_lock_time=300, force=True):
         try:
             if os.path.isfile(name) and name.endswith(suffix):
                 if os.path.getmtime(name) < expire_time:
-                    if os.stat(name).st_uid == os.getuid():
-                        try:
-                            os.unlink(name)
-                        except IOError as ex:
-                            log.warning('could not remove old lock file %s: %s', name, ex)
+                    try:
+                        os.unlink(name)
+                    except IOError as ex:
+                        log.warning('could not remove old lock file %s: %s', name, ex)
         except OSError as e:
             # some one might have removed the file (ENOENT)
             # or we don't have permissions to remove it (EACCES)
@@ -136,8 +137,9 @@ class SemLock(FileLock):
     File-lock-based counting semaphore (i.e. this lock can be locked n-times).
     """
 
-    def __init__(self, lock_file, n, timeout=60.0, step=0.01):
-        FileLock.__init__(self, lock_file, timeout=timeout, step=step)
+    def __init__(self, lock_file, n, timeout=60.0, step=0.01, directory_permissions=None, file_permissions=None):
+        FileLock.__init__(self, lock_file, timeout=timeout, step=step, directory_permissions=directory_permissions,
+                          file_permissions=file_permissions)
         self.n = n
 
     def _try_lock(self):
@@ -146,7 +148,7 @@ class SemLock(FileLock):
         while True:
             tries += 1
             try:
-                return LockFile(self.lock_file + str(i))
+                return LockFile(self.lock_file + str(i), self.file_permissions)
             except LockError:
                 if tries >= self.n:
                     raise


=====================================
setup.py
=====================================
@@ -10,7 +10,7 @@ install_requires = [
     'pyproj>=2',
     'jsonschema>=4',
     'importlib_resources;python_version<="3.8"',
-    'werkzeug==1.0.1'
+    'werkzeug<4'
 ]
 
 
@@ -63,11 +63,14 @@ def long_description(changelog_releases=10):
 
 setup(
     name='MapProxy',
-    version="3.1.0",
+    version="3.1.1",
     description='An accelerating proxy for tile and web map services',
     long_description=long_description(7),
+    long_description_content_type='text/x-rst',
     author='Oliver Tonnhofer',
     author_email='olt at omniscale.de',
+    maintainer='terrestris GmbH & Co. KG',
+    maintainer_email='info at terrestris.de',
     url='https://mapproxy.org',
     license='Apache Software License 2.0',
     packages=find_packages(),



View it on GitLab: https://salsa.debian.org/debian-gis-team/mapproxy/-/compare/926dbd2c05c9a58d5c5edd26340b6d4654fa819a...0cbe6ae2578d039f6cd6fce485c4fe6e9ad4e2e0

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/mapproxy/-/compare/926dbd2c05c9a58d5c5edd26340b6d4654fa819a...0cbe6ae2578d039f6cd6fce485c4fe6e9ad4e2e0
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20241115/b9b243c9/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list