package: Don't consider uninstalled packages as available

- Ensure that packages that are not installable to negative priority are not
shown as available.

Tests:

- Set priority of an available package to less than 0. This package will be
shown as not-available in the app install page.

- Normal apps are shown as available and can be installed as usual.

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-09-04 13:21:20 -07:00 committed by James Valleroy
parent 866daf27ef
commit d8c727a109
No known key found for this signature in database
GPG Key ID: 77C0C75E7B650808
2 changed files with 35 additions and 9 deletions

View File

@ -69,8 +69,11 @@ class Package(PackageExpression):
def actual(self) -> str:
cache = apt.Cache()
if self.name in cache:
# TODO: Also return version and suite to install from
if self.name in cache and cache[self.name].candidate:
# cache[package].candidate returns installation candidate. If the
# package is not installable due to the available versions being of
# priority less than 0, then .candidate will be None. TODO: Also
# return version and suite to install from.
return self.name
raise MissingPackageError(self.name)

View File

@ -80,11 +80,21 @@ def test_packages_init():
assert component.rerun_setup_on_upgrade
def test_packages_get_actual_packages():
@patch('apt.Cache')
def test_packages_get_actual_packages(cache):
"""Test resolving of package expressions to actual packages."""
cache.return_value = {
'python3': Mock(name='python3', candidate='1.0'),
'janus': Mock(name='janus', candidate=None)
}
component = Packages('test-component', ['python3'])
assert component.get_actual_packages() == ['python3']
component = Packages('test-component', ['unknown-package'])
with pytest.raises(MissingPackageError):
component.get_actual_packages()
component = Packages('test-component',
[Package('unknown-package') | Package('python3')])
assert component.get_actual_packages() == ['python3']
@ -94,6 +104,10 @@ def test_packages_get_actual_packages():
conflicts_action=Packages.ConflictsAction.IGNORE)
assert component.get_actual_packages() == []
component = Packages('test-component', ['janus'])
with pytest.raises(MissingPackageError):
component.get_actual_packages()
@patch('plinth.package.install')
def test_packages_setup(install):
@ -356,17 +370,23 @@ def test_packages_is_available(path_class, cache, refresh_package_lists):
'/etc/apt/sources.list': sources_list
}[path]
def get_cache_packages(packages):
return {
package: Mock(name=package, candidate='1.0')
for package in packages
}
path_class.side_effect = path_side_effect
# Packages found in cache
component = Packages('test-component', ['package1', 'package2'])
cache.return_value = ['package1', 'package2']
cache.return_value = get_cache_packages(['package1', 'package2'])
assert component.is_available()
path_class.assert_not_called()
refresh_package_lists.assert_not_called()
# Packages not found, cache exists and is fresh
cache.return_value = ['package1']
cache.return_value = get_cache_packages(['package1'])
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
@ -374,13 +394,13 @@ def test_packages_is_available(path_class, cache, refresh_package_lists):
refresh_package_lists.assert_not_called()
# Packages not found, cache does not exist
cache.return_value = ['package1']
cache.return_value = get_cache_packages(['package1'])
package_cache.exists.return_value = False
assert not component.is_available()
refresh_package_lists.assert_called_once()
# Packages not found, cache is stale because it older than 1 hour
cache.return_value = ['package1']
cache.return_value = get_cache_packages(['package1'])
refresh_package_lists.reset_mock()
package_cache.exists.return_value = True
package_cache.stat.return_value.st_mtime = time.time() - 7200
@ -388,7 +408,7 @@ def test_packages_is_available(path_class, cache, refresh_package_lists):
refresh_package_lists.assert_called_once()
# Packages not found, cache is stale because it older than sources.list
cache.return_value = ['package1']
cache.return_value = get_cache_packages(['package1'])
refresh_package_lists.reset_mock()
package_cache.exists.return_value = True
package_cache.stat.return_value.st_mtime = time.time() - 100
@ -397,7 +417,10 @@ def test_packages_is_available(path_class, cache, refresh_package_lists):
refresh_package_lists.assert_called_once()
# Packages not found, cache is stale, but packages found after refresh
cache.side_effect = [['package1'], ['package1', 'package2']]
cache.side_effect = [
get_cache_packages(['package1']),
get_cache_packages(['package1', 'package2'])
]
refresh_package_lists.reset_mock()
assert component.is_available()