[master][PATCH] Don't rely on Gtk being importable for exception handling
by Vratislav Podzimek
The anaconda-core package doesn't require Gtk to be installed. If it fails to be
imported, it means for us the same as if fails to be initialized.
Signed-off-by: Vratislav Podzimek <vpodzime(a)redhat.com>
---
pyanaconda/exception.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyanaconda/exception.py b/pyanaconda/exception.py
index e61cce0..f97407a 100644
--- a/pyanaconda/exception.py
+++ b/pyanaconda/exception.py
@@ -116,7 +116,7 @@ class AnacondaExceptionHandler(ExceptionHandler):
super(AnacondaExceptionHandler, self).handleException(
dump_info)
- except RuntimeError:
+ except (RuntimeError, ImportError):
log.debug("Gtk cannot be initialized")
# X not running (Gtk cannot be initialized)
if threadMgr.in_main_thread():
--
1.8.4.2
10 years, 5 months
[PATCH 0/2] fix extlinux boot parameters
by Gene Czarcinski
NOTE: rhbz#1033764 is currently defined as an "Accepted Freeze
Exception" for Fedora 20 Final BLockers.
This pair of updates addresses the problems documented by
rhbz#1036903 and rhbz#1033764.
The first problem is that "ro" is not specified as a kernel parameter.
The second problem is for the situation with the rootfs ("/") is
on a BTRFS subvolume. In that case, there needs to be the
kernel parameter rootflags=subvol=<name> where <name? is the name
of the subvolume.
Gene Czarcinski (2):
add ro to bootloader kernel parameters
if rootfs is btrfs, add rootflags=subvol to kernel parameters
pyanaconda/bootloader.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
--
1.8.4.2
10 years, 5 months
[PATCH 1/2] Add a check that files with translatable strings are in POTFILES.in
by David Shea
This script does a simple check for gettext usage in Python, C, and
glade files, along with a check for the intltool output for desktop
files, and reports whether files that use gettext are missing from
POTFILES.in.
---
tests/Makefile.am | 2 ++
tests/gettext/gettext_potfiles.py | 63 +++++++++++++++++++++++++++++++++++++++
2 files changed, 65 insertions(+)
create mode 100755 tests/gettext/gettext_potfiles.py
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 9074543..3d7f22d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -47,6 +47,7 @@ dist_check_SCRIPTS = glade/accelerators/check_accelerators.py \
pylint/pylint-one.sh \
testenv.sh \
gettext/gettext_warnings.sh \
+ gettext/gettext_potfiles.py \
storage/run_storage_tests.py \
$(srcdir)/storage/cases/*.py \
$(srcdir)/*_tests/*.py
@@ -54,6 +55,7 @@ dist_check_SCRIPTS = glade/accelerators/check_accelerators.py \
TESTS = nosetests.sh \
pylint/runpylint.sh \
gettext/gettext_warnings.sh \
+ gettext/gettext_potfiles.py \
storage/run_storage_tests.py \
glade/accelerators/run_check_accelerators.sh \
glade/pw_visibility/run_check_pw_visibility.sh
diff --git a/tests/gettext/gettext_potfiles.py b/tests/gettext/gettext_potfiles.py
new file mode 100755
index 0000000..b8626a5
--- /dev/null
+++ b/tests/gettext/gettext_potfiles.py
@@ -0,0 +1,63 @@
+#!/usr/bin/python
+
+import os, sys, subprocess
+
+# The xpath in this file is simple enough that Python's built-in
+# ElementTree can handle it, so we don't need lxml here
+import xml.etree.ElementTree as ET
+
+if "top_srcdir" not in os.environ:
+ sys.stderr.write("$top_srcdir must be defined in the test environment\n")
+ # This return code tells the automake test driver that the test setup failed
+ os._exit(99)
+
+success = True
+
+def check_potfiles(checklist, dirname, names):
+ global success
+
+ potcheckfiles = []
+
+ # Skip the .git directory
+ if ".git" in names:
+ names.remove(".git")
+
+ # Strip the "./" component from the path name
+ dirname = os.path.relpath(dirname, ".")
+
+ for checkfile in (os.path.join(dirname, name) for name in names):
+ if checkfile.endswith(".py"):
+ # Check whether the file imports the i18n module
+ if subprocess.call(["grep", "-q", "^from pyanaconda.i18n import", checkfile]) == 0:
+ potcheckfiles.append(checkfile)
+ elif checkfile.endswith(".c"):
+ # Check whether the file includes intl.h
+ if subprocess.call(["grep", "-q", "#include .intl\\.h.", checkfile]) == 0:
+ potcheckfiles.append(checkfile)
+ elif checkfile.endswith(".glade"):
+ # Look for a "translatable=yes" attribute
+ if ET.parse(checkfile).findall(".//*[@translatable='yes']"):
+ potcheckfiles.append(checkfile)
+ elif checkfile.endswith(".desktop.in"):
+ # These are handled by intltool, make sure the .h version is present
+ potcheckfiles.append(checkfile + ".h")
+
+ for checkfile in potcheckfiles:
+ if checkfile not in checklist:
+ sys.stderr.write("%s not in POTFILES.in\n" % checkfile)
+ success = False
+
+# Read in POTFILES.in, skip comments and blank lines
+POTFILES = []
+with open(os.path.join(os.environ["top_srcdir"], "po", "POTFILES.in")) as f:
+ for line in (line.strip() for line in f):
+ if not line or line.startswith("#"):
+ continue
+ POTFILES.append(line)
+
+# Walk the source tree and look for files with translatable strings
+os.chdir(os.environ["top_srcdir"])
+os.path.walk(".", check_potfiles, POTFILES)
+
+if not success:
+ os._exit(1)
--
1.8.4.2
10 years, 5 months
Re: [PATCH V5][blivet] Add support for FBA EDEV/EAV installation (#885957)
by Nageswara R Sastry
Hello,
Do you have any updates?
This feature needs to be introduced in the coming release, your quick response
is appreciated. Thanks in advance.
Regards
R.Nageswara Sastry
On 11/28/2013 4:58 PM, Nageswara R Sastry wrote:
> On 11/27/2013 10:33 PM, David Lehman wrote:
> Hello David,
>
>> What version of anaconda are you using for development? I think there
>> may be a bug in anaconda that's causing your problem with boot disk.
>> Also, could you send me a set of logs including both storage.log and
>> anaconda.log?
>
> I am using Fedora19's Anaconda and Blivet.
> anaconda-19.30.13
> blivet-0.17
>
> boot-disk is not setting because of the condition disk.protected == true,
> from the following code - ksdata.bootloader.execute(storage, ksdata, instClass)
> is not executed
>
> anaconda-19.30.13/pyanaconda/kickstart.py
> def doKickstartStorage(storage, ksdata, instClass):
> """ Setup storage state from the kickstart data """
> ksdata.clearpart.execute(storage, ksdata, instClass)
> if not any(d for d in storage.disks
> if not d.format.hidden and not d.protected):
> return
> ksdata.bootloader.execute(storage, ksdata, instClass)
> ...
>
> I tricked it to execute it, but later when the installation completed, the disk is
> corrupted because parted object is not properly initialized by
> blivet-0.17/formats/disklabel.py: def partedDisk
>
> After the partedDisk initialization happens correctly, installation fails at
> device creation, blivet-0.17/devices.py: def create(self):
> and raising error - raise DeviceCreateError(str(e), self.name)
>
> Reason for the above error is - request for committing the partition is sent to
> parted tool and parted tool thrown error "Too many primary partitions". Because
> already the disk is having one partition and can not create one more. This happens
> because of the disk's nature can not create/delete a partition.
>
>
> Thanks!!
> Regards
> R.Nageswara Sastry
>
10 years, 5 months
[f20-branch/master/rhel7-branch][PATCH] Make sure url and mirrorlist are not set at once
by Martin Kolman
While looking like a simple fix, this bug is actually quite convoluted. :)
While kickstart already throws a parsing error if you try to use
--baseurl and --mirrorlist at once, up till now it was still possible
to set both if the method or repo boot options were used together with a kickstart
with url & the --mirrorlist option. Like this, the boot option set ksdata.method.url
and the kickstart command set ksdata.method.mirrorlist. So Yum got both and if the
repos were not in sync it tended to abort the installation.
The attached patch fixes the issue by clearing ksdata.method.mirrorlist if
the repo or method boot options are used.
But it does not end here. If you check out the bug number 1026834,
you might notice that the issue only happens if the old depreciated
method boot option is used and never if repo is used. This is because
of Dracut, which is also parsing the kickstart, but incorrectly.
The parse-kickstart script does not know about the --mirrorlist
option, so it outputs inst.repo=None. This line ends in the
/run/install/cmdline.d/80-kickstart.conf file.
Dracut also detects that method is depreciated, so it prints a warning
and adds and corrects it to repo and outputs the line out to the
/run/install/cmdline.d/75-anaconda-options.conf
Once Anaconda is started, it parses all files command line files
it can fins, including the kernel command line file and _ALL_ files
in /run/install/cmdline.d.
As a result, the Anaconda option parser gets _3_ different valid installation source
options: method (from kernel command line), repo(from 75-anaconda-options.conf) and
inst.repo (from 80-kickstart.conf)
Even though the options are stored in a dictionary, looks like most of the time
the option parser gets the url and not the None from inst.repo, so both url & mirrorlist
are set as described above.
But why does it work if repo is used instead of method ?
Actually, it doesn't. :) If method is not used, the option parser gets only
repo (set to url provided to the bootoption) and inst.repo (set to None).
Again, by chance, this time the option parser uses the None, so
ksdata.method.url stays None, and ksdata.method.mirrorlist is used for the
installation. _This is wrong._ The mirror list provided by kickstart is
overriding the url provided by the boot option! :) So it works with repo
only due to a bug & depends on dict ordering...
Unfortunately, there doesn't seem to be an easy fix for this. We can't
just stop parsing the url kickstart command in Dracut, as it seems to be used
inside Dracut for some sort of iSCSI initialization. We also can't just stop
parsing the 80-kickstart.conf file in Anaconda because it contains valuable
information, such as which network device was used to boot the system.
Basically, it all boils down to the fact that we are mixing stuff provided
by Dracut Anaconda is interested in with internal Dracut data that Anaconda
should _not_ be processing at all. So to fix it, our Dracut module
needs to be modified to separate Anaconda specific and Dracut specific output.
In short:
* the attached patch fixes the installation abort reported in the bug report
* there is still a less serious issue of Kickstart source overriding
source provided by a bootoption
* to fix the second issue, changes to our Dracut module will be needed
* we are parsing quite a lot of shady files provided by Dracut directly to
our boot option dict without any checking
Martin Kolman (1):
Make sure url and mirrorlist are not set at once (#1026834)
anaconda | 8 ++++++++
1 file changed, 8 insertions(+)
--
1.8.4.2
10 years, 5 months
[master/f20] btrfs and xfs do not support fsck or dump at boot time (#862871)
by Brian C. Lane
From: "Brian C. Lane" <bcl(a)redhat.com>
---
blivet/formats/fs.py | 4 ----
1 file changed, 4 deletions(-)
diff --git a/blivet/formats/fs.py b/blivet/formats/fs.py
index 43f9d44..103717e 100644
--- a/blivet/formats/fs.py
+++ b/blivet/formats/fs.py
@@ -1030,8 +1030,6 @@ class BTRFS(FS):
_linuxNative = True
_maxLabelChars = 256
_supported = True
- _dump = True
- _check = True
_packages = ["btrfs-progs"]
_minSize = 256
_maxSize = 16 * 1024 * 1024
@@ -1191,8 +1189,6 @@ class XFS(FS):
_formattable = True
_linuxNative = True
_supported = True
- _dump = True
- _check = True
_packages = ["xfsprogs"]
_infofs = "xfs_db"
_defaultInfoOptions = ["-c", "\"sb 0\"", "-c", "\"p dblocks\"",
--
1.8.3.1
10 years, 5 months
[blivet][master/f20-branch]rhel7-branch] Remove some unnecessary code to check for LVM constraints on s390x. (#873125, #885011)
by Samantha N. Bueno
Related: rhbz#873125
Related: rhbz#885011
---
blivet/__init__.py | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/blivet/__init__.py b/blivet/__init__.py
index 9420c50..65e8026 100644
--- a/blivet/__init__.py
+++ b/blivet/__init__.py
@@ -1471,20 +1471,6 @@ class Blivet(object):
"which is required for installation of %s "
"to continue.") % (productName,))
- # Prevent users from installing on s390x with (a) no /boot volume, (b) the
- # root volume on LVM, and (c) the root volume not restricted to a single
- # PV
- # NOTE: There is not really a way for users to create a / volume
- # restricted to a single PV. The backend support is there, but there are
- # no UI hook-ups to drive that functionality, but I do not personally
- # care. --dcantrell
- if arch.isS390() and not self.mountpoints.has_key('/boot') and root:
- if root.type == 'lvmlv' and not root.singlePV:
- errors.append(_("This platform requires /boot on a dedicated "
- "partition or logical volume. If you do not "
- "want a /boot volume, you must place / on a "
- "dedicated non-LVM partition."))
-
# FIXME: put a check here for enough space on the filesystems. maybe?
for (mount, size) in checkSizes:
--
1.8.3.1
10 years, 5 months
[PATCH] Fix the handling of renames in the pylint git hook.
by David Shea
Rename status entries have "source -> target" as the filename. Parse
that and run pylint on the target.
---
scripts/githooks/pre-commit | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/scripts/githooks/pre-commit b/scripts/githooks/pre-commit
index ec143f3..501a9c3 100755
--- a/scripts/githooks/pre-commit
+++ b/scripts/githooks/pre-commit
@@ -42,6 +42,11 @@ for gf in git_files.splitlines():
# If the file is being removed or is not in git, ignore it
if gf[0] in ('D', '?'):
continue
+ # If the file is being renamed, grab the target filename
+ if gf[0] == 'R':
+ target = gf[3:].split(' -> ')[1]
+ if is_python(target):
+ pylint_files.append(target)
elif is_python(gf[3:]):
# If the file is unmerged or changed locally, raise an error
if gf[0] == 'U' or gf[1] in ('U', 'M'):
--
1.8.4.2
10 years, 5 months
[PATCH] Remove startup-id from AnacondaBaseWindow.
by David Shea
This property isn't in Gtk3, it doesn't look like we need the workaround
anymore, and since the glade adaptor is setting a property that isn't in
GtkWidget anymore, it doesn't show up as a regular gobject property
anymore and makes things looks really weird for gobject-introspection.
---
pyanaconda/ui/gui/hubs/progress.glade | 2 --
pyanaconda/ui/gui/hubs/summary.glade | 2 --
pyanaconda/ui/gui/spokes/custom.glade | 2 --
pyanaconda/ui/gui/spokes/datetime_spoke.glade | 2 --
pyanaconda/ui/gui/spokes/filter.glade | 2 --
pyanaconda/ui/gui/spokes/keyboard.glade | 2 --
pyanaconda/ui/gui/spokes/langsupport.glade | 2 --
pyanaconda/ui/gui/spokes/network.glade | 4 ----
pyanaconda/ui/gui/spokes/password.glade | 2 --
pyanaconda/ui/gui/spokes/software.glade | 2 --
pyanaconda/ui/gui/spokes/source.glade | 2 --
pyanaconda/ui/gui/spokes/storage.glade | 2 --
pyanaconda/ui/gui/spokes/user.glade | 2 --
pyanaconda/ui/gui/spokes/welcome.glade | 2 --
widgets/glade/AnacondaWidgets.xml | 1 -
widgets/src/glade-adaptor.c | 9 ---------
16 files changed, 40 deletions(-)
diff --git a/pyanaconda/ui/gui/hubs/progress.glade b/pyanaconda/ui/gui/hubs/progress.glade
index 3794c71..46bad85 100644
--- a/pyanaconda/ui/gui/hubs/progress.glade
+++ b/pyanaconda/ui/gui/hubs/progress.glade
@@ -4,9 +4,7 @@
<!-- interface-requires gtk+ 3.0 -->
<!-- interface-requires AnacondaWidgets 1.0 -->
<object class="AnacondaHubWindow" id="progressWindow">
- <property name="startup_id">filler</property>
<property name="can_focus">False</property>
- <property name="startup_id">filler</property>
<property name="window_name" translatable="yes">CONFIGURATION</property>
<child internal-child="main_box">
<object class="GtkBox" id="AnacondaHubWindow-main_box1">
diff --git a/pyanaconda/ui/gui/hubs/summary.glade b/pyanaconda/ui/gui/hubs/summary.glade
index 6bcdea4..103f971 100644
--- a/pyanaconda/ui/gui/hubs/summary.glade
+++ b/pyanaconda/ui/gui/hubs/summary.glade
@@ -4,9 +4,7 @@
<!-- interface-requires gtk+ 3.0 -->
<!-- interface-requires AnacondaWidgets 1.0 -->
<object class="AnacondaHubWindow" id="summaryWindow">
- <property name="startup_id">filler</property>
<property name="can_focus">False</property>
- <property name="startup_id">filler</property>
<property name="window_name" translatable="yes">INSTALLATION SUMMARY</property>
<child internal-child="main_box">
<object class="GtkBox" id="AnacondaHubWindow-main_box1">
diff --git a/pyanaconda/ui/gui/spokes/custom.glade b/pyanaconda/ui/gui/spokes/custom.glade
index 592fd49..8476e66 100644
--- a/pyanaconda/ui/gui/spokes/custom.glade
+++ b/pyanaconda/ui/gui/spokes/custom.glade
@@ -710,10 +710,8 @@ use. Try something else?</property>
</action-widgets>
</object>
<object class="AnacondaSpokeWindow" id="customStorageWindow">
- <property name="startup_id">filler</property>
<property name="can_focus">False</property>
<property name="events">GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
- <property name="startup_id">filler</property>
<property name="window_name" translatable="yes">MANUAL PARTITIONING</property>
<signal name="button-clicked" handler="on_back_clicked" swapped="no"/>
<signal name="info-bar-clicked" handler="on_info_bar_clicked" swapped="no"/>
diff --git a/pyanaconda/ui/gui/spokes/datetime_spoke.glade b/pyanaconda/ui/gui/spokes/datetime_spoke.glade
index 1662e11..413f92c 100644
--- a/pyanaconda/ui/gui/spokes/datetime_spoke.glade
+++ b/pyanaconda/ui/gui/spokes/datetime_spoke.glade
@@ -76,9 +76,7 @@
</columns>
</object>
<object class="AnacondaSpokeWindow" id="datetimeWindow">
- <property name="startup_id">filler</property>
<property name="can_focus">False</property>
- <property name="startup_id">filler</property>
<property name="window_name" translatable="yes">DATE & TIME</property>
<signal name="button-clicked" handler="on_back_clicked" swapped="no"/>
<child internal-child="main_box">
diff --git a/pyanaconda/ui/gui/spokes/filter.glade b/pyanaconda/ui/gui/spokes/filter.glade
index 4e2b461..f5ef863 100644
--- a/pyanaconda/ui/gui/spokes/filter.glade
+++ b/pyanaconda/ui/gui/spokes/filter.glade
@@ -55,11 +55,9 @@
<property name="child_model">diskStore</property>
</object>
<object class="AnacondaSpokeWindow" id="filterWindow">
- <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">INSTALLATION DESTINATION</property>
<signal name="button-clicked" handler="on_back_clicked" swapped="no"/>
<child internal-child="main_box">
diff --git a/pyanaconda/ui/gui/spokes/keyboard.glade b/pyanaconda/ui/gui/spokes/keyboard.glade
index 2fb391d..ac9f06e 100644
--- a/pyanaconda/ui/gui/spokes/keyboard.glade
+++ b/pyanaconda/ui/gui/spokes/keyboard.glade
@@ -199,9 +199,7 @@
</object>
<object class="GtkTextBuffer" id="layoutTestBuffer"/>
<object class="AnacondaSpokeWindow" id="keyboardWindow">
- <property name="startup_id">filler</property>
<property name="can_focus">False</property>
- <property name="startup_id">filler</property>
<property name="window_name" translatable="yes">KEYBOARD LAYOUT</property>
<signal name="button-clicked" handler="on_back_clicked" swapped="no"/>
<child internal-child="main_box">
diff --git a/pyanaconda/ui/gui/spokes/langsupport.glade b/pyanaconda/ui/gui/spokes/langsupport.glade
index bc0df87..0c0c440 100644
--- a/pyanaconda/ui/gui/spokes/langsupport.glade
+++ b/pyanaconda/ui/gui/spokes/langsupport.glade
@@ -29,9 +29,7 @@
</columns>
</object>
<object class="AnacondaSpokeWindow" id="langsupportWindow">
- <property name="startup_id">filler</property>
<property name="can_focus">False</property>
- <property name="startup_id">filler</property>
<property name="window_name" translatable="yes">LANGUAGE SUPPORT</property>
<signal name="button-clicked" handler="on_back_clicked" swapped="no"/>
<child internal-child="main_box">
diff --git a/pyanaconda/ui/gui/spokes/network.glade b/pyanaconda/ui/gui/spokes/network.glade
index 5101e1b..d1fdd94 100644
--- a/pyanaconda/ui/gui/spokes/network.glade
+++ b/pyanaconda/ui/gui/spokes/network.glade
@@ -157,9 +157,7 @@
</columns>
</object>
<object class="AnacondaStandaloneWindow" id="networkStandaloneWindow">
- <property name="startup_id">filler</property>
<property name="can_focus">False</property>
- <property name="startup_id">filler</property>
<property name="window_name" translatable="yes">NETWORK CONFIGURATION</property>
<child internal-child="main_box">
<object class="GtkBox" id="AnacondaStandaloneWindow-main_box5">
@@ -233,9 +231,7 @@ updates available for you.</property>
</child>
</object>
<object class="AnacondaSpokeWindow" id="networkWindow">
- <property name="startup_id">filler</property>
<property name="can_focus">False</property>
- <property name="startup_id">filler</property>
<property name="window_name" translatable="yes">NETWORK CONFIGURATION</property>
<signal name="button-clicked" handler="on_back_clicked" swapped="no"/>
<child internal-child="main_box">
diff --git a/pyanaconda/ui/gui/spokes/password.glade b/pyanaconda/ui/gui/spokes/password.glade
index a508e1c..a6c8724 100644
--- a/pyanaconda/ui/gui/spokes/password.glade
+++ b/pyanaconda/ui/gui/spokes/password.glade
@@ -3,9 +3,7 @@
<!-- interface-requires gtk+ 3.6 -->
<!-- interface-requires AnacondaWidgets 1.0 -->
<object class="AnacondaSpokeWindow" id="passwordWindow">
- <property name="startup_id">filler</property>
<property name="can_focus">False</property>
- <property name="startup_id">filler</property>
<property name="window_name" translatable="yes">ROOT PASSWORD</property>
<signal name="button-clicked" handler="on_back_clicked" swapped="no"/>
<child internal-child="main_box">
diff --git a/pyanaconda/ui/gui/spokes/software.glade b/pyanaconda/ui/gui/spokes/software.glade
index 7a9a717..3ea3fbb 100644
--- a/pyanaconda/ui/gui/spokes/software.glade
+++ b/pyanaconda/ui/gui/spokes/software.glade
@@ -26,11 +26,9 @@
</columns>
</object>
<object class="AnacondaSpokeWindow" id="softwareWindow">
- <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">SOFTWARE SELECTION</property>
<signal name="button-clicked" handler="on_back_clicked" swapped="no"/>
<signal name="info-bar-clicked" handler="on_info_bar_clicked" swapped="no"/>
diff --git a/pyanaconda/ui/gui/spokes/source.glade b/pyanaconda/ui/gui/spokes/source.glade
index 3dbf2b4..47ebfd6 100644
--- a/pyanaconda/ui/gui/spokes/source.glade
+++ b/pyanaconda/ui/gui/spokes/source.glade
@@ -490,9 +490,7 @@
</columns>
</object>
<object class="AnacondaSpokeWindow" id="sourceWindow">
- <property name="startup_id">filler</property>
<property name="can_focus">False</property>
- <property name="startup_id">filler</property>
<property name="window_name" translatable="yes">INSTALLATION SOURCE</property>
<signal name="button-clicked" handler="on_back_clicked" swapped="no"/>
<child internal-child="main_box">
diff --git a/pyanaconda/ui/gui/spokes/storage.glade b/pyanaconda/ui/gui/spokes/storage.glade
index 4486bf9..325e227 100644
--- a/pyanaconda/ui/gui/spokes/storage.glade
+++ b/pyanaconda/ui/gui/spokes/storage.glade
@@ -794,9 +794,7 @@
</columns>
</object>
<object class="AnacondaSpokeWindow" id="storageWindow">
- <property name="startup_id">filler</property>
<property name="can_focus">False</property>
- <property name="startup_id">filler</property>
<property name="window_name" translatable="yes">INSTALLATION DESTINATION</property>
<signal name="button-clicked" handler="on_back_clicked" swapped="no"/>
<signal name="info-bar-clicked" handler="on_info_bar_clicked" swapped="no"/>
diff --git a/pyanaconda/ui/gui/spokes/user.glade b/pyanaconda/ui/gui/spokes/user.glade
index 123dfb3..949b33e 100644
--- a/pyanaconda/ui/gui/spokes/user.glade
+++ b/pyanaconda/ui/gui/spokes/user.glade
@@ -4,11 +4,9 @@
<!-- interface-requires gtk+ 3.6 -->
<!-- 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">
diff --git a/pyanaconda/ui/gui/spokes/welcome.glade b/pyanaconda/ui/gui/spokes/welcome.glade
index 7d88912..faa6b14 100644
--- a/pyanaconda/ui/gui/spokes/welcome.glade
+++ b/pyanaconda/ui/gui/spokes/welcome.glade
@@ -275,9 +275,7 @@
</action-widgets>
</object>
<object class="AnacondaStandaloneWindow" id="welcomeWindow">
- <property name="startup_id">filler</property>
<property name="can_focus">False</property>
- <property name="startup_id">filler</property>
<property name="window_name"/>
<child internal-child="main_box">
<object class="GtkBox" id="AnacondaStandaloneWindow-main_box1">
diff --git a/widgets/glade/AnacondaWidgets.xml b/widgets/glade/AnacondaWidgets.xml
index 7a496c3..d078bcf 100644
--- a/widgets/glade/AnacondaWidgets.xml
+++ b/widgets/glade/AnacondaWidgets.xml
@@ -17,7 +17,6 @@
<property id="height-request" disabled="True" />
<property id="modal" disabled="True" />
<property id="resizable" disabled="True" />
- <property id="startup-id" visible="False" />
<property id="title" disabled="True" />
<property id="type" disabled="True" />
<property id="width-request" disabled="True" />
diff --git a/widgets/src/glade-adaptor.c b/widgets/src/glade-adaptor.c
index edf52da..00c2f55 100644
--- a/widgets/src/glade-adaptor.c
+++ b/widgets/src/glade-adaptor.c
@@ -76,18 +76,9 @@ void anaconda_standalone_window_post_create(GladeWidgetAdaptor *adaptor,
void anaconda_standalone_window_write_widget(GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlContext *context, GladeXmlNode *node) {
- GladeProperty *startup_id_prop;
-
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
- /* Set a bogus startup-id in the output XML file. This doesn't really seem
- * like it should be necessary, but glade will crash if I don't.
- */
- startup_id_prop = glade_widget_get_property(widget, "startup-id");
- glade_property_set(startup_id_prop, "filler");
- glade_property_write(startup_id_prop, context, node);
-
/* Chain up and write the parent's properties */
GWA_GET_CLASS (GTK_TYPE_WINDOW)->write_widget (adaptor, widget, context, node);
}
--
1.8.4.2
10 years, 5 months
[PATCH] Use abstract base classes for mixins.
by David Shea
This is only a beginning, but hopefully enough to get the idea across.
The purpose of this is twofold: For mixins/interfaces/whatever that do
not make sense unless inherited by another class, don't allow the class
to be instantiated. For mixins/interfaces/whatever that depend on
properties that are implemented in the inheriting class or its other
subclasses, make the relationship explicit through the use of abstract
properties.
SourceSwitchHandler is a good example, and the catalyst for this.
SourceSwitchHandler manipulates self.data, which is provided in the
subclass by way of EditTUISpoke -> UIObject. This kind of a
relationship is flagged by pylint since .data is not provided by
SourceSwitchHandler or any of its subclasses. b5df3a90 attempted to
remedy this by storing a copy of data in SourceSwitchHandler, but that
commit is incorrect: self.data in SourceSwitchHandler will resolve to
UIObject.data when called from a class that inherits from both, and
UIObject.data is a read-only property. This commit instead makes
SourceSwitchHandler an abstract base class. It implements a data
property of its own but requires that the property be overridden by
another class. This way no class can inherit from SourceSwitchHandler
without providing a data property.
---
po/POTFILES.in | 1 +
pyanaconda/ui/gui/spokes/storage.py | 36 +------
pyanaconda/ui/interfaces.py | 184 ++++++++++++++++++++++++++++++++++++
pyanaconda/ui/tui/spokes/source.py | 95 ++-----------------
4 files changed, 196 insertions(+), 120 deletions(-)
create mode 100644 pyanaconda/ui/interfaces.py
diff --git a/po/POTFILES.in b/po/POTFILES.in
index af263f9..c1d3a7e 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -28,6 +28,7 @@ pyanaconda/packaging/yumpayload.py
# Interfaces
pyanaconda/ui/common.py
+pyanaconda/ui/interfaces.py
pyanaconda/ui/__init__.py
# Common stuff
diff --git a/pyanaconda/ui/gui/spokes/storage.py b/pyanaconda/ui/gui/spokes/storage.py
index 4192a1a..ce80c72 100644
--- a/pyanaconda/ui/gui/spokes/storage.py
+++ b/pyanaconda/ui/gui/spokes/storage.py
@@ -50,6 +50,7 @@ from pyanaconda.ui.gui.spokes.lib.detailederror import DetailedErrorDialog
from pyanaconda.ui.gui.spokes.lib.resize import ResizeDialog
from pyanaconda.ui.gui.categories.system import SystemCategory
from pyanaconda.ui.gui.utils import enlightbox, escape_markup
+from pyanaconda.ui.interfaces import StorageChecker
from pyanaconda.kickstart import doKickstartStorage, getAvailableDiskSpace
from blivet import empty_device
@@ -306,33 +307,6 @@ class InstallOptions3Dialog(InstallOptions1Dialog):
def continue_response(self):
return self.RESPONSE_CONTINUE_NONE
-class StorageChecker(object):
- errors = []
- warnings = []
- _mainSpokeClass = "StorageSpoke"
-
- def __init__(self):
- # This is provided by the StorageSpoke class, which is a subclass of
- # this one. Backwards, I know.
- self.storage = None
-
- def run(self):
- threadMgr.add(AnacondaThread(name=constants.THREAD_CHECK_STORAGE,
- target=self.checkStorage))
-
- def checkStorage(self):
- threadMgr.wait(constants.THREAD_EXECUTE_STORAGE)
-
- hubQ.send_not_ready(self._mainSpokeClass)
- hubQ.send_message(self._mainSpokeClass, _("Checking storage configuration..."))
- (StorageChecker.errors,
- StorageChecker.warnings) = self.storage.sanityCheck()
- hubQ.send_ready(self._mainSpokeClass, True)
- for e in StorageChecker.errors:
- log.error(e)
- for w in StorageChecker.warnings:
- log.warn(w)
-
class StorageSpoke(NormalSpoke, StorageChecker):
builderObjects = ["storageWindow", "addSpecializedImage"]
mainWidgetName = "storageWindow"
@@ -431,7 +405,7 @@ class StorageSpoke(NormalSpoke, StorageChecker):
doKickstartStorage(self.storage, self.data, self.instclass)
except (StorageError, KickstartValueError) as e:
log.error("storage configuration failed: %s", e)
- StorageChecker.errors = str(e).split("\n")
+ self.errors = str(e).split("\n")
hubQ.send_message(self.__class__.__name__, _("Failed to save storage configuration..."))
self.data.bootloader.bootDrive = ""
self.data.ignoredisk.drives = []
@@ -443,14 +417,14 @@ class StorageSpoke(NormalSpoke, StorageChecker):
self._applyDiskSelection(self.selected_disks)
except BootLoaderError as e:
log.error("BootLoader setup failed: %s", e)
- StorageChecker.errors = str(e).split("\n")
+ self.errors = str(e).split("\n")
hubQ.send_message(self.__class__.__name__, _("Failed to save storage configuration..."))
self.data.bootloader.bootDrive = ""
else:
if self.autopart:
# this was already run as part of doAutoPartition. dumb.
- StorageChecker.errors = []
- StorageChecker.warnings = []
+ self.errors = []
+ self.warnings = []
self.run()
finally:
self._ready = True
diff --git a/pyanaconda/ui/interfaces.py b/pyanaconda/ui/interfaces.py
new file mode 100644
index 0000000..6b46d03
--- /dev/null
+++ b/pyanaconda/ui/interfaces.py
@@ -0,0 +1,184 @@
+# Abstract interfaces for UI classes
+#
+# 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): David Shea <dshea(a)redhat.com
+#
+
+# This file contains abstract base classes that provide specific functionality
+# that can be added to another class. The idea is sort-of modelled after Java's
+# interfaces. An abstract base class cannot be instatiated, and it provides a
+# contract for classes that inherit from it: any method or property marked as
+# abstract in the base class must be overriden in the inheriting class. This
+# allows for cleaner implementation of certain types of mixin-classes: a class
+# that adds functionality to another class can explicitly require that methods
+# or properties be provided by the inheriting class or another superclass of
+# the inheriting class.
+#
+# In general, classes that inherit from abstract base classes should place the
+# abstract base class at the end of the inheritance list. This way any abstract
+# methods or properties in the abc will be overridden by the base classes
+# that are first in the inheritance list. For example, an abstract base class
+# may add a method that reads from spoke.data:
+#
+# class Mixin(object):
+# __metaclass__ = ABCMeta
+#
+# @abstractproperty
+# def data(self): pass
+#
+# def isHD(self):
+# return self.data.method == "harddrive"
+#
+# The Mixin class will add the method isHD to any class that inherits from it,
+# and classes that inherit from Mixin must provide a data property.
+#
+# class MixedObject(UIObject, Mixin):
+# ....
+#
+# The method resolution order of MixedObject resolves UIObject.data before
+# Mixin.data, so UIObject.data satisfies the requirment that Mixin.data be
+# overriden.
+
+from abc import ABCMeta, abstractproperty
+
+from pyanaconda import constants
+from pyanaconda.threads import threadMgr, AnacondaThread
+from pyanaconda.ui.communication import hubQ
+from pyanaconda.i18n import _
+
+import logging
+import copy
+
+class StorageChecker(object):
+ __metaclass__ = ABCMeta
+
+ log = logging.getLogger("anaconda")
+
+ def __init__(self):
+ self.errors = []
+ self.warnings = []
+
+ @abstractproperty
+ def storage(self): pass
+
+ def run(self):
+ threadMgr.add(AnacondaThread(name=constants.THREAD_CHECK_STORAGE,
+ target=self.checkStorage))
+
+ def checkStorage(self):
+ threadMgr.wait(constants.THREAD_EXECUTE_STORAGE)
+
+ hubQ.send_not_read(self.__class__.__name__)
+ hubQ.send_message(self.__class__.__name__, _("Check storage configuration..."))
+ (self.errors,
+ self.warnings) = self.storage.sanityCheck()
+ for e in self.errors:
+ self.log.error(e)
+ for w in self.warnings:
+ self.log.warn(w)
+
+class SourceSwitchHandler(object):
+ """ A class that can be used as a mixin handling
+ installation source switching.
+ It will correctly switch to the new method
+ and cleanup any previous method set.
+ """
+
+ __metaclass__ = ABCMeta
+
+ @abstractproperty
+ def data(self): pass
+
+ @abstractproperty
+ def storage(self): pass
+
+ def __init__(self):
+ self._device = None
+ self._current_iso_path = None
+
+ def _clean_hdd_iso(self):
+ """ Clean HDD ISO usage
+ This means unmounting the partition and unprotecting it,
+ so it can be used for the installation.
+ """
+ if self.data.method.method == "harddrive" and self.data.method.partition:
+ part = self.data.method.partition
+ dev = self.storage.devicetree.getDeviceByName(part)
+ if dev:
+ dev.protected = False
+ self.storage.config.protectedDevSpecs.remove(part)
+
+ def set_source_hdd_iso(self, device, iso_path):
+ """ Switch to the HDD ISO install source
+ :param partition: name of the partition hosting the ISO
+ :type partition: string
+ :param iso_path: full path to the source ISO file
+ :type iso_path: string
+ """
+ partition = device.name
+ # the GUI source spoke also does the copy
+ old_source = copy.copy(self.data.method)
+
+ # if a different partition was used previously, unprotect it
+ if old_source.method == "harddrive" and old_source.partition != partition:
+ self._clean_hdd_iso()
+
+ # protect current device
+ if device:
+ device.protected = True
+ self.storage.config.protectedDevSpecs.append(device.name)
+
+ self.data.method.method = "harddrive"
+ self.data.method.partition = partition
+ # the / gets stripped off by payload.ISOImage
+ self.data.method.dir = "/" + iso_path
+
+ # as we already made the device protected when
+ # switching to it, we don't need to protect it here
+
+ def set_source_url(self, url=None):
+ """ Switch to install source specified by URL """
+ # clean any old HDD ISO sources
+ self._clean_hdd_iso()
+
+ self.data.method.method = "url"
+ if url is not None:
+ self.data.method.url = url
+
+ def set_source_nfs(self, opts=None):
+ """ Switch to NFS install source """
+ # clean any old HDD ISO sources
+ self._clean_hdd_iso()
+
+ self.data.method.method = "nfs"
+ if opts is not None:
+ self.data.method.opts = opts
+
+ def set_source_cdrom(self):
+ """ Switch to cdrom install source """
+ # clean any old HDD ISO sources
+ self._clean_hdd_iso()
+
+ self.data.method.method = "cdrom"
+
+ def set_source_closest_mirror(self):
+ """ Switch to the closest mirror install source """
+ # clean any old HDD ISO sources
+ self._clean_hdd_iso()
+
+ self.data.method.method = None
diff --git a/pyanaconda/ui/tui/spokes/source.py b/pyanaconda/ui/tui/spokes/source.py
index 977e7df..a3397fd 100644
--- a/pyanaconda/ui/tui/spokes/source.py
+++ b/pyanaconda/ui/tui/spokes/source.py
@@ -33,12 +33,13 @@ from pyanaconda.constants import THREAD_PAYLOAD_MD, THREAD_STORAGE, THREAD_STORA
from pyanaconda.constants import THREAD_CHECK_SOFTWARE, ISO_DIR, DRACUT_ISODIR
from pyanaconda.constants_text import INPUT_PROCESSED
+from pyanaconda.ui.interfaces import SourceSwitchHandler
+
from blivet.util import get_mount_paths
import re
import os
import fnmatch
-import copy
import logging
LOG = logging.getLogger("anaconda")
@@ -46,90 +47,6 @@ LOG = logging.getLogger("anaconda")
__all__ = ["SourceSpoke"]
-class SourceSwitchHandler(object):
- """ A class that can be used as a mixin handling
- installation source switching.
- It will correctly switch to the new method
- and cleanup any previous method set.
- """
- def __init__(self, data, storage):
- self._device = None
- self._current_iso_path = None
- self.data = data
- self.storage = storage
-
- def _clean_hdd_iso(self):
- """ Clean HDD ISO usage
- This means unmounting the partition and unprotecting it,
- so it can be used for the installation.
- """
- if self.data.method.method == "harddrive" and self.data.method.partition:
- part = self.data.method.partition
- dev = self.storage.devicetree.getDeviceByName(part)
- if dev:
- dev.protected = False
- self.storage.config.protectedDevSpecs.remove(part)
-
- def set_source_hdd_iso(self, device, iso_path):
- """ Switch to the HDD ISO install source
- :param partition: name of the partition hosting the ISO
- :type partition: string
- :param iso_path: full path to the source ISO file
- :type iso_path: string
- """
- partition = device.name
- # the GUI source spoke also does the copy
- old_source = copy.copy(self.data.method)
-
- # if a different partition was used previously, unprotect it
- if old_source.method == "harddrive" and old_source.partition != partition:
- self._clean_hdd_iso()
-
- # protect current device
- if device:
- device.protected = True
- self.storage.config.protectedDevSpecs.append(device.name)
-
- self.data.method.method = "harddrive"
- self.data.method.partition = partition
- # the / gets stripped off by payload.ISOImage
- self.data.method.dir = "/" + iso_path
-
- # as we already made the device protected when
- # switching to it, we don't need to protect it here
-
- def set_source_url(self, url=None):
- """ Switch to install source specified by URL """
- # clean any old HDD ISO sources
- self._clean_hdd_iso()
-
- self.data.method.method = "url"
- if url is not None:
- self.data.method.url = url
-
- def set_source_nfs(self, opts=None):
- """ Switch to NFS install source """
- # clean any old HDD ISO sources
- self._clean_hdd_iso()
-
- self.data.method.method = "nfs"
- if opts is not None:
- self.data.method.opts = opts
-
- def set_source_cdrom(self):
- """ Switch to cdrom install source """
- # clean any old HDD ISO sources
- self._clean_hdd_iso()
-
- self.data.method.method = "cdrom"
-
- def set_source_closest_mirror(self):
- """ Switch to the closest mirror install source """
- # clean any old HDD ISO sources
- self._clean_hdd_iso()
-
- self.data.method.method = None
-
class SourceSpoke(EditTUISpoke, SourceSwitchHandler):
""" Spoke used to customize the install source repo. """
title = N_("Installation source")
@@ -142,7 +59,7 @@ class SourceSpoke(EditTUISpoke, SourceSwitchHandler):
def __init__(self, app, data, storage, payload, instclass):
EditTUISpoke.__init__(self, app, data, storage, payload, instclass)
- SourceSwitchHandler.__init__(self, data, storage)
+ SourceSwitchHandler.__init__(self)
self._ready = False
self.errors = []
self._cdrom = None
@@ -344,7 +261,7 @@ class SpecifyRepoSpoke(EditTUISpoke, SourceSwitchHandler):
def __init__(self, app, data, storage, payload, instclass, selection):
EditTUISpoke.__init__(self, app, data, storage, payload, instclass)
- SourceSwitchHandler.__init__(self, data, storage)
+ SourceSwitchHandler.__init__(self)
self.selection = selection
self.args = self.data.method
@@ -383,7 +300,7 @@ class SpecifyNFSRepoSpoke(EditTUISpoke, SourceSwitchHandler):
def __init__(self, app, data, storage, payload, instclass, selection, errors):
EditTUISpoke.__init__(self, app, data, storage, payload, instclass)
- SourceSwitchHandler.__init__(self, data, storage)
+ SourceSwitchHandler.__init__(self)
self.selection = selection
self.args = self.data.method
self.errors = errors
@@ -504,7 +421,7 @@ class SelectISOSpoke(NormalTUISpoke, SourceSwitchHandler):
def __init__(self, app, data, storage, payload, instclass, device):
NormalTUISpoke.__init__(self, app, data, storage, payload, instclass)
- SourceSwitchHandler.__init__(self, data, storage)
+ SourceSwitchHandler.__init__(self)
self.selection = None
self.args = self.data.method
self._device = device
--
1.8.4.2
10 years, 5 months