[master] UTC/localtime HW clock heuristic
by Vratislav Podzimek
PATCH [1/2] is just a minor change without any significant result.
PATCH [2/2] adds a heuristic to guess wheter HW clock uses UTC or local
time by searching for bootable NTFS partitions. It adds two threads, but
these are really lightweight and just handle the potential long storage
initialization.
Vratislav Podzimek (2):
Return bool value from the GRUB.has_windows method
Set system time from HW clock and guess if it is UTC
anaconda | 11 ++++++++-
pyanaconda/bootloader.py | 2 +-
pyanaconda/kickstart.py | 7 ------
pyanaconda/timezone.py | 38 ++++++++++++++++++++++++++++++
pyanaconda/ui/gui/spokes/datetime_spoke.py | 20 ++++++++++++++++
5 files changed, 69 insertions(+), 9 deletions(-)
--
1.7.11.7
10 years, 11 months
[PATCH] remove the remnants of sparc support
by Dennis Gilmore
Signed-off-by: Dennis Gilmore <dennis(a)ausil.us>
---
configure.ac | 5 +--
pyanaconda/bootloader.py | 86 ++-------------------------------------------
pyanaconda/isys/__init__.py | 2 +-
pyanaconda/isys/isys.c | 2 +-
4 files changed, 5 insertions(+), 90 deletions(-)
diff --git a/configure.ac b/configure.ac
index 71c3285..345b6df 100644
--- a/configure.ac
+++ b/configure.ac
@@ -171,7 +171,7 @@ rel="`awk '/Release:/ { split($2, r, "%"); print r[[1]] }' anaconda.spec.in`"
AC_SUBST(PACKAGE_RELEASE, [$rel])
# Set $(ARCH) and arch-related tests
-s_arch="`uname -m | sed -e s/i.86/i386/ -e s/sparc.*/sparc/ -e s/ppc.*/ppc/`"
+s_arch="`uname -m | sed -e s/i.86/i386/ -e s/ppc.*/ppc/`"
AC_SUBST(ARCH, [$s_arch])
AM_CONDITIONAL(IS_LIVEINST_ARCH,
@@ -195,9 +195,6 @@ AM_CONDITIONAL(IS_S390,
AM_CONDITIONAL(IS_X86_64,
[test x$s_arch == xx86_64])
-AM_CONDITIONAL(IS_SPARC,
- [test x$s_arch == xsparc || test x$s_arch == xsparc64])
-
AC_CONFIG_SUBDIRS([widgets])
AC_CONFIG_FILES([Makefile
diff --git a/pyanaconda/bootloader.py b/pyanaconda/bootloader.py
index c24ccc3..a802ca8 100644
--- a/pyanaconda/bootloader.py
+++ b/pyanaconda/bootloader.py
@@ -900,7 +900,6 @@ class BootLoader(object):
def write_config_images(self, config):
"""Write image configuration entries."""
- # XXX might this be identical for yaboot and silo?
raise NotImplementedError()
def write_config_post(self):
@@ -1707,7 +1706,7 @@ class MacEFIGRUB(EFIGRUB):
self.mactel_config()
-class YabootSILOBase(BootLoader):
+class YabootBase(BootLoader):
def write_config_password(self, config):
if self.password:
config.write("password=%s\n" % self.password)
@@ -1751,7 +1750,7 @@ class YabootSILOBase(BootLoader):
config.write(stanza)
-class Yaboot(YabootSILOBase):
+class Yaboot(YabootBase):
name = "Yaboot"
_config_file = "yaboot.conf"
prog = "ybin"
@@ -2070,86 +2069,6 @@ class ZIPL(BootLoader):
message = iutil.reIPL(self.stage1_name)
log.info(message)
-class SILO(YabootSILOBase):
- name = "SILO"
- _config_file = "silo.conf"
- message_file = "/etc/silo.message"
-
- # stage1 device requirements
- stage1_device_types = ["disk"]
-
- # stage2 device requirements
- stage2_device_types = ["partition"]
-
- packages = ["silo"]
-
- image_label_attr = "short_label"
-
- #
- # configuration
- #
-
- @property
- def config_dir(self):
- if self.stage2_device.format.mountpoint == "/boot":
- return "/boot"
- else:
- return "/etc"
-
- @property
- def config_file(self):
- return "%s/%s" % (self.config_dir, self._config_file)
-
- def write_message_file(self):
- message_file = os.path.normpath(ROOT_PATH + self.message_file)
- f = open(message_file, "w")
- f.write("Welcome to %s!\nHit <TAB> for boot options\n\n" % productName)
- f.close()
- os.chmod(message_file, 0600)
-
- def write_config_header(self, config):
- header = ("# silo.conf generated by anaconda\n\n"
- "#boot=%(stage1dev)s\n"
- "message=%(message)s\n"
- "timeout=%(timeout)d\n"
- "partition=%(boot_part_num)d\n"
- "default=%(default)s\n"
- % {"stage1dev": self.stage1_device.path,
- "message": self.message_file, "timeout": self.timeout,
- "boot_part_num": self.stage1_device.partedPartition.number,
- "default": self.image_label(self.default)})
- config.write(header)
- self.write_config_password(config)
-
- def write_config_post(self):
- etc_silo = os.path.normpath(ROOT_PATH + "/etc/" + self._config_file)
- if not os.access(etc_silo, os.R_OK):
- try:
- os.symlink("../boot/%s" % self._config_file, etc_silo)
- except OSError as e:
- log.warning("failed to create /etc/silo.conf symlink: %s" % e)
-
- def write_config(self):
- self.write_message_file()
- super(SILO, self).write_config()
-
- #
- # installation
- #
-
- def install(self):
- backup = "%s/backup.b" % self.config_dir
- args = ["-f", "-C", self.config_file, "-S", backup]
- variant = iutil.getSparcMachine()
- if variant in ("sun4u", "sun4v"):
- args.append("-u")
- else:
- args.append("-U")
-
- rc = iutil.execWithRedirect("silo", args, root=ROOT_PATH)
-
- if rc:
- raise BootLoaderError("bootloader install failed")
class UBOOT(BootLoader):
name = "UBOOT"
@@ -2199,7 +2118,6 @@ bootloader_by_platform = {platform.X86: GRUB2,
platform.IPSeriesPPC: IPSeriesGRUB2,
platform.NewWorldPPC: MacYaboot,
platform.S390: ZIPL,
- platform.Sparc: SILO,
platform.ARM: UBOOT,
platform.omapARM: UBOOT}
diff --git a/pyanaconda/isys/__init__.py b/pyanaconda/isys/__init__.py
index bbf4a2e..6953793 100755
--- a/pyanaconda/isys/__init__.py
+++ b/pyanaconda/isys/__init__.py
@@ -45,7 +45,7 @@ import dbus
import logging
log = logging.getLogger("anaconda")
-if blivet.arch.getArch() in ("sparc", "ppc64"):
+if blivet.arch.getArch() in ("ppc64"):
MIN_RAM = 768 * 1024
GUI_INSTALL_EXTRA_RAM = 512 * 1024
else:
diff --git a/pyanaconda/isys/isys.c b/pyanaconda/isys/isys.c
index d4e977c..c99cb19 100644
--- a/pyanaconda/isys/isys.c
+++ b/pyanaconda/isys/isys.c
@@ -26,7 +26,7 @@
#include <fcntl.h>
/* Need to tell loop.h what the actual dev_t type is. */
#undef dev_t
-#if defined(__alpha) || (defined(__sparc__) && defined(__arch64__))
+#if defined(__alpha)
#define dev_t unsigned int
#else
#if defined(__x86_64__)
--
1.8.1.4
11 years, 2 months
[master] Patch for exceptions in non-main thread in TUI
by Vratislav Podzimek
This patch provides a fix for the case when there is an exception
in a non-main thread in text mode. It is impossible to run the
exception handler in the non-main thread for many reasons. It competes
with the main thread for standard input, it cannot run libreport
because libreport forks, it cannot quit the installer because the main
thread would still be running and probably something else I didn't hit
yet. This builds on Martin's patch for processing our message queue in
text mode.
The only remaining problem is, that when the main thread runs raw_input
another call of raw_input from the exception handler is blocked until
the first one is finished. Thus one needs to hit ENTER before entering
any input for the exception handler. This can be fixed by telling
python-meh's exception handler that it should use our raw_input instead
of the built-in one but I am leaving this for an additional patch as it
needs some changes in python-meh (and thus new build).
Vratislav Podzimek (1):
Run exception handling in the main thread also in TUI
anaconda | 4 ++-
pyanaconda/exception.py | 74 ++++++++++++++++++++++++++++++++-----------
pyanaconda/ui/tui/__init__.py | 7 ++--
3 files changed, 64 insertions(+), 21 deletions(-)
--
1.7.11.7
11 years, 2 months
[PATCH 1/4] Add the User creation spoke including the Advanced dialog
by Martin Sivak
---
po/POTFILES.in | 3 +
pyanaconda/ui/gui/spokes/advanced_user.glade | 437 +++++++++++++++++++++++++++
pyanaconda/ui/gui/spokes/password.py | 2 +-
pyanaconda/ui/gui/spokes/user.glade | 377 +++++++++++++++++++++++
pyanaconda/ui/gui/spokes/user.py | 423 ++++++++++++++++++++++++++
5 files changed, 1241 insertions(+), 1 deletion(-)
create mode 100644 pyanaconda/ui/gui/spokes/advanced_user.glade
create mode 100644 pyanaconda/ui/gui/spokes/user.glade
create mode 100644 pyanaconda/ui/gui/spokes/user.py
diff --git a/po/POTFILES.in b/po/POTFILES.in
index aaa1231..c2ad78d 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -66,6 +66,7 @@ pyanaconda/ui/gui/spokes/password.py
pyanaconda/ui/gui/spokes/software.py
pyanaconda/ui/gui/spokes/source.py
pyanaconda/ui/gui/spokes/storage.py
+pyanaconda/ui/gui/spokes/user.py
pyanaconda/ui/gui/spokes/welcome.py
pyanaconda/ui/gui/spokes/lib/accordion.py
pyanaconda/ui/gui/spokes/lib/cart.py
@@ -73,6 +74,7 @@ pyanaconda/ui/gui/spokes/lib/passphrase.py
pyanaconda/ui/gui/spokes/lib/resize.py
# Interface files.
+pyanaconda/ui/gui/spokes/advanced_user.glade
pyanaconda/ui/gui/spokes/datetime_spoke.glade
pyanaconda/ui/gui/spokes/network.glade
pyanaconda/ui/gui/spokes/software.glade
@@ -81,6 +83,7 @@ pyanaconda/ui/gui/spokes/keyboard.glade
pyanaconda/ui/gui/spokes/password.glade
pyanaconda/ui/gui/spokes/source.glade
pyanaconda/ui/gui/spokes/welcome.glade
+pyanaconda/ui/gui/spokes/user.glade
pyanaconda/ui/gui/spokes/custom.glade
pyanaconda/ui/gui/spokes/lib/cart.glade
pyanaconda/ui/gui/spokes/lib/detailederror.glade
diff --git a/pyanaconda/ui/gui/spokes/advanced_user.glade b/pyanaconda/ui/gui/spokes/advanced_user.glade
new file mode 100644
index 0000000..6159f53
--- /dev/null
+++ b/pyanaconda/ui/gui/spokes/advanced_user.glade
@@ -0,0 +1,437 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <object class="GtkDialog" id="advancedUserDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">5</property>
+ <property name="type_hint">dialog</property>
+ <property name="decorated">False</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="button2">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button1">
+ <property name="label" translatable="yes">Save Changes</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_right">16</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">ADVANCED USER CONFIGURATION</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ <attribute name="scale" value="100"/>
+ <attribute name="size" value="125"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_top">8</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Home Directory</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">16</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkCheckButton" id="c_home">
+ <property name="label" translatable="yes">Create a _home directory for this user.</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="margin_top">4</property>
+ <property name="use_underline">True</property>
+ <property name="xalign">0</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="_apply_checkboxes" swapped="no"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">42</property>
+ <property name="margin_top">3</property>
+ <child>
+ <object class="GtkLabel" id="l_home">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Home _directory:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">t_home</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="t_home">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="margin_left">13</property>
+ <property name="invisible_char">●</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_top">8</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">User and Group IDs</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">16</property>
+ <property name="margin_top">3</property>
+ <child>
+ <object class="GtkCheckButton" id="c_uid">
+ <property name="label" translatable="yes">Specify a _user ID manually:</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="_apply_checkboxes" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="c_gid">
+ <property name="label" translatable="yes">Specify a _group ID manually:</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="_apply_checkboxes" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spin_uid">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="margin_left">8</property>
+ <property name="invisible_char">●</property>
+ <property name="width_chars">5</property>
+ <property name="progress_pulse_step">0.0099999997764825821</property>
+ <property name="adjustment">uid</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="spin_gid">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="margin_left">8</property>
+ <property name="invisible_char">●</property>
+ <property name="width_chars">5</property>
+ <property name="adjustment">gid</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_top">8</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Group Membership</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">16</property>
+ <property name="margin_top">3</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Add user to the following groups:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">t_groups</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="t_groups">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="margin_top">3</property>
+ <property name="invisible_char">●</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkGrid" id="grid2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_top">3</property>
+ <child>
+ <object class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">5</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">wheel, my-team (1245), project-x (29935)</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">5</property>
+ <property name="margin_top">3</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="label" translatable="yes">You may input a comma-separated list of group names and group IDs here.
+Groups that do not already exist will be created; specify their GID in parentheses. </property>
+ <property name="wrap">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label9">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">1</property>
+ <property name="label" translatable="yes">Example:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label10">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_top">3</property>
+ <property name="xalign">1</property>
+ <property name="yalign">0</property>
+ <property name="label" translatable="yes">Tip:</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ </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">6</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="2">button2</action-widget>
+ <action-widget response="1">button1</action-widget>
+ </action-widgets>
+ </object>
+ <object class="GtkAdjustment" id="gid">
+ <property name="lower">500</property>
+ <property name="upper">32535</property>
+ <property name="value">1000</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="uid">
+ <property name="lower">500</property>
+ <property name="upper">32535</property>
+ <property name="value">1000</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+</interface>
diff --git a/pyanaconda/ui/gui/spokes/password.py b/pyanaconda/ui/gui/spokes/password.py
index 6950472..441050e 100644
--- a/pyanaconda/ui/gui/spokes/password.py
+++ b/pyanaconda/ui/gui/spokes/password.py
@@ -85,7 +85,7 @@ class PasswordSpoke(FirstbootSpokeMixIn, NormalSpoke):
@property
def mandatory(self):
- return False
+ return not self.data.user.userList
def apply(self):
self.data.rootpw.password = cryptPassword(self._password)
diff --git a/pyanaconda/ui/gui/spokes/user.glade b/pyanaconda/ui/gui/spokes/user.glade
new file mode 100644
index 0000000..7dbd705
--- /dev/null
+++ b/pyanaconda/ui/gui/spokes/user.glade
@@ -0,0 +1,377 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <!-- interface-requires AnacondaWidgets 1.0 -->
+ <object class="AnacondaSpokeWindow" id="userCreationWindow">
+ <property name="startup_id">filler</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="startup_id">filler</property>
+ <property name="window_name" translatable="yes">CREATE USER</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="app_paintable">True</property>
+ <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="margin_top">12</property>
+ <property name="yalign">0</property>
+ <property name="xscale">0.75</property>
+ <property name="yscale">0.75</property>
+ <property name="bottom_padding">48</property>
+ <property name="left_padding">24</property>
+ <property name="right_padding">24</property>
+ <child internal-child="action_area">
+ <object class="GtkBox" id="AnacondaSpokeWindow-action_area1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">8</property>
+ <property name="column_spacing">9</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">1</property>
+ <property name="xpad">10</property>
+ <property name="label" translatable="yes">_Full name</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">t_fullname</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">1</property>
+ <property name="xpad">10</property>
+ <property name="label" translatable="yes">_Username</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">t_username</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="t_fullname">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">●</property>
+ <property name="invisible_char_set">True</property>
+ <property name="caps_lock_warning">False</property>
+ <signal name="changed" handler="_guessNames" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="t_username">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">●</property>
+ <property name="invisible_char_set">True</property>
+ <signal name="changed" handler="_guessNameDisabler" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">1</property>
+ <property name="xpad">10</property>
+ <property name="label" translatable="yes">_Password</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">t_password</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">5</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">1</property>
+ <property name="xpad">10</property>
+ <property name="label" translatable="yes">_Confirm password</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">t_verifypassword</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">7</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="t_password">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="visibility">False</property>
+ <property name="invisible_char">●</property>
+ <signal name="changed" handler="_checkPassword" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">5</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="t_verifypassword">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="visibility">False</property>
+ <property name="invisible_char">●</property>
+ <signal name="changed" handler="_checkPassword" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">7</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes"><b>Tip:</b> lorem ipsum dolor sit amet...</property>
+ <property name="use_markup">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="c_usepassword">
+ <property name="label" translatable="yes">Require a password to use this account</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="xalign">0</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="_passwordDisabler" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">4</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkLevelBar" id="password_bar">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <property name="mode">GTK_LEVEL_BAR_MODE_DISCRETE</property>
+ <property name="min-value">0</property>
+ <property name="max-value">4</property>
+ <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
+ <property name="value">2</property>
+ <property name="halign">fill</property>
+ <property name="valign">center</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="password_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">center</property>
+ <property name="xpad">6</property>
+ <property name="label" translatable="yes">empty password</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">6</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="c_admin">
+ <property name="label" translatable="yes">Make this user administrator</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="xalign">0</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkGrid" id="grid2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkButton" id="b_advanced">
+ <property name="label" translatable="yes">_Advanced...</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ <signal name="clicked" handler="on_advanced_clicked" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="b_network_login">
+ <property name="label" translatable="yes">Use network login...</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="margin_left">6</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">8</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</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/user.py b/pyanaconda/ui/gui/spokes/user.py
new file mode 100644
index 0000000..927285c
--- /dev/null
+++ b/pyanaconda/ui/gui/spokes/user.py
@@ -0,0 +1,423 @@
+# User creation spoke
+#
+# Copyright (C) 2013 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.
+#
+# Red Hat Author(s): Martin Sivak <msivak(a)redhat.com>
+#
+
+import gettext
+_ = lambda x: gettext.ldgettext("anaconda", x)
+N_ = lambda x: x
+
+from gi.repository import Gtk
+
+from pyanaconda.users import cryptPassword, validatePassword
+from pwquality import PWQError
+
+from pyanaconda.ui.gui.spokes import NormalSpoke
+from pyanaconda.ui.gui import GUIObject
+from pyanaconda.ui.gui.categories.user_settings import UserSettingsCategory
+from pyanaconda.ui.common import FirstbootSpokeMixIn
+from pyanaconda.ui.gui.utils import enlightbox
+
+import unicodedata
+import pwquality
+
+__all__ = ["UserSpoke", "AdvancedUserDialog"]
+
+def strip_accents(s):
+ """This function takes arbitrary unicode string
+ and returns it with all the diacritics removed.
+
+ :param s: arbitrary string
+ :type s: unicode
+
+ :return: s with diacritics removed
+ :rtype: unicode
+
+ """
+ return ''.join((c for c in unicodedata.normalize('NFD', s)
+ if unicodedata.category(c) != 'Mn'))
+
+class AdvancedUserDialog(GUIObject):
+ builderObjects = ["advancedUserDialog", "uid", "gid"]
+ mainWidgetName = "advancedUserDialog"
+ uiFile = "advanced_user.glade"
+
+ def __init__(self, user, groupDict, data):
+ GUIObject.__init__(self, data)
+ self._user = user
+ self._groupDict = groupDict
+
+ def initialize(self):
+ GUIObject.initialize(self)
+
+ def _apply_checkboxes(self, _editable, data = None):
+ """Update the state of this screen according to the
+ checkbox states on the screen. It is called from
+ the toggled Gtk event.
+ """
+ c_home = self.builder.get_object("c_home").get_active()
+ c_uid = self.builder.get_object("c_uid").get_active()
+ c_gid = self.builder.get_object("c_gid").get_active()
+
+ self.builder.get_object("t_home").set_sensitive(c_home)
+ self.builder.get_object("l_home").set_sensitive(c_home)
+ self.builder.get_object("spin_uid").set_sensitive(c_uid)
+ self.builder.get_object("spin_gid").set_sensitive(c_gid)
+
+ def refresh(self):
+ t_home = self.builder.get_object("t_home")
+ if self._user.homedir:
+ t_home.set_text(self._user.homedir)
+ elif self._user.name:
+ t_home.set_text("/home/%s" % self._user.name)
+
+ groups = []
+ for group_name in self._user.groups:
+ group = self._groupDict[group_name]
+
+ if group.name and group.gid is not None:
+ groups.append("%s (%d)" % (group.name, group.gid))
+ elif group.name:
+ groups.append(group.name)
+ elif group.gid is not None:
+ groups.append("(%d)" % (group.gid,))
+
+ self.builder.get_object("t_groups").set_text(", ".join(groups))
+
+ def run(self):
+ self.window.show()
+ rc = self.window.run()
+ self.window.hide()
+
+ #OK clicked
+ if rc == 1:
+ if self.builder.get_object("c_home").get_active():
+ self._user.homedir = self.builder.get_object("t_home").get_text()
+ else:
+ self._user.homedir = None
+
+ if self.builder.get_object("c_uid").get_active():
+ self._user.uid = int(self.builder.get_object("uid").get_value())
+ else:
+ self._user.uid = None
+
+ if self.builder.get_object("c_gid").get_active():
+ pass
+ #self._user.gid = int(self.builder.get_widget("gid").get_value())
+ else:
+ #self._user.gid = None
+ pass
+
+ groups = self.builder.get_object("t_groups").get_text().split(",")
+ self._user.groups = []
+ for group in groups:
+ group = group.strip()
+ if group not in self._groupDict:
+ self._groupDict[group] = self.data.GroupData(name = group)
+ self._user.groups.append(group)
+
+ #Cancel clicked, window destroyed...
+ else:
+ pass
+
+ return rc
+
+
+
+class UserSpoke(FirstbootSpokeMixIn, NormalSpoke):
+ builderObjects = ["userCreationWindow"]
+
+ mainWidgetName = "userCreationWindow"
+ uiFile = "spokes/user.glade"
+
+ category = UserSettingsCategory
+
+ icon = "avatar-default-symbolic"
+ title = N_("_USER CREATION")
+
+ def __init__(self, *args):
+ NormalSpoke.__init__(self, *args)
+ self._oldweak = None
+ self._error = False
+
+ def initialize(self):
+ NormalSpoke.initialize(self)
+
+ if self.data.user.userList:
+ self._user = self.data.user.userList[0]
+ else:
+ self._user = self.data.UserData()
+ self._wheel = self.data.GroupData(name = "wheel")
+ self._groupDict = {"wheel": self._wheel}
+
+ # placeholders for the text boxes
+ self.fullname = self.builder.get_object("t_fullname")
+ self.username = self.builder.get_object("t_username")
+ self.pw = self.builder.get_object("t_password")
+ self.confirm = self.builder.get_object("t_verifypassword")
+ self.admin = self.builder.get_object("c_admin")
+ self.usepassword = self.builder.get_object("c_usepassword")
+
+ self.guesser = {
+ self.username: True
+ }
+
+ # set up passphrase quality checker
+ self._pwq = pwquality.PWQSettings()
+ self._pwq.read_config()
+
+ self.pw_bar = self.builder.get_object("password_bar")
+ self.pw_label = self.builder.get_object("password_label")
+
+ self._advanced = AdvancedUserDialog(self._user, self._groupDict,
+ self.data)
+ self._advanced.initialize()
+
+ def refresh(self):
+ self.username.set_text(self._user.name)
+ self.fullname.set_text(self._user.gecos)
+ self.admin.set_active(self._wheel.name in self._user.groups)
+
+ if self.usepassword.get_active():
+ self._checkPassword()
+
+ if self.username.get_text() and self.usepassword.get_active():
+ self.pw.grab_focus()
+ elif self.fullname.get_text():
+ self.username.grab_focus()
+ else:
+ self.fullname.grab_focus()
+
+ @property
+ def status(self):
+ if self._error:
+ return _("Error creating user account: %s") % self._error
+ elif len(self.data.user.userList) == 0:
+ return _("No user will be created")
+ elif self._wheel.name in self.data.user.userList[0].groups:
+ return _("Administrator %s will be created") % self.data.user.userList[0].name
+ else:
+ return _("User %s will be created") % self.data.user.userList[0].name
+
+ @property
+ def mandatory(self):
+ # mandatory only if root account is disabled
+ return (not self.data.rootpw.password) or self.data.rootpw.lock
+
+ def apply(self):
+ if self.username.get_text():
+ self._user.name = self.username.get_text()
+ self._user.gecos = self.fullname.get_text()
+ self._user.password = cryptPassword(self.pw.get_text())
+ self._user.isCrypted = True
+
+ if self.admin.get_active() and \
+ self._wheel.name not in self._user.groups:
+ self._user.groups.append(self._wheel.name)
+ elif not self.admin.get_active() and \
+ self._wheel.name in self._user.groups:
+ self._user.groups.remove(self._wheel.name)
+
+ self.data.group.groupList += [self._groupDict[g] for g in self._user.groups
+ if g != self._wheel.name]
+
+ if self._user not in self.data.user.userList:
+ self.data.user.userList.append(self._user)
+
+ elif self._user in self.data.user.userList:
+ self.data.user.userList.remove(self._user)
+
+ @property
+ def completed(self):
+ return self._user in self.data.user.userList
+
+ def _passwordDisabler(self, editable = None, data = None):
+ """Called by Gtk callback when the "Use password" check
+ button is toggled. It will make password entries in/sensitive."""
+
+ self.pw.set_sensitive(self.usepassword.get_active())
+ self.confirm.set_sensitive(self.usepassword.get_active())
+ if not self.usepassword.get_active():
+ self.clear_info()
+ else:
+ self._checkPassword()
+
+ def _guessNameDisabler(self, editable = None, data = None):
+ """Called by Gtk callback when the username or hostname
+ entry changes. It disables the guess algorithm if the
+ user added his own text there and reenable it when the
+ user deletes the whole text."""
+
+ if editable.get_text() == "":
+ self.guesser[editable] = True
+ self._guessNames()
+ else:
+ self.guesser[editable] = False
+
+ def _guessNames(self, editable = None, data = None):
+ """Called by Gtk callback when the full name field changes.
+ It guesses the username and hostname, strips diacritics
+ and make those lowercase.
+ """
+
+ fullname = self.fullname.get_text().split()
+ username = fullname[-1].decode("utf-8").lower()
+ if len(fullname) > 1:
+ username = fullname[0][0].decode("utf-8").lower() + username
+ username = strip_accents(username).encode("utf-8")
+
+ # after the text is updated in guesser, the guess has to be reenabled
+ if self.guesser[self.username]:
+ self.username.set_text(username)
+ self.guesser[self.username] = True
+
+ def _checkPassword(self, editable = None, data = None):
+ """This method updates the password indicators according
+ to the passwords entered by the user. It is called by
+ the changed Gtk event handler.
+ """
+ if self.pw.get_text() == "":
+ strength = -2
+ elif self.pw.get_text() != self.confirm.get_text():
+ strength = -1
+ else:
+ try:
+ strength = self._pwq.check(self.pw.get_text(), None, None)
+ _pwq_error = None
+ except pwquality.PWQError as (e, msg):
+ _pwq_error = msg
+ strength = 0
+
+ if strength == -1:
+ val = 0
+ text = _("Mismatch!")
+ self._error = _("The passwords do not match!")
+ elif strength == -2:
+ val = 0
+ text = _("Empty!")
+ self._error = _("The password is empty!")
+ elif strength < 50:
+ val = 1
+ text = _("Weak")
+ self._error = _("The password you have provided is weak")
+ if _pwq_error:
+ self._error += ": %s. " % _pwq_error
+ else:
+ self._error += ". "
+ self._error += _("You will have to press Done twice to confirm it.")
+ elif strength < 75:
+ val = 2
+ text = _("Fair")
+ self._error = False
+ elif strength < 90:
+ val = 3
+ text = _("Good")
+ self._error = False
+ else:
+ val = 4
+ text = _("Strong")
+ self._error = False
+
+ self.pw_bar.set_value(val)
+ self.pw_label.set_text(text)
+
+ self.clear_info()
+ if self._error:
+ self.set_warning(self._error)
+ self.window.show_all()
+
+ def _validatePassword(self):
+ """This method checks the password weakness and
+ implements the Press Done twice logic. It is used from
+ the on_back_clicked handler.
+
+ It also sets the self._error of the password is not
+ sufficient or does not pass the pwquality checks.
+
+ :return: True if the password should be accepted, False otherwise
+ :rtype: bool
+
+ """
+
+ # Do various steps to validate the password
+ # sets self._error to an error string
+ # Return True if valid, False otherwise
+ self._error = False
+ pw = self.pw.get_text()
+ confirm = self.confirm.get_text()
+
+ if not pw and not confirm:
+ self._error = _("You must provide and confirm a password.")
+ return False
+
+ try:
+ self._error = validatePassword(pw, confirm)
+ except PWQError as (_e, msg):
+ if pw == self._oldweak:
+ # We got a second attempt with the same weak password
+ pass
+ else:
+ self._error = _("You have provided a weak password: %s. "
+ " Press Done again to use anyway.") % msg
+ self._oldweak = pw
+ return False
+
+ if self._error:
+ return False
+
+ # if no errors, clear the info for next time we go into the spoke
+ self._password = pw
+ self.clear_info()
+ self._error = False
+ return True
+
+ def on_advanced_clicked(self, _button):
+ """Handler for the Advanced.. button. It starts the Advanced dialog
+ for setting homedit, uid, gid and groups.
+ """
+
+ self._user.name = self.username.get_text()
+
+ if self.admin.get_active() and \
+ self._wheel.name not in self._user.groups:
+ self._user.groups.append(self._wheel.name)
+ elif not self.admin.get_active() and \
+ self._wheel.name in self._user.groups:
+ self._user.groups.remove(self._wheel.name)
+
+ self._advanced.refresh()
+ with enlightbox(self.window, self._advanced.window):
+ response = self._advanced.run()
+
+ if response == 1:
+ pass
+
+ self.admin.set_active(self._wheel.name in self._user.groups)
+
+ def on_back_clicked(self, button):
+ if not self.usepassword.get_active() or self._validatePassword():
+ self._error = False
+ self.clear_info()
+ NormalSpoke.on_back_clicked(self, button)
+ else:
+ self.clear_info()
+ self.set_warning(self._error)
+ self.pw.grab_focus()
+ self.window.show_all()
+
--
1.7.11.7
11 years, 2 months
[PATCH] Use GDBus also for connection settings update.
by Radek Vykydal
---
pyanaconda/nm.py | 108 ++++++++++++++++++++++++++++++++++++-------------------
1 file changed, 71 insertions(+), 37 deletions(-)
diff --git a/pyanaconda/nm.py b/pyanaconda/nm.py
index ab497a2..b37ef02 100644
--- a/pyanaconda/nm.py
+++ b/pyanaconda/nm.py
@@ -350,22 +350,13 @@ def nm_device_setting_value(name, key1, key2):
value = None
return value
-def _update_settings_libdbus(settings_path, key1, key2, value):
- """Update setting key1, key2 with value."""
- import dbus
- con = dbus.SystemBus().get_object("org.freedesktop.NetworkManager", settings_path)
- settings = con.GetSettings()
- try:
- # TODO: create key1 if missing?
- settings[key1][key2] = value
- except KeyError:
- return False
- con.Update(settings)
- return True
-
-def nm_update_settings_of_device(name, key1, key2, value):
+def nm_update_settings_of_device(name, key1, key2, value, value_type_str=None):
"""Update setting key1, key2 of device name with value.
+ value_type_str indicates type of value. It may be required if the setting
+ is not present in current settings and we can't guess the type which
+ we do only for string and bool currently.
+
Exceptions:
UnknownDeviceError - device was not found
DeviceSettingsNotFoundError - settings were not found (eg for "wlan0")
@@ -373,27 +364,59 @@ def nm_update_settings_of_device(name, key1, key2, value):
settings_path = _device_settings(name)
if not settings_path:
raise DeviceSettingsNotFoundError(name)
- return _update_settings_libdbus(_device_settings(name), key1, key2, value)
-
-
-#def _update_settings(settings_path, key1, key2, value):
-# """Update settings"""
-# proxy = _get_proxy(object_path=settings_path, interface_name="org.freedesktop.NetworkManager.Settings.Connection")
-# args = None
-# settings = proxy.call_sync("GetSettings",
-# args,
-# Gio.DBusCallFlags.NONE,
-# -1,
-# None)
-# # FIXME need to figure out how to create updated
-# # GVariant and convert value to GVariant
-# # to do this: settings[0][key1][key2] = value
-# proxy.call_sync("Update",
-# settings,
-# Gio.DBusCallFlags.NONE,
-# -1,
-# None)
-#
+ return _update_settings(_device_settings(name), key1, key2, value, value_type_str)
+
+def _update_settings(settings_path, key1, key2, value, value_type_str=None):
+ """Update settings"""
+ proxy = _get_proxy(object_path=settings_path, interface_name="org.freedesktop.NetworkManager.Settings.Connection")
+ args = None
+ settings = proxy.call_sync("GetSettings",
+ args,
+ Gio.DBusCallFlags.NONE,
+ -1,
+ None)
+ new_settings = _gvariant_settings(settings, key1, key2, value, value_type_str)
+
+ proxy.call_sync("Update",
+ new_settings,
+ Gio.DBusCallFlags.NONE,
+ -1,
+ None)
+
+def _gvariant_settings(settings, key1, key2, value, value_type_str=None):
+
+ # build copy of GVariant settings as mutable python object
+ new_settings = {}
+ dict1 = settings.get_child_value(0)
+ for key1_idx in range(dict1.n_children()):
+ key_dict2 = dict1.get_child_value(key1_idx)
+ key1_ = key_dict2.get_child_value(0).unpack()
+ new_settings[key1_] = {}
+ dict2 = key_dict2.get_child_value(1)
+ for key2_idx in range(dict2.n_children()):
+ key_val = dict2.get_child_value(key2_idx)
+ key2_ = key_val.get_child_value(0).unpack()
+ val = key_val.get_child_value(1)
+ # get type string of updated value
+ if key1_ == key1 and key2_ == key2:
+ value_type_str = val.get_child_value(0).get_type_string()
+ val = val.get_child_value(0)
+ new_settings[key1_][key2_] = val
+
+ if value_type_str is None:
+ # infer the new value type for string and boolean
+ if type(value) is type(True):
+ value_type_str = 'b'
+ if type(value) is type(''):
+ value_type_str = 's'
+
+ if value_type_str is not None:
+ if key1 not in new_settings:
+ new_settings[key1] = {}
+ new_settings[key1][key2] = GLib.Variant(value_type_str, value)
+
+ return GLib.Variant(settings.get_type_string(), (new_settings,))
+
if __name__ == "__main__":
print "NM state: %s:" % nm_state()
@@ -481,7 +504,7 @@ if __name__ == "__main__":
key1 = "connection"
key2 = "autoconnect"
original_value = nm_device_setting_value(devname, key1, key2)
- print "Setting value %s %s: %s" % (key1, key2, original_value)
+ print "Value of setting %s %s: %s" % (key1, key2, original_value)
# None means default in this case, which is true
if original_value in (None, True):
new_value = False
@@ -490,7 +513,11 @@ if __name__ == "__main__":
print "Updating to %s" % new_value
nm_update_settings_of_device(devname, key1, key2, new_value)
- print "Setting value %s %s: %s" % (key1, key2, nm_device_setting_value(devname, key1, key2))
+ print "Value of setting %s %s: %s" % (key1, key2, nm_device_setting_value(devname, key1, key2))
+ nm_update_settings_of_device(devname, key1, key2, original_value)
+ print "Value of setting %s %s: %s" % (key1, key2, nm_device_setting_value(devname, key1, key2))
+ nm_update_settings_of_device(devname, key1, key2, original_value, "b")
+ print "Value of setting %s %s: %s" % (key1, key2, nm_device_setting_value(devname, key1, key2))
nm_update_settings_of_device(devname, key1, "nonexisting", new_value)
nm_update_settings_of_device(devname, "nonexisting", "nonexisting", new_value)
@@ -504,3 +531,10 @@ if __name__ == "__main__":
nm_update_settings_of_device(wireless_device, key1, key2, new_value)
except DeviceSettingsNotFoundError as e:
print "%s" % e
+
+ #nm_update_settings_of_device(devname, "connection", "id", "test")
+ #nm_update_settings_of_device(devname, "connection", "timestamp", 11111111)
+ #nm_update_settings_of_device(devname, "802-3-ethernet", "mac-address", [55,55,55,55,55,55])
+ #nm_update_settings_of_device(devname, "ipv6", "method", "auto")
+ #nm_update_settings_of_device(devname, "connection", "autoconnect", True)
+ #nm_update_settings_of_device(devname, "connection", "autoconnect", False, "b")
--
1.7.11.7
11 years, 2 months
[PATCH] Add bonding support in kickstart
by Radek Vykydal
Essential stuff, expecting quite a lot of pain due to switchroot dracut
/ NM takover and sync.
This is:
- bonding in kickstart + anaconda
Next steps:
- GUI
- bonding in ks + GUI
- bonding in dracut + anaconda
- bonding in dracut + (bonding in) kickstart + anaconda
- variations on the above
- generating kickstart
- bonding + (root on) iscsi (!?!?)
11 years, 2 months
[PATCH] Remove installmethod.py (dead code)
by Will Woods
The only thing here was one completely unused function that tried to
eject the media at the end of the install.
We've got better ways to handle eject now, so this code is useless.
Remove it.
---
pyanaconda/installmethod.py | 46 ---------------------------------------------
1 file changed, 46 deletions(-)
delete mode 100644 pyanaconda/installmethod.py
diff --git a/pyanaconda/installmethod.py b/pyanaconda/installmethod.py
deleted file mode 100644
index 3a737f4..0000000
--- a/pyanaconda/installmethod.py
+++ /dev/null
@@ -1,46 +0,0 @@
-#
-# installmethod.py - Base class for install methods
-#
-# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
-# Red Hat, Inc. All rights reserved.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty 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, see <http://www.gnu.org/licenses/>.
-#
-
-import os, shutil, string
-from constants import *
-from iutil import dracut_eject
-
-import logging
-log = logging.getLogger("anaconda")
-
-import isys, product
-
-def doMethodComplete(anaconda):
- def _ejectDevice():
- # Ejecting the CD/DVD for kickstart is handled at the end of anaconda
- if anaconda.ksdata:
- return None
-
- if anaconda.mediaDevice:
- return anaconda.storage.devicetree.getDeviceByName(anaconda.mediaDevice)
-
- # If we booted off the boot.iso instead of disc 1, eject that as well.
- if anaconda.stage2 and anaconda.stage2.startswith("cdrom://"):
- dev = anaconda.stage2[8:].split(':')[0]
- return anaconda.storage.devicetree.getDeviceByName(dev)
-
- dev = _ejectDevice()
- if dev:
- dracut_eject(dev.path)
--
1.8.1.2
11 years, 2 months
[PATCH] Make default media eject behavior match old behavior
by Will Woods
Previous versions of anaconda ejected the media by default for
interactive installs.
After commit a724f80 (May 2007), kickstart installs needed to pass
"reboot --eject" to make the drive eject. (See bug #238711, #239002)
Commit 2f601d2 (Sep 2010) added the "noeject" boot argument, which
overrides both the default and the kickstart command. (See bug #477887)
This patch should restore this behavior:
a) Eject is enabled by default, but
b) disabled for automatedInstall unless "reboot --eject" is used, and
c) disabled if "noeject" is passed as a boot argument.
---
anaconda | 5 ++++-
pyanaconda/flags.py | 1 +
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/anaconda b/anaconda
index 8c5a8a9..604ad1d 100755
--- a/anaconda
+++ b/anaconda
@@ -64,7 +64,7 @@ def exitHandler(rebootData, storage, exitCode=None):
from pykickstart.constants import KS_SHUTDOWN, KS_WAIT, KS_REBOOT
from pyanaconda.iutil import dracut_eject
- if rebootData.eject:
+ if flags.eject or rebootData.eject:
for drive in storage.devicetree.devices:
if drive.type != "cdrom":
continue
@@ -286,6 +286,7 @@ def parseOptions(argv=None, cmdline=None):
op.add_option("--memcheck", action="store_true", default=True)
op.add_option("--nomemcheck", action="store_false", dest="memcheck")
op.add_option("--leavebootorder", action="store_true", default=False)
+ op.add_option("--noeject", action="store_false", dest="eject", default=True)
# some defaults change based on cmdline flags
if cmdline is not None:
@@ -808,6 +809,7 @@ if __name__ == "__main__":
flags.dmraid = opts.dmraid
flags.mpath = opts.mpath
flags.selinux = opts.selinux
+ flags.eject = opts.eject
if can_touch_runtime_system("start audit daemon"):
startAuditDaemon()
@@ -841,6 +843,7 @@ if __name__ == "__main__":
ksdata = None
if opts.ksfile:
flags.automatedInstall = True
+ flags.eject = False
files = [opts.ksfile]
else:
files = ["/tmp/updates/interactive-defaults.ks",
diff --git a/pyanaconda/flags.py b/pyanaconda/flags.py
index c6fdcc7..5538266 100644
--- a/pyanaconda/flags.py
+++ b/pyanaconda/flags.py
@@ -69,6 +69,7 @@ class Flags(object):
self.automatedInstall = False
self.dirInstall = False
self.askmethod = False
+ self.eject = True
# for non-physical consoles like some ppc and sgi altix,
# we need to preserve the console device and not try to
# do things like bogl on them. this preserves what that
--
1.8.1.2
11 years, 2 months
[PATCH] Silence "cp: cannot stat '/etc/cmdline'..." error message
by Will Woods
These files may or may not exist; check to see if they exist before
copying them!
---
dracut/anaconda-copy-cmdline.sh | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/dracut/anaconda-copy-cmdline.sh b/dracut/anaconda-copy-cmdline.sh
index 26aa340..2731d6c 100755
--- a/dracut/anaconda-copy-cmdline.sh
+++ b/dracut/anaconda-copy-cmdline.sh
@@ -1,5 +1,7 @@
#!/bin/sh
# Copy over cmdline(.d) files from the initrd to /run before pivot
mkdir -p /run/install/cmdline.d
-cp /etc/cmdline.d/* /run/install/cmdline.d/
-cp /etc/cmdline /run/install/
+for f in /etc/cmdline.d/*; do
+ [ -e $f ] && cp $f /run/install/cmdline.d/
+done
+[ -e /etc/cmdline ] && cp /etc/cmdline /run/install/
--
1.8.1.2
11 years, 2 months
[PATCH] Pressing F12 should do the same thing as clicking "Done" (#840998).
by Chris Lumens
You could do this in the old UI, so let's bring it forward to the new UI.
---
widgets/src/SpokeWindow.c | 15 ++++++++++++++-
widgets/src/StandaloneWindow.c | 23 ++++++++++++++++++++++-
2 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/widgets/src/SpokeWindow.c b/widgets/src/SpokeWindow.c
index 2db0efe..9c1ae47 100644
--- a/widgets/src/SpokeWindow.c
+++ b/widgets/src/SpokeWindow.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Red Hat, Inc.
+ * Copyright (C) 2011-2013 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,6 +21,8 @@
#include "SpokeWindow.h"
#include "intl.h"
+#include <gdk/gdkkeysyms.h>
+
/**
* SECTION: SpokeWindow
* @title: AnacondaSpokeWindow
@@ -155,6 +157,7 @@ static void anaconda_spoke_window_init(AnacondaSpokeWindow *win) {
}
static void anaconda_spoke_window_realize(GtkWidget *widget, gpointer user_data) {
+ GtkAccelGroup *accel_group;
GError *error;
GdkPixbuf *pixbuf;
cairo_pattern_t *pattern;
@@ -189,6 +192,16 @@ static void anaconda_spoke_window_realize(GtkWidget *widget, gpointer user_data)
cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT);
gdk_window_set_background_pattern(gtk_widget_get_window(nav_box), pattern);
}
+
+ /* Pressing F12 should send you back to the hub, similar to how the old UI worked. */
+ accel_group = gtk_accel_group_new();
+ gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);
+ gtk_widget_add_accelerator(window->priv->button,
+ "clicked",
+ accel_group,
+ GDK_KEY_F12,
+ 0,
+ 0);
}
static void anaconda_spoke_window_button_clicked(GtkButton *button,
diff --git a/widgets/src/StandaloneWindow.c b/widgets/src/StandaloneWindow.c
index d7e86a8..28b25e2 100644
--- a/widgets/src/StandaloneWindow.c
+++ b/widgets/src/StandaloneWindow.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2012 Red Hat, Inc.
+ * Copyright (C) 2011-2013 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,6 +21,8 @@
#include "StandaloneWindow.h"
#include "intl.h"
+#include <gdk/gdkkeysyms.h>
+
/**
* SECTION: StandaloneWindow
* @title: AnacondaStandaloneWindow
@@ -63,6 +65,8 @@ static void anaconda_standalone_window_quit_clicked(GtkButton *button,
AnacondaStandaloneWindow *win);
static void anaconda_standalone_window_continue_clicked(GtkButton *button,
AnacondaStandaloneWindow *win);
+static void anaconda_standalone_window_realize(GtkWidget *widget,
+ AnacondaStandaloneWindow *win);
G_DEFINE_TYPE(AnacondaStandaloneWindow, anaconda_standalone_window, ANACONDA_TYPE_BASE_WINDOW)
@@ -149,6 +153,23 @@ static void anaconda_standalone_window_init(AnacondaStandaloneWindow *win) {
gtk_container_add(GTK_CONTAINER(win->priv->button_box), win->priv->continue_button);
gtk_box_pack_start(GTK_BOX(main_box), win->priv->button_box, FALSE, TRUE, 0);
+
+ /* It would be handy for F12 to continue to work like it did in the old
+ * UI, by skipping you to the next screen.
+ */
+ g_signal_connect(win, "realize", G_CALLBACK(anaconda_standalone_window_realize), win);
+}
+
+static void anaconda_standalone_window_realize(GtkWidget *widget,
+ AnacondaStandaloneWindow *win) {
+ GtkAccelGroup *accel_group = gtk_accel_group_new();
+ gtk_window_add_accel_group(GTK_WINDOW(win), accel_group);
+ gtk_widget_add_accelerator(win->priv->continue_button,
+ "clicked",
+ accel_group,
+ GDK_KEY_F12,
+ 0,
+ 0);
}
static void anaconda_standalone_window_quit_clicked(GtkButton *button,
--
1.8.1.2
11 years, 2 months