Compare commits
No commits in common. 'i9' and 'i8-beta' have entirely different histories.
@ -1 +1 @@
|
|||||||
71620d2ed3ce54558da0cb8d49cac48fa89d3a7a SOURCES/anaconda-34.25.4.9.tar.bz2
|
7450b69534ac5ce10f8698270153984ec9871944 SOURCES/anaconda-33.16.10.4.tar.bz2
|
||||||
|
@ -1 +1 @@
|
|||||||
SOURCES/anaconda-34.25.4.9.tar.bz2
|
SOURCES/anaconda-33.16.10.4.tar.bz2
|
||||||
|
@ -1,102 +0,0 @@
|
|||||||
From 03809bf006ee92d63a3bc4bc9702ceca757a5e9c Mon Sep 17 00:00:00 2001
|
|
||||||
From: Eugene Zamriy <eugene@zamriy.info>
|
|
||||||
Date: Fri, 14 Apr 2023 18:23:29 +0300
|
|
||||||
Subject: [PATCH 08/15] Replace Fedora references and update translations
|
|
||||||
|
|
||||||
---
|
|
||||||
data/liveinst/gnome/fedora-welcome.desktop | 3 ++-
|
|
||||||
data/liveinst/gnome/fedora-welcome.js | 6 +++---
|
|
||||||
docs/intro.rst | 4 ++--
|
|
||||||
docs/iscsi.rst | 2 +-
|
|
||||||
pyanaconda/core/constants.py | 4 ++--
|
|
||||||
5 files changed, 10 insertions(+), 9 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/data/liveinst/gnome/fedora-welcome.desktop b/data/liveinst/gnome/fedora-welcome.desktop
|
|
||||||
index 60e5c38..90f5678 100644
|
|
||||||
--- a/data/liveinst/gnome/fedora-welcome.desktop
|
|
||||||
+++ b/data/liveinst/gnome/fedora-welcome.desktop
|
|
||||||
@@ -1,5 +1,6 @@
|
|
||||||
[Desktop Entry]
|
|
||||||
-Name=Welcome to Fedora
|
|
||||||
+Name=Welcome to MSVSphere
|
|
||||||
+Name[ru]=Добро пожаловать в МСВСфера
|
|
||||||
Exec=/usr/share/anaconda/gnome/fedora-welcome
|
|
||||||
Terminal=false
|
|
||||||
Type=Application
|
|
||||||
diff --git a/data/liveinst/gnome/fedora-welcome.js b/data/liveinst/gnome/fedora-welcome.js
|
|
||||||
index 0520557..4c0a66a 100755
|
|
||||||
--- a/data/liveinst/gnome/fedora-welcome.js
|
|
||||||
+++ b/data/liveinst/gnome/fedora-welcome.js
|
|
||||||
@@ -62,7 +62,7 @@ const WelcomeWindow = new Lang.Class({
|
|
||||||
default_width: 600,
|
|
||||||
default_height: 550,
|
|
||||||
skip_taskbar_hint: true,
|
|
||||||
- title: _("Welcome to Fedora"),
|
|
||||||
+ title: _("Welcome to MSVSphere"),
|
|
||||||
window_position: Gtk.WindowPosition.CENTER });
|
|
||||||
this.window.connect('key-press-event', Lang.bind(this,
|
|
||||||
function(w, event) {
|
|
||||||
@@ -91,7 +91,7 @@ const WelcomeWindow = new Lang.Class({
|
|
||||||
spacing: 16 });
|
|
||||||
tryContent.add(new Gtk.Image({ icon_name: 'media-optical',
|
|
||||||
pixel_size: 256 }));
|
|
||||||
- tryContent.add(makeLabel(_("Try Fedora"), true));
|
|
||||||
+ tryContent.add(makeLabel(_("Try MSVSphere"), true));
|
|
||||||
|
|
||||||
let tryButton = new Gtk.Button({ child: tryContent });
|
|
||||||
buttonBox.add(tryButton);
|
|
||||||
@@ -107,7 +107,7 @@ const WelcomeWindow = new Lang.Class({
|
|
||||||
let installButton = new Gtk.Button({ child: installContent });
|
|
||||||
buttonBox.add(installButton);
|
|
||||||
|
|
||||||
- this._label = makeLabel(_("You are currently running Fedora from live media.\nYou can install Fedora now, or choose \"Install to Hard Drive\" in the Activities Overview at any later time."), false);
|
|
||||||
+ this._label = makeLabel(_("You are currently running MSVSphere from live media.\nYou can install MSVSphere now, or choose \"Install to Hard Drive\" in the Activities Overview at any later time."), false);
|
|
||||||
mainGrid.add(this._label);
|
|
||||||
|
|
||||||
installButton.connect('clicked', Lang.bind(this,
|
|
||||||
diff --git a/docs/intro.rst b/docs/intro.rst
|
|
||||||
index bbaf74f..65a1a35 100644
|
|
||||||
--- a/docs/intro.rst
|
|
||||||
+++ b/docs/intro.rst
|
|
||||||
@@ -1,8 +1,8 @@
|
|
||||||
Introduction to Anaconda
|
|
||||||
========================
|
|
||||||
|
|
||||||
-Anaconda is the installation program used by Fedora, Red Hat Enterprise Linux
|
|
||||||
-and some other distributions.
|
|
||||||
+Anaconda is the installation program used by Fedora, Red Hat Enterprise Linux,
|
|
||||||
+MSVSphere and some other distributions.
|
|
||||||
|
|
||||||
During installation, a target computer's hardware is identified and configured
|
|
||||||
and the appropriate file systems for the system's architecture are created.
|
|
||||||
diff --git a/docs/iscsi.rst b/docs/iscsi.rst
|
|
||||||
index 847078d..6d9c4b3 100644
|
|
||||||
--- a/docs/iscsi.rst
|
|
||||||
+++ b/docs/iscsi.rst
|
|
||||||
@@ -139,7 +139,7 @@ If for some reason the DeviceTree fails at recognizing iscsi devices as such,
|
|
||||||
The booting problems are either due to incorrectly generated dracut boot
|
|
||||||
arguments or they are simply dracut bugs.
|
|
||||||
|
|
||||||
-Note that many of the iscsi adapters are installed in different Red Hat machines
|
|
||||||
+Note that many of the iscsi adapters are installed in different MSVSphere machines
|
|
||||||
and so the issues can often be reproduced and debugged.
|
|
||||||
|
|
||||||
|
|
||||||
diff --git a/pyanaconda/core/constants.py b/pyanaconda/core/constants.py
|
|
||||||
index ca9dadc..84b03e3 100644
|
|
||||||
--- a/pyanaconda/core/constants.py
|
|
||||||
+++ b/pyanaconda/core/constants.py
|
|
||||||
@@ -156,8 +156,8 @@ WARNING_SUPPORT_REMOVED = N_(
|
|
||||||
)
|
|
||||||
|
|
||||||
WARNING_HARDWARE_UNSUPPORTED = N_(
|
|
||||||
- "This hardware (or a combination thereof) is not supported by Red Hat. For more information "
|
|
||||||
- "on supported hardware, please refer to http://www.redhat.com/hardware."
|
|
||||||
+ "This hardware (or a combination thereof) is not supported by MSVSphere. For more information "
|
|
||||||
+ "on supported hardware, please refer to https://msvsphere-os.ru."
|
|
||||||
)
|
|
||||||
|
|
||||||
# Storage messages
|
|
||||||
--
|
|
||||||
2.44.0
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,50 +0,0 @@
|
|||||||
From 60ffb83455ecba7fccef1044e7eb17b55c589c44 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Eugene Zamriy <eugene@zamriy.info>
|
|
||||||
Date: Wed, 19 Apr 2023 12:06:57 +0300
|
|
||||||
Subject: [PATCH 10/15] Set English as fallback language for help
|
|
||||||
|
|
||||||
---
|
|
||||||
pyanaconda/core/constants.py | 4 ++++
|
|
||||||
pyanaconda/ui/lib/help.py | 4 ++--
|
|
||||||
2 files changed, 6 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/pyanaconda/core/constants.py b/pyanaconda/core/constants.py
|
|
||||||
index 84b03e3..b7c2e5e 100644
|
|
||||||
--- a/pyanaconda/core/constants.py
|
|
||||||
+++ b/pyanaconda/core/constants.py
|
|
||||||
@@ -74,6 +74,10 @@ ANACONDA_CONFIG_TMP = "/run/anaconda/anaconda.conf"
|
|
||||||
# NOTE: this should be LANG_TERRITORY.CODESET, e.g. en_US.UTF-8
|
|
||||||
DEFAULT_LANG = "ru_RU.UTF-8"
|
|
||||||
|
|
||||||
+# NOTE: MSVSphere change, set English as a fallback help language because
|
|
||||||
+# we use Russian by default for UI
|
|
||||||
+DEFAULT_HELP_LANG = "en_US.UTF-8"
|
|
||||||
+
|
|
||||||
DEFAULT_VC_FONT = "eurlatgr"
|
|
||||||
|
|
||||||
DEFAULT_KEYBOARD = "us"
|
|
||||||
diff --git a/pyanaconda/ui/lib/help.py b/pyanaconda/ui/lib/help.py
|
|
||||||
index 271e587..b8f424d 100644
|
|
||||||
--- a/pyanaconda/ui/lib/help.py
|
|
||||||
+++ b/pyanaconda/ui/lib/help.py
|
|
||||||
@@ -25,7 +25,7 @@ from collections import namedtuple
|
|
||||||
|
|
||||||
from pyanaconda.anaconda_loggers import get_module_logger
|
|
||||||
from pyanaconda.core.configuration.anaconda import conf
|
|
||||||
-from pyanaconda.core.constants import DEFAULT_LANG, DisplayModes
|
|
||||||
+from pyanaconda.core.constants import DEFAULT_HELP_LANG, DisplayModes
|
|
||||||
from pyanaconda.core.util import startProgram, join_paths
|
|
||||||
from pyanaconda.localization import find_best_locale_match
|
|
||||||
|
|
||||||
@@ -224,7 +224,7 @@ def _find_best_help_file(current_locale, available_files):
|
|
||||||
:param dict available_files: a dictionary of langcodes and help paths
|
|
||||||
:return str: a path to the best help file or None
|
|
||||||
"""
|
|
||||||
- for locale in (current_locale, DEFAULT_LANG):
|
|
||||||
+ for locale in (current_locale, DEFAULT_HELP_LANG):
|
|
||||||
best_lang = find_best_locale_match(locale, available_files.keys())
|
|
||||||
best_path = available_files.get(best_lang, None)
|
|
||||||
|
|
||||||
--
|
|
||||||
2.44.0
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
|||||||
|
From 44aeb5edc044dd6e8af54117c02181d9e9552413 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Anton Volkov <AV.Volkov@softline.com>
|
||||||
|
Date: Thu, 8 Feb 2024 20:59:29 +0300
|
||||||
|
Subject: [PATCH 12/14] Backport bugfixes for keyboard layout:
|
||||||
|
https://bugzilla.redhat.com/show_bug.cgi?id=1039185
|
||||||
|
https://bugzilla.redhat.com/show_bug.cgi?id=1912609
|
||||||
|
|
||||||
|
---
|
||||||
|
pyanaconda/keyboard.py | 12 ++++++++++--
|
||||||
|
1 file changed, 10 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/pyanaconda/keyboard.py b/pyanaconda/keyboard.py
|
||||||
|
index 2c3226c..3ab47bc 100644
|
||||||
|
--- a/pyanaconda/keyboard.py
|
||||||
|
+++ b/pyanaconda/keyboard.py
|
||||||
|
@@ -171,8 +171,10 @@ def set_x_keyboard_defaults(localization_proxy, xkl_wrapper):
|
||||||
|
# store it normalized
|
||||||
|
new_layouts = [normalize_layout_variant(layouts[0])]
|
||||||
|
if not langtable.supports_ascii(layouts[0]):
|
||||||
|
- # does not support typing ASCII chars, append the default layout
|
||||||
|
- new_layouts.append(DEFAULT_KEYBOARD)
|
||||||
|
+ # The default keymap setting should have "us" before the native layout
|
||||||
|
+ # which does not support ascii,
|
||||||
|
+ # refer: https://bugzilla.redhat.com/show_bug.cgi?id=1039185
|
||||||
|
+ new_layouts.insert(0, DEFAULT_KEYBOARD)
|
||||||
|
else:
|
||||||
|
log.error("Failed to get layout for chosen locale '%s'", locale)
|
||||||
|
new_layouts = [DEFAULT_KEYBOARD]
|
||||||
|
@@ -181,6 +183,12 @@ def set_x_keyboard_defaults(localization_proxy, xkl_wrapper):
|
||||||
|
if conf.system.can_configure_keyboard:
|
||||||
|
xkl_wrapper.replace_layouts(new_layouts)
|
||||||
|
|
||||||
|
+ # the console layout configured should be "native" by default,
|
||||||
|
+ # setting that explicitly for non-ascii layouts where we prepend "us"
|
||||||
|
+ # refer: https://bugzilla.redhat.com/show_bug.cgi?id=1912609
|
||||||
|
+ if len(new_layouts) >= 2 and not langtable.supports_ascii(new_layouts[1]):
|
||||||
|
+ localization_proxy.SetVirtualConsoleKeymap(new_layouts[1])
|
||||||
|
+
|
||||||
|
if len(new_layouts) >= 2 and not localization_proxy.LayoutSwitchOptions:
|
||||||
|
# initialize layout switching if needed
|
||||||
|
localization_proxy.SetLayoutSwitchOptions(["grp:alt_shift_toggle"])
|
||||||
|
--
|
||||||
|
2.39.3
|
||||||
|
|
@ -0,0 +1,262 @@
|
|||||||
|
From e9211745672557570dc16829489556fa58254cbd Mon Sep 17 00:00:00 2001
|
||||||
|
From: Anton Volkov <AV.Volkov@softline.com>
|
||||||
|
Date: Tue, 20 Feb 2024 19:38:47 +0300
|
||||||
|
Subject: [PATCH 13/14] Activate all wired network devices with link in up
|
||||||
|
state when running interactive installation
|
||||||
|
|
||||||
|
---
|
||||||
|
anaconda.py | 3 +
|
||||||
|
pyanaconda/modules/network/initialization.py | 44 +++++++++
|
||||||
|
pyanaconda/modules/network/network.py | 15 ++-
|
||||||
|
.../modules/network/network_interface.py | 9 ++
|
||||||
|
pyanaconda/network.py | 91 +++++++++++++++++++
|
||||||
|
5 files changed, 161 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/anaconda.py b/anaconda.py
|
||||||
|
index bbf801b..ae282e3 100755
|
||||||
|
--- a/anaconda.py
|
||||||
|
+++ b/anaconda.py
|
||||||
|
@@ -516,6 +516,9 @@ if __name__ == "__main__":
|
||||||
|
# Initialize the network now, in case the display needs it
|
||||||
|
from pyanaconda.network import initialize_network, wait_for_connecting_NM_thread, wait_for_connected_NM
|
||||||
|
|
||||||
|
+ import pyanaconda.network # @UnusedImport
|
||||||
|
+ pyanaconda.network.interactive_mode = anaconda.interactive_mode
|
||||||
|
+
|
||||||
|
initialize_network()
|
||||||
|
# If required by user, wait for connection before starting the installation.
|
||||||
|
if opts.waitfornet:
|
||||||
|
diff --git a/pyanaconda/modules/network/initialization.py b/pyanaconda/modules/network/initialization.py
|
||||||
|
index f61b88f..dc8035a 100644
|
||||||
|
--- a/pyanaconda/modules/network/initialization.py
|
||||||
|
+++ b/pyanaconda/modules/network/initialization.py
|
||||||
|
@@ -32,6 +32,7 @@ from pyanaconda.modules.network.ifcfg import get_ifcfg_file_of_device, find_ifcf
|
||||||
|
from pyanaconda.modules.network.device_configuration import supported_wired_device_types, \
|
||||||
|
virtual_device_types
|
||||||
|
from pyanaconda.modules.network.utils import guard_by_system_configuration
|
||||||
|
+from pyanaconda.network import switch_all_network_devices
|
||||||
|
|
||||||
|
log = get_module_logger(__name__)
|
||||||
|
|
||||||
|
@@ -40,6 +41,49 @@ gi.require_version("NM", "1.0")
|
||||||
|
from gi.repository import NM
|
||||||
|
|
||||||
|
|
||||||
|
+class SwitchNetworkDevicesTask(Task):
|
||||||
|
+ """Task for switching all network devices ON"""
|
||||||
|
+
|
||||||
|
+ def __init__(self, network_data, supported_devices, bootif, ifname_option_values):
|
||||||
|
+ """Create a new task.
|
||||||
|
+
|
||||||
|
+ :param network_data: kickstart network data to be applied
|
||||||
|
+ :type: list(NetworkData)
|
||||||
|
+ :param supported_devices: list of names of supported network devices
|
||||||
|
+ :type supported_devices: list(str)
|
||||||
|
+ :param bootif: MAC addres of device to be used for --device=bootif specification
|
||||||
|
+ :type bootif: str
|
||||||
|
+ :param ifname_option_values: list of ifname boot option values
|
||||||
|
+ :type ifname_option_values: list(str)
|
||||||
|
+ """
|
||||||
|
+ super().__init__()
|
||||||
|
+ self._network_data = network_data
|
||||||
|
+ self._supported_devices = supported_devices
|
||||||
|
+ self._bootif = bootif
|
||||||
|
+ self._ifname_option_values = ifname_option_values
|
||||||
|
+
|
||||||
|
+ @property
|
||||||
|
+ def name(self):
|
||||||
|
+ return "Switch network devices on"
|
||||||
|
+
|
||||||
|
+ def for_publication(self):
|
||||||
|
+ """Return a DBus representation."""
|
||||||
|
+ return NetworkInitializationTaskInterface(self)
|
||||||
|
+
|
||||||
|
+ @guard_by_system_configuration(return_value=[])
|
||||||
|
+ def run(self):
|
||||||
|
+ """Run the switching network devices on.
|
||||||
|
+
|
||||||
|
+ :returns: names of devices
|
||||||
|
+ :rtype: list(str)
|
||||||
|
+ """
|
||||||
|
+ with nm_client_in_thread() as nm_client:
|
||||||
|
+ return self._run(nm_client)
|
||||||
|
+
|
||||||
|
+ def _run(self, nm_client):
|
||||||
|
+ return switch_all_network_devices(nm_client)
|
||||||
|
+
|
||||||
|
+
|
||||||
|
class ApplyKickstartTask(Task):
|
||||||
|
"""Task for application of kickstart network configuration."""
|
||||||
|
|
||||||
|
diff --git a/pyanaconda/modules/network/network.py b/pyanaconda/modules/network/network.py
|
||||||
|
index 1e194c3..d436190 100644
|
||||||
|
--- a/pyanaconda/modules/network/network.py
|
||||||
|
+++ b/pyanaconda/modules/network/network.py
|
||||||
|
@@ -39,7 +39,7 @@ from pyanaconda.modules.network.ifcfg import get_kickstart_network_data, \
|
||||||
|
get_ifcfg_file, get_ifcfg_files_content
|
||||||
|
from pyanaconda.modules.network.installation import NetworkInstallationTask, \
|
||||||
|
ConfigureActivationOnBootTask, HostnameConfigurationTask
|
||||||
|
-from pyanaconda.modules.network.initialization import ApplyKickstartTask, \
|
||||||
|
+from pyanaconda.modules.network.initialization import ApplyKickstartTask, SwitchNetworkDevicesTask, \
|
||||||
|
ConsolidateInitramfsConnectionsTask, SetRealOnbootValuesFromKickstartTask, \
|
||||||
|
DumpMissingIfcfgFilesTask
|
||||||
|
from pyanaconda.modules.network.utils import get_default_route_iface
|
||||||
|
@@ -550,6 +550,19 @@ class NetworkService(KickstartService):
|
||||||
|
self._ifname_option_values = values
|
||||||
|
log.debug("ifname boot option values are set to %s", values)
|
||||||
|
|
||||||
|
+ def switch_network_devices_with_task(self):
|
||||||
|
+ """Switch all network devices ON
|
||||||
|
+
|
||||||
|
+ :returns: a task switching all network devices ON
|
||||||
|
+ """
|
||||||
|
+ supported_devices = [dev_info.device_name for dev_info in self.get_supported_devices()]
|
||||||
|
+ task = SwitchNetworkDevicesTask(self._original_network_data,
|
||||||
|
+ supported_devices,
|
||||||
|
+ self.bootif,
|
||||||
|
+ self.ifname_option_values)
|
||||||
|
+ task.succeeded_signal.connect(lambda: self.log_task_result(task, check_result=True))
|
||||||
|
+ return task
|
||||||
|
+
|
||||||
|
def apply_kickstart_with_task(self):
|
||||||
|
"""Apply kickstart configuration which has not already been applied.
|
||||||
|
|
||||||
|
diff --git a/pyanaconda/modules/network/network_interface.py b/pyanaconda/modules/network/network_interface.py
|
||||||
|
index 6e904ba..27e6e3d 100644
|
||||||
|
--- a/pyanaconda/modules/network/network_interface.py
|
||||||
|
+++ b/pyanaconda/modules/network/network_interface.py
|
||||||
|
@@ -213,6 +213,15 @@ class NetworkInterface(KickstartModuleInterface):
|
||||||
|
self.implementation.consolidate_initramfs_connections_with_task()
|
||||||
|
)
|
||||||
|
|
||||||
|
+ def SwitchNetworkDevicesWithTask(self) -> ObjPath:
|
||||||
|
+ """Switch network devices ON
|
||||||
|
+
|
||||||
|
+ :returns: DBus path of the task switching network devices ON
|
||||||
|
+ """
|
||||||
|
+ return TaskContainer.to_object_path(
|
||||||
|
+ self.implementation.switch_network_devices_with_task()
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
def ApplyKickstartWithTask(self) -> ObjPath:
|
||||||
|
"""Apply kickstart configuration which has not already been applied.
|
||||||
|
|
||||||
|
diff --git a/pyanaconda/network.py b/pyanaconda/network.py
|
||||||
|
index d757934..f7fa48c 100644
|
||||||
|
--- a/pyanaconda/network.py
|
||||||
|
+++ b/pyanaconda/network.py
|
||||||
|
@@ -50,6 +50,8 @@ log = get_module_logger(__name__)
|
||||||
|
|
||||||
|
DEFAULT_HOSTNAME = "localhost.localdomain"
|
||||||
|
|
||||||
|
+interactive_mode = False
|
||||||
|
+
|
||||||
|
network_connected = None
|
||||||
|
network_connected_condition = threading.Condition()
|
||||||
|
|
||||||
|
@@ -272,6 +274,91 @@ def run_network_initialization_task(task_path):
|
||||||
|
log.debug(msg)
|
||||||
|
|
||||||
|
|
||||||
|
+def switch_all_network_devices(client, activate=True, check_link=True, wait=True):
|
||||||
|
+ """
|
||||||
|
+ Switch ON (or OFF) all wired network devices with link in up state.
|
||||||
|
+ Return list of device names switched ON
|
||||||
|
+ :param client: Network Manager client object
|
||||||
|
+ :param activate: True = activate (ON), False = deactivate network devices
|
||||||
|
+ :param check_link: True = activate network devices with link in up state only
|
||||||
|
+ :param wait: True = wait for network devices to become active before exiting the function
|
||||||
|
+ :rtype list(str)
|
||||||
|
+ """
|
||||||
|
+ action = "on" if activate else "off"
|
||||||
|
+ log.debug("start switching all devices %s", action)
|
||||||
|
+ if not client:
|
||||||
|
+ log.debug("NM client not available")
|
||||||
|
+ return []
|
||||||
|
+ devices = client.get_devices()
|
||||||
|
+ if not devices:
|
||||||
|
+ log.debug("No devices found")
|
||||||
|
+ return []
|
||||||
|
+ activated_ifaces = get_activated_devices(client)
|
||||||
|
+ active_connections = client.get_active_connections()
|
||||||
|
+ active_uuids = set([con.get_uuid() for con in active_connections])
|
||||||
|
+ changed = False
|
||||||
|
+ ifaces = set()
|
||||||
|
+ for device in devices:
|
||||||
|
+ if not device:
|
||||||
|
+ continue
|
||||||
|
+ switched = False
|
||||||
|
+ iface = device.get_iface()
|
||||||
|
+ if not device_type_is_supported_wired(device.get_device_type()):
|
||||||
|
+ log.debug("device %s is not wired, skipping", iface)
|
||||||
|
+ continue
|
||||||
|
+ if activate:
|
||||||
|
+ if iface in activated_ifaces:
|
||||||
|
+ log.debug("device %s activated already, skipping", iface)
|
||||||
|
+ continue
|
||||||
|
+ elif iface not in activated_ifaces:
|
||||||
|
+ log.debug("device %s not activated already, skipping", iface)
|
||||||
|
+ continue
|
||||||
|
+ # check if the link for the device is up
|
||||||
|
+ if check_link and activate:
|
||||||
|
+ try:
|
||||||
|
+ carrier = device.get_carrier()
|
||||||
|
+ except AttributeError:
|
||||||
|
+ carrier = None
|
||||||
|
+ if carrier:
|
||||||
|
+ log.debug("device %s link is up", iface)
|
||||||
|
+ else:
|
||||||
|
+ log.debug("device %s link is down", iface)
|
||||||
|
+ # skip activating device if link is down
|
||||||
|
+ continue
|
||||||
|
+ connections = device.get_available_connections()
|
||||||
|
+ if not connections:
|
||||||
|
+ log.debug("No available connections for device %s", iface)
|
||||||
|
+ continue
|
||||||
|
+ for con in connections:
|
||||||
|
+ if not con:
|
||||||
|
+ continue
|
||||||
|
+ uuid = con.get_uuid()
|
||||||
|
+ if activate:
|
||||||
|
+ if uuid in active_uuids:
|
||||||
|
+ log.debug("connection %s for device %s is active already, skipping", uuid, iface)
|
||||||
|
+ continue
|
||||||
|
+ elif uuid not in active_uuids:
|
||||||
|
+ log.debug("connection %s for device %s is not active already, skipping", uuid, iface)
|
||||||
|
+ continue
|
||||||
|
+ if activate:
|
||||||
|
+ client.activate_connection_async(con, device, None, None)
|
||||||
|
+ ifaces.add(iface)
|
||||||
|
+ else:
|
||||||
|
+ device.disconnect(None)
|
||||||
|
+ switched = changed = True
|
||||||
|
+ if switched:
|
||||||
|
+ log.info("device %s switched %s", iface, action)
|
||||||
|
+ if not changed:
|
||||||
|
+ log.debug("No devices switched %s", action)
|
||||||
|
+ if wait and ifaces:
|
||||||
|
+ if wait_for_network_devices(ifaces):
|
||||||
|
+ log.debug("waiting succeeded: devices are active")
|
||||||
|
+ else:
|
||||||
|
+ log.debug("waiting timeout has expired")
|
||||||
|
+ log.debug("finish switching all devices %s", action)
|
||||||
|
+ return list(ifaces)
|
||||||
|
+
|
||||||
|
+
|
||||||
|
def initialize_network():
|
||||||
|
"""Initialize networking."""
|
||||||
|
if not conf.system.can_configure_network:
|
||||||
|
@@ -290,6 +377,10 @@ def initialize_network():
|
||||||
|
run_network_initialization_task(network_proxy.ApplyKickstartWithTask())
|
||||||
|
run_network_initialization_task(network_proxy.DumpMissingIfcfgFilesWithTask())
|
||||||
|
run_network_initialization_task(network_proxy.SetRealOnbootValuesFromKickstartWithTask())
|
||||||
|
+ if interactive_mode:
|
||||||
|
+ run_network_initialization_task(network_proxy.SwitchNetworkDevicesWithTask())
|
||||||
|
+ else:
|
||||||
|
+ log.debug("Not activating all wired network devices in non-interactive mode")
|
||||||
|
|
||||||
|
if network_proxy.Hostname == DEFAULT_HOSTNAME:
|
||||||
|
bootopts_hostname = hostname_from_cmdline(kernel_arguments)
|
||||||
|
--
|
||||||
|
2.39.3
|
||||||
|
|
@ -0,0 +1,234 @@
|
|||||||
|
From b6807446c6531753b5b46ec906f8fa4d05f91770 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Anton Volkov <AV.Volkov@softline.com>
|
||||||
|
Date: Thu, 22 Feb 2024 12:42:25 +0300
|
||||||
|
Subject: [PATCH 14/14] Set autoconnect and autoconnect-priority for
|
||||||
|
connections of all network devices with link in up state
|
||||||
|
|
||||||
|
---
|
||||||
|
pyanaconda/modules/network/initialization.py | 53 +++++++++++++-
|
||||||
|
pyanaconda/modules/network/network.py | 15 +++-
|
||||||
|
.../modules/network/network_interface.py | 9 +++
|
||||||
|
pyanaconda/network.py | 69 +++++++++++++++++++
|
||||||
|
4 files changed, 144 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/pyanaconda/modules/network/initialization.py b/pyanaconda/modules/network/initialization.py
|
||||||
|
index dc8035a..5530075 100644
|
||||||
|
--- a/pyanaconda/modules/network/initialization.py
|
||||||
|
+++ b/pyanaconda/modules/network/initialization.py
|
||||||
|
@@ -32,7 +32,7 @@ from pyanaconda.modules.network.ifcfg import get_ifcfg_file_of_device, find_ifcf
|
||||||
|
from pyanaconda.modules.network.device_configuration import supported_wired_device_types, \
|
||||||
|
virtual_device_types
|
||||||
|
from pyanaconda.modules.network.utils import guard_by_system_configuration
|
||||||
|
-from pyanaconda.network import switch_all_network_devices
|
||||||
|
+from pyanaconda.network import switch_all_network_devices, configure_connections
|
||||||
|
|
||||||
|
log = get_module_logger(__name__)
|
||||||
|
|
||||||
|
@@ -41,6 +41,57 @@ gi.require_version("NM", "1.0")
|
||||||
|
from gi.repository import NM
|
||||||
|
|
||||||
|
|
||||||
|
+class SetAutoconnectPriorityTask(Task):
|
||||||
|
+ """
|
||||||
|
+ Task for configuring autoconnect and autoconnect-priority for connections of
|
||||||
|
+ all network devices with link in up state
|
||||||
|
+ """
|
||||||
|
+
|
||||||
|
+ def __init__(self, network_data, supported_devices, bootif, ifname_option_values):
|
||||||
|
+ """Create a new task.
|
||||||
|
+
|
||||||
|
+ :param network_data: kickstart network data to be applied
|
||||||
|
+ :type: list(NetworkData)
|
||||||
|
+ :param supported_devices: list of names of supported network devices
|
||||||
|
+ :type supported_devices: list(str)
|
||||||
|
+ :param bootif: MAC addres of device to be used for --device=bootif specification
|
||||||
|
+ :type bootif: str
|
||||||
|
+ :param ifname_option_values: list of ifname boot option values
|
||||||
|
+ :type ifname_option_values: list(str)
|
||||||
|
+ """
|
||||||
|
+ super().__init__()
|
||||||
|
+ self._network_data = network_data
|
||||||
|
+ self._supported_devices = supported_devices
|
||||||
|
+ self._bootif = bootif
|
||||||
|
+ self._ifname_option_values = ifname_option_values
|
||||||
|
+
|
||||||
|
+ @property
|
||||||
|
+ def name(self):
|
||||||
|
+ return "Set autoconnect and autoconnect-priority for connections of network devices with link in up state"
|
||||||
|
+
|
||||||
|
+ def for_publication(self):
|
||||||
|
+ """Return a DBus representation."""
|
||||||
|
+ return NetworkInitializationTaskInterface(self)
|
||||||
|
+
|
||||||
|
+ @guard_by_system_configuration(return_value=[])
|
||||||
|
+ def run(self):
|
||||||
|
+ """
|
||||||
|
+ Run nmcli utility to set autoconnect and autoconnect-priority for
|
||||||
|
+ connections of network devices with link in up state
|
||||||
|
+ :returns: names of devices
|
||||||
|
+ :rtype: list(str)
|
||||||
|
+ """
|
||||||
|
+ with nm_client_in_thread() as nm_client:
|
||||||
|
+ return self._run(nm_client)
|
||||||
|
+
|
||||||
|
+ def _run(self, nm_client):
|
||||||
|
+ settings = {
|
||||||
|
+ "connection.autoconnect" : "yes",
|
||||||
|
+ "connection.autoconnect-priority" : "-999"
|
||||||
|
+ }
|
||||||
|
+ return configure_connections(nm_client, settings)
|
||||||
|
+
|
||||||
|
+
|
||||||
|
class SwitchNetworkDevicesTask(Task):
|
||||||
|
"""Task for switching all network devices ON"""
|
||||||
|
|
||||||
|
diff --git a/pyanaconda/modules/network/network.py b/pyanaconda/modules/network/network.py
|
||||||
|
index d436190..c196ac5 100644
|
||||||
|
--- a/pyanaconda/modules/network/network.py
|
||||||
|
+++ b/pyanaconda/modules/network/network.py
|
||||||
|
@@ -40,7 +40,7 @@ from pyanaconda.modules.network.ifcfg import get_kickstart_network_data, \
|
||||||
|
from pyanaconda.modules.network.installation import NetworkInstallationTask, \
|
||||||
|
ConfigureActivationOnBootTask, HostnameConfigurationTask
|
||||||
|
from pyanaconda.modules.network.initialization import ApplyKickstartTask, SwitchNetworkDevicesTask, \
|
||||||
|
- ConsolidateInitramfsConnectionsTask, SetRealOnbootValuesFromKickstartTask, \
|
||||||
|
+ ConsolidateInitramfsConnectionsTask, SetRealOnbootValuesFromKickstartTask, SetAutoconnectPriorityTask, \
|
||||||
|
DumpMissingIfcfgFilesTask
|
||||||
|
from pyanaconda.modules.network.utils import get_default_route_iface
|
||||||
|
from pyanaconda.modules.common.structures.network import NetworkDeviceInfo
|
||||||
|
@@ -550,6 +550,19 @@ class NetworkService(KickstartService):
|
||||||
|
self._ifname_option_values = values
|
||||||
|
log.debug("ifname boot option values are set to %s", values)
|
||||||
|
|
||||||
|
+ def set_autoconnect_priority_with_task(self):
|
||||||
|
+ """
|
||||||
|
+ Set autoconnect and autoconnect-priority for connections of network devices with link in up state
|
||||||
|
+ :returns: a task configuring autoconnect and autoconnect-priority for all network devices
|
||||||
|
+ """
|
||||||
|
+ supported_devices = [dev_info.device_name for dev_info in self.get_supported_devices()]
|
||||||
|
+ task = SetAutoconnectPriorityTask(self._original_network_data,
|
||||||
|
+ supported_devices,
|
||||||
|
+ self.bootif,
|
||||||
|
+ self.ifname_option_values)
|
||||||
|
+ task.succeeded_signal.connect(lambda: self.log_task_result(task, check_result=True))
|
||||||
|
+ return task
|
||||||
|
+
|
||||||
|
def switch_network_devices_with_task(self):
|
||||||
|
"""Switch all network devices ON
|
||||||
|
|
||||||
|
diff --git a/pyanaconda/modules/network/network_interface.py b/pyanaconda/modules/network/network_interface.py
|
||||||
|
index 27e6e3d..52b7b48 100644
|
||||||
|
--- a/pyanaconda/modules/network/network_interface.py
|
||||||
|
+++ b/pyanaconda/modules/network/network_interface.py
|
||||||
|
@@ -213,6 +213,15 @@ class NetworkInterface(KickstartModuleInterface):
|
||||||
|
self.implementation.consolidate_initramfs_connections_with_task()
|
||||||
|
)
|
||||||
|
|
||||||
|
+ def SetAutoconnectPriorityWithTask(self) -> ObjPath:
|
||||||
|
+ """Set autoconnect and autoconnect-priority for connections of network devices with link in up state
|
||||||
|
+
|
||||||
|
+ :returns: DBus path of the task switching network devices ON
|
||||||
|
+ """
|
||||||
|
+ return TaskContainer.to_object_path(
|
||||||
|
+ self.implementation.set_autoconnect_priority_with_task()
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
def SwitchNetworkDevicesWithTask(self) -> ObjPath:
|
||||||
|
"""Switch network devices ON
|
||||||
|
|
||||||
|
diff --git a/pyanaconda/network.py b/pyanaconda/network.py
|
||||||
|
index f7fa48c..7179c19 100644
|
||||||
|
--- a/pyanaconda/network.py
|
||||||
|
+++ b/pyanaconda/network.py
|
||||||
|
@@ -46,6 +46,8 @@ from pyanaconda.modules.common.structures.network import NetworkDeviceInfo
|
||||||
|
from pyanaconda.modules.common.util import is_module_available
|
||||||
|
from pyanaconda.anaconda_loggers import get_module_logger
|
||||||
|
|
||||||
|
+import subprocess
|
||||||
|
+
|
||||||
|
log = get_module_logger(__name__)
|
||||||
|
|
||||||
|
DEFAULT_HOSTNAME = "localhost.localdomain"
|
||||||
|
@@ -274,6 +276,72 @@ def run_network_initialization_task(task_path):
|
||||||
|
log.debug(msg)
|
||||||
|
|
||||||
|
|
||||||
|
+def configure_connections(client, settings, check_link=True):
|
||||||
|
+ """
|
||||||
|
+ Configure connection parameters for all wired network devices with link in up state.
|
||||||
|
+ Return list of device names affected
|
||||||
|
+ :param client: Network Manager client object
|
||||||
|
+ :param settings: dict(str, str) = {name:value} of the setting to configure
|
||||||
|
+ :param check_link: True = handle network devices with link in up state only
|
||||||
|
+ :rtype list(str)
|
||||||
|
+ """
|
||||||
|
+ log.debug("start configuring autoconnect for all network devices with link in up state")
|
||||||
|
+ if not client:
|
||||||
|
+ log.debug("NM client not available")
|
||||||
|
+ return []
|
||||||
|
+ devices = client.get_devices()
|
||||||
|
+ if not devices:
|
||||||
|
+ log.debug("No devices found")
|
||||||
|
+ return []
|
||||||
|
+ if not settings:
|
||||||
|
+ log.debug("No settings passed")
|
||||||
|
+ return []
|
||||||
|
+ changed = False
|
||||||
|
+ ifaces = set()
|
||||||
|
+ for device in devices:
|
||||||
|
+ if not device:
|
||||||
|
+ continue
|
||||||
|
+ switched = False
|
||||||
|
+ iface = device.get_iface()
|
||||||
|
+ if not device_type_is_supported_wired(device.get_device_type()):
|
||||||
|
+ log.debug("device %s is not wired, skipping", iface)
|
||||||
|
+ continue
|
||||||
|
+ # check if the link for the device is up
|
||||||
|
+ if check_link:
|
||||||
|
+ try:
|
||||||
|
+ carrier = device.get_carrier()
|
||||||
|
+ except AttributeError:
|
||||||
|
+ carrier = None
|
||||||
|
+ if carrier:
|
||||||
|
+ log.debug("device %s link is up", iface)
|
||||||
|
+ else:
|
||||||
|
+ log.debug("device %s link is down", iface)
|
||||||
|
+ # skip modifying the autoconnect.priority setting for the device if link is down
|
||||||
|
+ continue
|
||||||
|
+ connections = device.get_available_connections()
|
||||||
|
+ if not connections:
|
||||||
|
+ log.debug("No available connections for device %s", iface)
|
||||||
|
+ continue
|
||||||
|
+ for con in connections:
|
||||||
|
+ if not con:
|
||||||
|
+ continue
|
||||||
|
+ uuid = con.get_uuid()
|
||||||
|
+ cmd_line = ["nmcli", "connection", "modify", "uuid", uuid]
|
||||||
|
+ for setting_name in settings:
|
||||||
|
+ setting_value = settings[setting_name]
|
||||||
|
+ cmd_line.extend([setting_name, setting_value])
|
||||||
|
+ p = subprocess.run(cmd_line, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=False, close_fds=True)
|
||||||
|
+ log.debug("update settings for connection %s for device %s, nmcli exit code = %s", uuid, iface, str(p.returncode))
|
||||||
|
+ ifaces.add(iface)
|
||||||
|
+ switched = changed = True
|
||||||
|
+ if switched:
|
||||||
|
+ log.info("connection settings for device %s updated", iface)
|
||||||
|
+ if not changed:
|
||||||
|
+ log.debug("No settings for devices updated")
|
||||||
|
+ log.debug("finish configuring autoconnect for all network devices with link in up state")
|
||||||
|
+ return list(ifaces)
|
||||||
|
+
|
||||||
|
+
|
||||||
|
def switch_all_network_devices(client, activate=True, check_link=True, wait=True):
|
||||||
|
"""
|
||||||
|
Switch ON (or OFF) all wired network devices with link in up state.
|
||||||
|
@@ -379,6 +447,7 @@ def initialize_network():
|
||||||
|
run_network_initialization_task(network_proxy.SetRealOnbootValuesFromKickstartWithTask())
|
||||||
|
if interactive_mode:
|
||||||
|
run_network_initialization_task(network_proxy.SwitchNetworkDevicesWithTask())
|
||||||
|
+ run_network_initialization_task(network_proxy.SetAutoconnectPriorityWithTask())
|
||||||
|
else:
|
||||||
|
log.debug("Not activating all wired network devices in non-interactive mode")
|
||||||
|
|
||||||
|
--
|
||||||
|
2.39.3
|
||||||
|
|
@ -1,25 +0,0 @@
|
|||||||
From b9fe4624a8f34bac765fd2788abebfec429cc0a2 Mon Sep 17 00:00:00 2001
|
|
||||||
From: tigro <tigro@msvsphere-os.ru>
|
|
||||||
Date: Mon, 12 Aug 2024 12:29:06 +0300
|
|
||||||
Subject: [PATCH 16/16] Set LatGrkCyr-8x16 as default font instead of eurlatgr
|
|
||||||
|
|
||||||
---
|
|
||||||
pyanaconda/core/constants.py | 2 +-
|
|
||||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/pyanaconda/core/constants.py b/pyanaconda/core/constants.py
|
|
||||||
index 78577cb..0bd5227 100644
|
|
||||||
--- a/pyanaconda/core/constants.py
|
|
||||||
+++ b/pyanaconda/core/constants.py
|
|
||||||
@@ -78,7 +78,7 @@ DEFAULT_LANG = "ru_RU.UTF-8"
|
|
||||||
# we use Russian by default for UI
|
|
||||||
DEFAULT_HELP_LANG = "en_US.UTF-8"
|
|
||||||
|
|
||||||
-DEFAULT_VC_FONT = "eurlatgr"
|
|
||||||
+DEFAULT_VC_FONT = "LatGrkCyr-8x16"
|
|
||||||
|
|
||||||
DEFAULT_KEYBOARD = "us"
|
|
||||||
|
|
||||||
--
|
|
||||||
2.46.0
|
|
||||||
|
|
@ -1,488 +0,0 @@
|
|||||||
From 2716b292b9d42961222fd645c6b2d281d46d6688 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Dmitry Samoylik <Dmitriy.Samoylik@softline.com>
|
|
||||||
Date: Thu, 26 Sep 2024 16:57:48 +0300
|
|
||||||
Subject: [PATCH] Implement show EULA before installation
|
|
||||||
|
|
||||||
---
|
|
||||||
data/anaconda.conf | 4 +-
|
|
||||||
pyanaconda/core/configuration/license.py | 2 -
|
|
||||||
pyanaconda/core/eula.py | 23 ++++
|
|
||||||
pyanaconda/ui/categories/eula.py | 14 +++
|
|
||||||
pyanaconda/ui/gui/spokes/eula.glade | 136 +++++++++++++++++++++++
|
|
||||||
pyanaconda/ui/gui/spokes/eula.py | 107 ++++++++++++++++++
|
|
||||||
pyanaconda/ui/tui/spokes/eula.py | 128 +++++++++++++++++++++
|
|
||||||
7 files changed, 409 insertions(+), 5 deletions(-)
|
|
||||||
create mode 100644 pyanaconda/core/eula.py
|
|
||||||
create mode 100644 pyanaconda/ui/categories/eula.py
|
|
||||||
create mode 100644 pyanaconda/ui/gui/spokes/eula.glade
|
|
||||||
create mode 100644 pyanaconda/ui/gui/spokes/eula.py
|
|
||||||
create mode 100644 pyanaconda/ui/tui/spokes/eula.py
|
|
||||||
|
|
||||||
diff --git a/data/anaconda.conf b/data/anaconda.conf
|
|
||||||
index b5878e3..c15e99d 100644
|
|
||||||
--- a/data/anaconda.conf
|
|
||||||
+++ b/data/anaconda.conf
|
|
||||||
@@ -308,9 +308,7 @@ password_policies =
|
|
||||||
# If the given distribution has an EULA & feels the need to
|
|
||||||
# tell the user about it fill in this variable by a path
|
|
||||||
# pointing to a file with the EULA on the installed system.
|
|
||||||
-#
|
|
||||||
-# This is currently used just to show the path to the file to
|
|
||||||
-# the user at the end of the installation.
|
|
||||||
+
|
|
||||||
eula =
|
|
||||||
|
|
||||||
|
|
||||||
diff --git a/pyanaconda/core/configuration/license.py b/pyanaconda/core/configuration/license.py
|
|
||||||
index 04c44bf..a51f52a 100644
|
|
||||||
--- a/pyanaconda/core/configuration/license.py
|
|
||||||
+++ b/pyanaconda/core/configuration/license.py
|
|
||||||
@@ -31,7 +31,5 @@ class LicenseSection(Section):
|
|
||||||
tell the user about it fill in this variable by a path
|
|
||||||
pointing to a file with the EULA on the installed system.
|
|
||||||
|
|
||||||
- This is currently used just to show the path to the file to
|
|
||||||
- the user at the end of the installation.
|
|
||||||
"""
|
|
||||||
return self._get_option("eula", str)
|
|
||||||
diff --git a/pyanaconda/core/eula.py b/pyanaconda/core/eula.py
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..15a393e
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/pyanaconda/core/eula.py
|
|
||||||
@@ -0,0 +1,23 @@
|
|
||||||
+import os
|
|
||||||
+from pyanaconda.core.configuration.anaconda import conf
|
|
||||||
+
|
|
||||||
+def get_license_file_name():
|
|
||||||
+ """Get filename of the license file best matching current localization settings.
|
|
||||||
+ :return: filename of the license file or None if no license file found
|
|
||||||
+ :rtype: str or None
|
|
||||||
+ """
|
|
||||||
+ if not conf.license.eula:
|
|
||||||
+ return None
|
|
||||||
+
|
|
||||||
+ if not os.path.exists(conf.license.eula):
|
|
||||||
+ return None
|
|
||||||
+
|
|
||||||
+ return conf.license.eula
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+def eula_available():
|
|
||||||
+ """Report if it looks like there is an EULA available on the system.
|
|
||||||
+ :return: True if an EULA seems to be available, False otherwise
|
|
||||||
+ :rtype: bool
|
|
||||||
+ """
|
|
||||||
+ return bool(get_license_file_name())
|
|
||||||
diff --git a/pyanaconda/ui/categories/eula.py b/pyanaconda/ui/categories/eula.py
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..0a4fe96
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/pyanaconda/ui/categories/eula.py
|
|
||||||
@@ -0,0 +1,14 @@
|
|
||||||
+from pyanaconda.ui.categories import SpokeCategory
|
|
||||||
+from pyanaconda.core.i18n import _
|
|
||||||
+
|
|
||||||
+__all__ = ["LicensingCategory"]
|
|
||||||
+
|
|
||||||
+class LicensingCategory(SpokeCategory):
|
|
||||||
+
|
|
||||||
+ @staticmethod
|
|
||||||
+ def get_title():
|
|
||||||
+ return _("LICENSING")
|
|
||||||
+
|
|
||||||
+ @staticmethod
|
|
||||||
+ def get_sort_order():
|
|
||||||
+ return 900
|
|
||||||
diff --git a/pyanaconda/ui/gui/spokes/eula.glade b/pyanaconda/ui/gui/spokes/eula.glade
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..1d340f0
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/pyanaconda/ui/gui/spokes/eula.glade
|
|
||||||
@@ -0,0 +1,136 @@
|
|
||||||
+<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
+<interface>
|
|
||||||
+ <!-- interface-requires gtk+ 3.6 -->
|
|
||||||
+ <!-- interface-requires AnacondaWidgets 1.0 -->
|
|
||||||
+ <object class="GtkTextBuffer" id="eulaBuffer">
|
|
||||||
+ <property name="text">The license will go here</property>
|
|
||||||
+ </object>
|
|
||||||
+ <object class="AnacondaSpokeWindow" id="eulaWindow">
|
|
||||||
+ <property name="can_focus">False</property>
|
|
||||||
+ <property name="hexpand">True</property>
|
|
||||||
+ <property name="vexpand">True</property>
|
|
||||||
+ <property name="window_name" translatable="yes">License Information</property>
|
|
||||||
+ <signal name="button-clicked" handler="on_back_clicked" swapped="no"/>
|
|
||||||
+ <child internal-child="main_box">
|
|
||||||
+ <object class="GtkBox" id="AnacondaSpokeWindow-main_box1">
|
|
||||||
+ <property name="can_focus">False</property>
|
|
||||||
+ <property name="orientation">vertical</property>
|
|
||||||
+ <property name="spacing">6</property>
|
|
||||||
+ <child internal-child="nav_box">
|
|
||||||
+ <object class="GtkEventBox" id="AnacondaSpokeWindow-nav_box1">
|
|
||||||
+ <property name="can_focus">False</property>
|
|
||||||
+ <child internal-child="nav_area">
|
|
||||||
+ <object class="GtkGrid" id="AnacondaSpokeWindow-nav_area1">
|
|
||||||
+ <property name="can_focus">False</property>
|
|
||||||
+ <property name="margin_left">6</property>
|
|
||||||
+ <property name="margin_right">6</property>
|
|
||||||
+ <property name="margin_top">6</property>
|
|
||||||
+ </object>
|
|
||||||
+ </child>
|
|
||||||
+ </object>
|
|
||||||
+ <packing>
|
|
||||||
+ <property name="expand">False</property>
|
|
||||||
+ <property name="fill">False</property>
|
|
||||||
+ <property name="position">0</property>
|
|
||||||
+ </packing>
|
|
||||||
+ </child>
|
|
||||||
+ <child internal-child="alignment">
|
|
||||||
+ <object class="GtkAlignment" id="AnacondaSpokeWindow-alignment1">
|
|
||||||
+ <property name="can_focus">False</property>
|
|
||||||
+ <property name="xscale">0.8</property>
|
|
||||||
+ <property name="yscale">0.8</property>
|
|
||||||
+ <child internal-child="action_area">
|
|
||||||
+ <object class="GtkBox" id="mainBox">
|
|
||||||
+ <property name="can_focus">False</property>
|
|
||||||
+ <property name="orientation">vertical</property>
|
|
||||||
+ <child>
|
|
||||||
+ <object class="GtkLabel" id="licenseAgreementLabel">
|
|
||||||
+ <property name="visible">True</property>
|
|
||||||
+ <property name="can_focus">False</property>
|
|
||||||
+ <property name="halign">start</property>
|
|
||||||
+ <property name="margin_top">24</property>
|
|
||||||
+ <property name="margin_bottom">6</property>
|
|
||||||
+ <property name="label" translatable="yes">License Agreement:</property>
|
|
||||||
+ </object>
|
|
||||||
+ <packing>
|
|
||||||
+ <property name="expand">False</property>
|
|
||||||
+ <property name="fill">True</property>
|
|
||||||
+ <property name="position">0</property>
|
|
||||||
+ </packing>
|
|
||||||
+ </child>
|
|
||||||
+ <child>
|
|
||||||
+ <object class="GtkBox" id="eulaBox">
|
|
||||||
+ <property name="visible">True</property>
|
|
||||||
+ <property name="can_focus">False</property>
|
|
||||||
+ <property name="hexpand">True</property>
|
|
||||||
+ <property name="vexpand">True</property>
|
|
||||||
+ <property name="orientation">vertical</property>
|
|
||||||
+ <child>
|
|
||||||
+ <object class="GtkScrolledWindow" id="eulaScrolledWindow">
|
|
||||||
+ <property name="visible">True</property>
|
|
||||||
+ <property name="can_focus">True</property>
|
|
||||||
+ <property name="shadow_type">in</property>
|
|
||||||
+ <child>
|
|
||||||
+ <object class="GtkTextView" id="eulaView">
|
|
||||||
+ <property name="visible">True</property>
|
|
||||||
+ <property name="can_focus">True</property>
|
|
||||||
+ <property name="margin_bottom">18</property>
|
|
||||||
+ <property name="hexpand">True</property>
|
|
||||||
+ <property name="vexpand">True</property>
|
|
||||||
+ <property name="vscroll_policy">natural</property>
|
|
||||||
+ <property name="pixels_above_lines">12</property>
|
|
||||||
+ <property name="editable">False</property>
|
|
||||||
+ <property name="wrap_mode">word</property>
|
|
||||||
+ <property name="left_margin">12</property>
|
|
||||||
+ <property name="right_margin">12</property>
|
|
||||||
+ <property name="cursor_visible">False</property>
|
|
||||||
+ <property name="buffer">eulaBuffer</property>
|
|
||||||
+ </object>
|
|
||||||
+ </child>
|
|
||||||
+ </object>
|
|
||||||
+ <packing>
|
|
||||||
+ <property name="expand">False</property>
|
|
||||||
+ <property name="fill">True</property>
|
|
||||||
+ <property name="position">0</property>
|
|
||||||
+ </packing>
|
|
||||||
+ </child>
|
|
||||||
+ <child>
|
|
||||||
+ <object class="GtkCheckButton" id="agreeCheckButton">
|
|
||||||
+ <property name="label" translatable="yes">I _accept the license agreement</property>
|
|
||||||
+ <property name="visible">True</property>
|
|
||||||
+ <property name="can_focus">True</property>
|
|
||||||
+ <property name="receives_default">False</property>
|
|
||||||
+ <property name="use_underline">True</property>
|
|
||||||
+ <property name="xalign">0</property>
|
|
||||||
+ <property name="draw_indicator">True</property>
|
|
||||||
+ <signal name="toggled" handler="on_check_button_toggled" swapped="no"/>
|
|
||||||
+ </object>
|
|
||||||
+ <packing>
|
|
||||||
+ <property name="expand">False</property>
|
|
||||||
+ <property name="fill">True</property>
|
|
||||||
+ <property name="position">2</property>
|
|
||||||
+ </packing>
|
|
||||||
+ </child>
|
|
||||||
+ </object>
|
|
||||||
+ <packing>
|
|
||||||
+ <property name="expand">False</property>
|
|
||||||
+ <property name="fill">True</property>
|
|
||||||
+ <property name="position">1</property>
|
|
||||||
+ </packing>
|
|
||||||
+ </child>
|
|
||||||
+ </object>
|
|
||||||
+ </child>
|
|
||||||
+ </object>
|
|
||||||
+ <packing>
|
|
||||||
+ <property name="expand">True</property>
|
|
||||||
+ <property name="fill">True</property>
|
|
||||||
+ <property name="position">1</property>
|
|
||||||
+ </packing>
|
|
||||||
+ </child>
|
|
||||||
+ <child>
|
|
||||||
+ <placeholder/>
|
|
||||||
+ </child>
|
|
||||||
+ </object>
|
|
||||||
+ </child>
|
|
||||||
+ </object>
|
|
||||||
+</interface>
|
|
||||||
diff --git a/pyanaconda/ui/gui/spokes/eula.py b/pyanaconda/ui/gui/spokes/eula.py
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..a487c6b
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/pyanaconda/ui/gui/spokes/eula.py
|
|
||||||
@@ -0,0 +1,107 @@
|
|
||||||
+import logging
|
|
||||||
+
|
|
||||||
+from pyanaconda.ui.common import FirstbootOnlySpokeMixIn
|
|
||||||
+from pyanaconda.ui.gui.spokes import NormalSpoke
|
|
||||||
+from pyanaconda.core.i18n import _, CN_
|
|
||||||
+from pyanaconda.core import eula
|
|
||||||
+from pyanaconda.ui.categories.eula import LicensingCategory
|
|
||||||
+from pyanaconda.anaconda_loggers import get_module_logger
|
|
||||||
+from pykickstart.constants import FIRSTBOOT_RECONFIG
|
|
||||||
+
|
|
||||||
+log = get_module_logger(__name__)
|
|
||||||
+__all__ = ["EULASpoke"]
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+class EULASpoke(FirstbootOnlySpokeMixIn, NormalSpoke):
|
|
||||||
+ """The EULA spoke"""
|
|
||||||
+
|
|
||||||
+ builderObjects = ["eulaBuffer", "eulaWindow"]
|
|
||||||
+ mainWidgetName = "eulaWindow"
|
|
||||||
+ uiFile = "spokes/eula.glade"
|
|
||||||
+ icon = "application-certificate-symbolic"
|
|
||||||
+ title = CN_("GUI|Spoke", "_License Information")
|
|
||||||
+ category = LicensingCategory
|
|
||||||
+
|
|
||||||
+ @staticmethod
|
|
||||||
+ def get_screen_id():
|
|
||||||
+ """Return a unique id of this UI screen."""
|
|
||||||
+ return "license-information"
|
|
||||||
+
|
|
||||||
+ def initialize(self):
|
|
||||||
+ log.debug("initializing the EULA spoke")
|
|
||||||
+ NormalSpoke.initialize(self)
|
|
||||||
+
|
|
||||||
+ self._have_eula = True
|
|
||||||
+ self._eula_buffer = self.builder.get_object("eulaBuffer")
|
|
||||||
+ self._agree_check_button = self.builder.get_object("agreeCheckButton")
|
|
||||||
+ self._agree_label = self._agree_check_button.get_child()
|
|
||||||
+ self._agree_text = self._agree_label.get_text()
|
|
||||||
+
|
|
||||||
+ log.debug("looking for the license file")
|
|
||||||
+ license_file = eula.get_license_file_name()
|
|
||||||
+ if not license_file:
|
|
||||||
+ log.error("no license found")
|
|
||||||
+ self._have_eula = False
|
|
||||||
+ self._eula_buffer.set_text(_("No license found"))
|
|
||||||
+ return
|
|
||||||
+
|
|
||||||
+ # if there is "eula <...>" in kickstart, use its value
|
|
||||||
+ if self.data.eula.agreed is not None:
|
|
||||||
+ self._agree_check_button.set_active(self.data.eula.agreed)
|
|
||||||
+
|
|
||||||
+ self._eula_buffer.set_text("")
|
|
||||||
+ itr = self._eula_buffer.get_iter_at_offset(0)
|
|
||||||
+ log.debug("opening the license file")
|
|
||||||
+ with open(license_file, "r") as fobj:
|
|
||||||
+ # insert the first line without prefixing with space
|
|
||||||
+ try:
|
|
||||||
+ first_line = next(fobj)
|
|
||||||
+ except StopIteration:
|
|
||||||
+ # nothing in the file
|
|
||||||
+ return
|
|
||||||
+ self._eula_buffer.insert(itr, first_line.strip())
|
|
||||||
+
|
|
||||||
+ # EULA file may be preformatted for the console, we want to let Gtk
|
|
||||||
+ # format it (blank lines should be preserved)
|
|
||||||
+ for line in fobj:
|
|
||||||
+ stripped_line = line.strip()
|
|
||||||
+ if stripped_line:
|
|
||||||
+ self._eula_buffer.insert(itr, " " + stripped_line)
|
|
||||||
+ else:
|
|
||||||
+ self._eula_buffer.insert(itr, "\n\n")
|
|
||||||
+
|
|
||||||
+ def refresh(self):
|
|
||||||
+ self._agree_check_button.set_sensitive(self._have_eula)
|
|
||||||
+ self._agree_check_button.set_active(self.data.eula.agreed)
|
|
||||||
+
|
|
||||||
+ def apply(self):
|
|
||||||
+ self.data.eula.agreed = self._agree_check_button.get_active()
|
|
||||||
+
|
|
||||||
+ @property
|
|
||||||
+ def completed(self):
|
|
||||||
+ return not self._have_eula or self.data.eula.agreed
|
|
||||||
+
|
|
||||||
+ @property
|
|
||||||
+ def status(self):
|
|
||||||
+ if not self._have_eula:
|
|
||||||
+ return _("No license found")
|
|
||||||
+
|
|
||||||
+ return _("License accepted") if self.data.eula.agreed else _("License not accepted")
|
|
||||||
+
|
|
||||||
+ @classmethod
|
|
||||||
+ def should_run(cls, environment, data):
|
|
||||||
+ if eula.eula_available():
|
|
||||||
+ # don't run if we are in initial-setup in reconfig mode and the EULA has already been accepted
|
|
||||||
+ if FirstbootOnlySpokeMixIn.should_run(environment, data) and data and data.firstboot.firstboot == FIRSTBOOT_RECONFIG and data.eula.agreed:
|
|
||||||
+ log.debug("not running license spoke: reconfig mode & license already accepted")
|
|
||||||
+ return False
|
|
||||||
+ return True
|
|
||||||
+ return False
|
|
||||||
+
|
|
||||||
+ def on_check_button_toggled(self, *args):
|
|
||||||
+ if self._agree_check_button.get_active():
|
|
||||||
+ log.debug("license is now accepted")
|
|
||||||
+ self._agree_label.set_markup("<b>%s</b>" % self._agree_text)
|
|
||||||
+ else:
|
|
||||||
+ log.debug("license no longer accepted")
|
|
||||||
+ self._agree_label.set_markup(self._agree_text)
|
|
||||||
diff --git a/pyanaconda/ui/tui/spokes/eula.py b/pyanaconda/ui/tui/spokes/eula.py
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..a3e8e62
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/pyanaconda/ui/tui/spokes/eula.py
|
|
||||||
@@ -0,0 +1,128 @@
|
|
||||||
+import logging
|
|
||||||
+
|
|
||||||
+from pyanaconda.ui.tui.spokes import NormalTUISpoke
|
|
||||||
+from simpleline.render.widgets import TextWidget, CheckboxWidget
|
|
||||||
+from simpleline.render.containers import ListRowContainer
|
|
||||||
+from simpleline.render.screen import UIScreen, InputState
|
|
||||||
+from simpleline.render.screen_handler import ScreenHandler
|
|
||||||
+from pyanaconda.ui.common import FirstbootOnlySpokeMixIn
|
|
||||||
+from pyanaconda.core import eula
|
|
||||||
+from pyanaconda.ui.categories.eula import LicensingCategory
|
|
||||||
+from pyanaconda.core.i18n import _, N_
|
|
||||||
+from pykickstart.constants import FIRSTBOOT_RECONFIG
|
|
||||||
+
|
|
||||||
+log = logging.getLogger("initial-setup")
|
|
||||||
+
|
|
||||||
+__all__ = ["EULASpoke"]
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+class EULASpoke(FirstbootOnlySpokeMixIn, NormalTUISpoke):
|
|
||||||
+ """The EULA spoke providing ways to read the license and agree/disagree with it."""
|
|
||||||
+
|
|
||||||
+ category = LicensingCategory
|
|
||||||
+
|
|
||||||
+ @staticmethod
|
|
||||||
+ def get_screen_id():
|
|
||||||
+ """Return a unique id of this UI screen."""
|
|
||||||
+ return "license-information"
|
|
||||||
+
|
|
||||||
+ def __init__(self, *args, **kwargs):
|
|
||||||
+ NormalTUISpoke.__init__(self, *args, **kwargs)
|
|
||||||
+ self.title = _("License information")
|
|
||||||
+ self._container = None
|
|
||||||
+
|
|
||||||
+ def initialize(self):
|
|
||||||
+ NormalTUISpoke.initialize(self)
|
|
||||||
+
|
|
||||||
+ def refresh(self, args=None):
|
|
||||||
+ NormalTUISpoke.refresh(self, args)
|
|
||||||
+
|
|
||||||
+ self._container = ListRowContainer(1)
|
|
||||||
+
|
|
||||||
+ log.debug("license found")
|
|
||||||
+ # make the options aligned to the same column (the checkbox has the
|
|
||||||
+ # '[ ]' prepended)
|
|
||||||
+ self._container.add(TextWidget("%s\n" % _("Read the License Agreement")),
|
|
||||||
+ self._show_license_screen_callback)
|
|
||||||
+
|
|
||||||
+ self._container.add(CheckboxWidget(title=_("I accept the license agreement"),
|
|
||||||
+ completed=self.data.eula.agreed),
|
|
||||||
+ self._license_accepted_callback)
|
|
||||||
+ self.window.add_with_separator(self._container)
|
|
||||||
+
|
|
||||||
+ @property
|
|
||||||
+ def completed(self):
|
|
||||||
+ # Either there is no EULA available, or user agrees/disagrees with it.
|
|
||||||
+ return self.data.eula.agreed
|
|
||||||
+
|
|
||||||
+ @property
|
|
||||||
+ def mandatory(self):
|
|
||||||
+ # This spoke is always mandatory.
|
|
||||||
+ return True
|
|
||||||
+
|
|
||||||
+ @property
|
|
||||||
+ def status(self):
|
|
||||||
+ return _("License accepted") if self.data.eula.agreed else _("License not accepted")
|
|
||||||
+
|
|
||||||
+ @classmethod
|
|
||||||
+ def should_run(cls, environment, data):
|
|
||||||
+ if eula.eula_available():
|
|
||||||
+ # don't run if we are in initial-setup in reconfig mode and the EULA has already been accepted
|
|
||||||
+ if FirstbootOnlySpokeMixIn.should_run(environment, data) and data and data.firstboot.firstboot == FIRSTBOOT_RECONFIG and data.eula.agreed:
|
|
||||||
+ log.debug("not running license spoke: reconfig mode & license already accepted")
|
|
||||||
+ return False
|
|
||||||
+ return True
|
|
||||||
+ return False
|
|
||||||
+
|
|
||||||
+ def apply(self):
|
|
||||||
+ # nothing needed here, the agreed field is changed in the input method
|
|
||||||
+ pass
|
|
||||||
+
|
|
||||||
+ def input(self, args, key):
|
|
||||||
+ if not self._container.process_user_input(key):
|
|
||||||
+ return key
|
|
||||||
+
|
|
||||||
+ return InputState.PROCESSED
|
|
||||||
+
|
|
||||||
+ @staticmethod
|
|
||||||
+ def _show_license_screen_callback(data):
|
|
||||||
+ # show license
|
|
||||||
+ log.debug("showing the license")
|
|
||||||
+ eula_screen = LicenseScreen()
|
|
||||||
+ ScreenHandler.push_screen(eula_screen)
|
|
||||||
+
|
|
||||||
+ def _license_accepted_callback(self, data):
|
|
||||||
+ # toggle EULA agreed checkbox by changing ksdata
|
|
||||||
+ log.debug("license accepted state changed to: %s", self.data.eula.agreed)
|
|
||||||
+ self.data.eula.agreed = not self.data.eula.agreed
|
|
||||||
+ self.redraw()
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+class LicenseScreen(UIScreen):
|
|
||||||
+ """Screen showing the License without any input from user requested."""
|
|
||||||
+
|
|
||||||
+ def __init__(self):
|
|
||||||
+ super().__init__()
|
|
||||||
+
|
|
||||||
+ self._license_file = eula.get_license_file_name()
|
|
||||||
+
|
|
||||||
+ def refresh(self, args=None):
|
|
||||||
+ super().refresh(args)
|
|
||||||
+
|
|
||||||
+ # read the license file and make it one long string so that it can be
|
|
||||||
+ # processed by the TextWidget to fit in the screen in a best possible
|
|
||||||
+ # way
|
|
||||||
+ log.debug("reading the license file")
|
|
||||||
+ with open(self._license_file, 'r') as f:
|
|
||||||
+ license_text = f.read()
|
|
||||||
+
|
|
||||||
+ self.window.add_with_separator(TextWidget(license_text))
|
|
||||||
+
|
|
||||||
+ def input(self, args, key):
|
|
||||||
+ """ Handle user input. """
|
|
||||||
+ return InputState.PROCESSED_AND_CLOSE
|
|
||||||
+
|
|
||||||
+ def prompt(self, args=None):
|
|
||||||
+ # we don't want to prompt user, just close the screen
|
|
||||||
+ self.close()
|
|
||||||
+ return None
|
|
||||||
--
|
|
||||||
2.39.2
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue