160 lines
5.3 KiB
Python
160 lines
5.3 KiB
Python
#
|
|
# The support for package and group requirements
|
|
#
|
|
# Copyright (C) 2020 Red Hat, Inc.
|
|
#
|
|
# This copyrighted material is made available to anyone wishing to use,
|
|
# modify, copy, or redistribute it subject to the terms and conditions of
|
|
# the GNU General Public License v.2, or (at your option) any later version.
|
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
# ANY WARRANTY expressed or implied, including the implied warranties of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
|
# Public License for more details. You should have received a copy of the
|
|
# GNU General Public License along with this program; if not, write to the
|
|
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
|
|
# source code or documentation are not subject to the GNU General Public
|
|
# License and may only be used or replicated with the express permission of
|
|
# Red Hat, Inc.
|
|
#
|
|
import os
|
|
|
|
from pyanaconda.anaconda_loggers import get_module_logger
|
|
from pyanaconda.core.configuration.anaconda import conf
|
|
from pyanaconda.core.constants import REQUIREMENT_TYPE_PACKAGE, REQUIREMENT_TYPE_GROUP
|
|
from pyanaconda.core.hw import detect_virtualized_platform
|
|
from pyanaconda.localization import find_best_locale_match, is_valid_langcode
|
|
from pyanaconda.modules.common.constants.services import LOCALIZATION, BOSS
|
|
from pyanaconda.modules.common.structures.requirement import Requirement
|
|
from pyanaconda.modules.common.util import is_module_available
|
|
|
|
log = get_module_logger(__name__)
|
|
|
|
|
|
def collect_remote_requirements():
|
|
"""Collect requirements of the DBus modules.
|
|
|
|
:return: a list of requirements
|
|
"""
|
|
boss = BOSS.get_proxy()
|
|
return Requirement.from_structure_list(
|
|
boss.CollectRequirements()
|
|
)
|
|
|
|
|
|
def collect_language_requirements(dnf_manager):
|
|
"""Collect requirements for supported languages.
|
|
|
|
:param dnf_manager: a DNF manager
|
|
:return: a list of requirements
|
|
"""
|
|
requirements = []
|
|
|
|
if not is_module_available(LOCALIZATION):
|
|
return requirements
|
|
|
|
localization_proxy = LOCALIZATION.get_proxy()
|
|
locales = [localization_proxy.Language] + localization_proxy.LanguageSupport
|
|
|
|
# Find all available langpacks.
|
|
packages = dnf_manager.match_available_packages("langpacks-*")
|
|
|
|
# Get all valid langcodes.
|
|
codes = [p.split('-', 1)[1] for p in packages]
|
|
codes = list(filter(is_valid_langcode, codes))
|
|
|
|
# Find the best langpacks to install.
|
|
for locale in locales:
|
|
best_locale = find_best_locale_match(locale, codes)
|
|
|
|
if not best_locale:
|
|
log.warning("Selected locale '%s' does not match "
|
|
"any available langpacks.", locale)
|
|
continue
|
|
|
|
requirements.append(Requirement.for_package(
|
|
package_name="langpacks-" + best_locale,
|
|
reason="Required to support the locale '{}'.".format(locale)
|
|
))
|
|
|
|
return requirements
|
|
|
|
|
|
def collect_platform_requirements(dnf_manager):
|
|
"""Collect the requirements for the current platform.
|
|
|
|
:param dnf_manager: a DNF manager
|
|
:return: a list of requirements
|
|
"""
|
|
# Detect the current platform.
|
|
platform = detect_virtualized_platform()
|
|
|
|
if not platform:
|
|
return []
|
|
|
|
# Add a platform specific group.
|
|
group = "platform-" + platform.lower()
|
|
|
|
if group not in dnf_manager.groups:
|
|
log.warning("Platform group %s not available.", group)
|
|
return []
|
|
|
|
return [Requirement.for_group(
|
|
group_name=group,
|
|
reason="Required for the {} platform.".format(platform)
|
|
)]
|
|
|
|
|
|
def collect_driver_disk_requirements(path="/run/install/dd_packages"):
|
|
"""Collect the requirements from the driver updates disk.
|
|
|
|
:param path: a path to the file with a package list
|
|
:return: a list of requirements
|
|
"""
|
|
requirements = []
|
|
|
|
if not os.path.exists(path):
|
|
return []
|
|
|
|
with open(path, "r") as f:
|
|
for line in f:
|
|
package = line.strip()
|
|
requirements.append(Requirement.for_package(
|
|
package_name=package,
|
|
reason="Required by the driver updates disk."
|
|
))
|
|
|
|
return requirements
|
|
|
|
|
|
def apply_requirements(requirements, include_list, exclude_list):
|
|
"""Apply the provided requirements.
|
|
|
|
:param requirements: a list of requirements
|
|
:param include_list: a list of specs to include in the transaction
|
|
:param exclude_list: a list of specs to exclude from the transaction
|
|
"""
|
|
log.debug("Applying requirements: %s", requirements)
|
|
|
|
for r in requirements:
|
|
# Generate a spec for the requirement.
|
|
if r.type == REQUIREMENT_TYPE_PACKAGE:
|
|
spec = r.name
|
|
elif r.type == REQUIREMENT_TYPE_GROUP:
|
|
spec = "@{}".format(r.name)
|
|
else:
|
|
log.warning("Unsupported type '%s' of the requirement.", r.type)
|
|
continue
|
|
|
|
# Check if the requirement can be applied.
|
|
if spec in conf.payload.ignored_packages:
|
|
log.debug("Requirement '%s' is ignored by the configuration.", spec)
|
|
continue
|
|
|
|
if spec in exclude_list:
|
|
log.debug("Requirement '%s' is ignored because it's excluded.", spec)
|
|
continue
|
|
|
|
# Apply the requirement.
|
|
include_list.append(spec)
|
|
log.debug("Requirement '%s' is applied. Reason: %s", spec, r.reason)
|