package: Refresh apt cache if sources list is newer

- When backports repository or unstable repository freshly added by the updates
app. We will like apps to become available due to newly available Debian
packages. For this to happen 'apt update' must be called before checking if an
app is available.

Tests:

- Freshly apply the patches for upgrades app. Setup is re-run and unstable
sources file is introduced. Immediately visit the Matrix app and notice that is
shown as available and can be installed immediately.

Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
Sunil Mohan Adapa 2025-08-07 12:32:14 -07:00 committed by James Valleroy
parent fecd6a3577
commit 866daf27ef
No known key found for this signature in database
GPG Key ID: 77C0C75E7B650808
2 changed files with 45 additions and 12 deletions

View File

@ -268,11 +268,23 @@ class Packages(app_module.FollowerComponent):
except MissingPackageError:
pass # We will retry after refreshing package list
# If the package cache is new, then package is really not available.
package_cache = pathlib.Path('/var/cache/apt/pkgcache.bin')
if (package_cache.exists()
and time.time() - package_cache.stat().st_mtime < 3600):
return False
if package_cache.exists():
package_cache_mtime = package_cache.stat().st_mtime
sources_dir = pathlib.Path('/etc/apt/sources.list.d')
source_files = ([pathlib.Path('/etc/apt/sources.list')] +
list(sources_dir.glob('*.list')) +
list(sources_dir.glob('*.sources')))
are_sources_newer = any(
source_file.stat().st_mtime > package_cache_mtime
for source_file in source_files)
# If the package cache is new, then package is really not
# available.
if (time.time() - package_cache.stat().st_mtime < 3600
and not are_sources_newer):
return False
# Perform 'apt-get update'
refresh_package_lists()

View File

@ -344,8 +344,19 @@ def test_packages_find_conflicts(packages_installed_):
@patch('pathlib.Path')
def test_packages_is_available(path_class, cache, refresh_package_lists):
"""Test checking for available packages."""
path = Mock()
path_class.return_value = path
package_cache = Mock()
sources_dir = Mock()
sources_dir.glob.return_value = []
sources_list = Mock()
def path_side_effect(path):
return {
'/var/cache/apt/pkgcache.bin': package_cache,
'/etc/apt/sources.list.d': sources_dir,
'/etc/apt/sources.list': sources_list
}[path]
path_class.side_effect = path_side_effect
# Packages found in cache
component = Packages('test-component', ['package1', 'package2'])
@ -356,22 +367,32 @@ def test_packages_is_available(path_class, cache, refresh_package_lists):
# Packages not found, cache exists and is fresh
cache.return_value = ['package1']
path.exists.return_value = True
path.stat.return_value.st_mtime = time.time()
package_cache.exists.return_value = True
package_cache.stat.return_value.st_mtime = time.time()
sources_list.stat.return_value.st_mtime = time.time() - 100
assert not component.is_available()
refresh_package_lists.assert_not_called()
# Packages not found, cache does not exist
cache.return_value = ['package1']
path.exists.return_value = False
package_cache.exists.return_value = False
assert not component.is_available()
refresh_package_lists.assert_called_once()
# Packages not found, cache is stale
# Packages not found, cache is stale because it older than 1 hour
cache.return_value = ['package1']
refresh_package_lists.reset_mock()
path.exists.return_value = True
path.stat.return_value.st_mtime = time.time() - 7200
package_cache.exists.return_value = True
package_cache.stat.return_value.st_mtime = time.time() - 7200
assert not component.is_available()
refresh_package_lists.assert_called_once()
# Packages not found, cache is stale because it older than sources.list
cache.return_value = ['package1']
refresh_package_lists.reset_mock()
package_cache.exists.return_value = True
package_cache.stat.return_value.st_mtime = time.time() - 100
sources_list.stat.return_value.st_mtime = time.time()
assert not component.is_available()
refresh_package_lists.assert_called_once()