diff --git a/src/cockpit/packages.py b/src/cockpit/packages.py index f43053ea25f..66c7ac970b0 100644 --- a/src/cockpit/packages.py +++ b/src/cockpit/packages.py @@ -266,11 +266,22 @@ def ensure_scanned(self) -> None: # Accept-Language is case-insensitive and uses '-' to separate variants lower_locale = locale.lower().replace('_', '-') + logger.debug('Adding translation %r %r -> %r', basename, lower_locale, name) self.translations[f'{basename}.js'][lower_locale] = name else: - basename = name[:-3] if name.endswith('.gz') else name + # strip out trailing '.gz' components + basename = re.sub('.gz$', '', name) + logger.debug('Adding content %r -> %r', basename, name) self.files[basename] = name + # If we see a filename like `x.min.js` we want to also offer it + # at `x.js`, but only if `x.js(.gz)` itself is not present. + # Note: this works for both the case where we found the `x.js` + # first (it's already in the map) and also if we find it second + # (it will be replaced in the map by the line just above). + # See https://github.com/cockpit-project/cockpit/pull/19716 + self.files.setdefault(basename.replace('.min.', '.'), name) + # support old cockpit-po-plugin which didn't write po.manifest.??.js if not self.translations['po.manifest.js']: self.translations['po.manifest.js'] = self.translations['po.js'] diff --git a/test/pytest/test_packages.py b/test/pytest/test_packages.py index e6d7c75c7f6..4170f5d50b7 100644 --- a/test/pytest/test_packages.py +++ b/test/pytest/test_packages.py @@ -239,3 +239,49 @@ def test_translation(pkgdir): assert b'eins\n' in contents assert b'zwo\n' in contents assert b'zwei\n' not in contents + + +def test_filename_mangling(pkgdir): + make_package(pkgdir, 'one') + + # test various filename variations + (pkgdir / 'one' / 'one.js').write_text('this is one.js') + (pkgdir / 'one' / 'two.js.gz').write_text('this is two.js') + (pkgdir / 'one' / 'three.min.js.gz').write_text('this is three.js') + (pkgdir / 'one' / 'four.min.js').write_text('this is four.js') + + packages = Packages() + encodings = set() + + for name in ['one', 'two', 'three', 'four']: + document = packages.load_path(f'/one/{name}.js', {}) + assert document.data.read().decode() == f'this is {name}.js' + assert '/javascript' in document.content_type + encodings.add(document.content_encoding) + + assert encodings == {None, 'gzip'} # make sure we saw both compressed and uncompressed + + +def test_overlapping_minified(pkgdir): + make_package(pkgdir, 'one') + (pkgdir / 'one' / 'one.min.js').write_text('min') + (pkgdir / 'one' / 'one.js').write_text('max') + + # try the other way around in hope of listing the files in reverse order + (pkgdir / 'one' / 'two.js').write_text('max') + (pkgdir / 'one' / 'two.min.js').write_text('min') + + packages = Packages() + + # if both files are present, we should find the original one + document = packages.load_path('/one/one.js', {}) + assert document.data.read().decode() == 'max' + document = packages.load_path('/one/two.js', {}) + assert document.data.read().decode() == 'max' + + # but requesting .min. explicitly will load it + document = packages.load_path('/one/one.min.js', {}) + assert document.data.read().decode() == 'min' + document = packages.load_path('/one/two.min.js', {}) + assert document.data.read().decode() == 'min' +