1 |
# |
2 |
# text.py - text mode frontend to anaconda |
3 |
# |
4 |
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. |
5 |
# All rights reserved. |
6 |
# |
7 |
# This program is free software; you can redistribute it and/or modify |
8 |
# it under the terms of the GNU General Public License as published by |
9 |
# the Free Software Foundation; either version 2 of the License, or |
10 |
# (at your option) any later version. |
11 |
# |
12 |
# This program is distributed in the hope that it will be useful, |
13 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
# GNU General Public License for more details. |
16 |
# |
17 |
# You should have received a copy of the GNU General Public License |
18 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 |
# |
20 |
# Author(s): Erik Troan <ewt@redhat.com> |
21 |
# Matt Wilson <msw@redhat.com> |
22 |
# |
23 |
|
24 |
from snack import * |
25 |
import sys |
26 |
import os |
27 |
import isys |
28 |
import iutil |
29 |
import time |
30 |
import signal |
31 |
import parted |
32 |
import product |
33 |
import string |
34 |
from language import expandLangs |
35 |
from flags import flags |
36 |
from constants_text import * |
37 |
from constants import * |
38 |
import network |
39 |
from installinterfacebase import InstallInterfaceBase |
40 |
import imputil |
41 |
|
42 |
import gettext |
43 |
_ = lambda x: gettext.ldgettext("anaconda", x) |
44 |
P_ = lambda x, y, z: gettext.ldngettext("anaconda", x, y, z) |
45 |
|
46 |
import logging |
47 |
log = logging.getLogger("anaconda") |
48 |
|
49 |
stepToClasses = { |
50 |
"language" : ("language_text", "LanguageWindow"), |
51 |
"keyboard" : ("keyboard_text", "KeyboardWindow"), |
52 |
"welcome" : ("welcome_text", "WelcomeWindow"), |
53 |
"parttype" : ("partition_text", "PartitionTypeWindow"), |
54 |
"addswap" : ("upgrade_text", "UpgradeSwapWindow"), |
55 |
"upgrademigratefs" : ("upgrade_text", "UpgradeMigrateFSWindow"), |
56 |
"zfcpconfig": ("zfcp_text", ("ZFCPWindow")), |
57 |
"findinstall" : ("upgrade_text", ("UpgradeExamineWindow")), |
58 |
"upgbootloader": ("upgrade_bootloader_text", "UpgradeBootloaderWindow"), |
59 |
"network" : ("network_text", ("HostnameWindow")), |
60 |
"timezone" : ("timezone_text", "TimezoneWindow"), |
61 |
"accounts" : ("userauth_text", "RootPasswordWindow"), |
62 |
"tasksel": ("task_text", "TaskWindow"), |
63 |
"install" : ("progress_text", "setupForInstall"), |
64 |
"complete" : ("complete_text", "FinishedWindow"), |
65 |
} |
66 |
|
67 |
if iutil.isS390(): |
68 |
stepToClasses["bootloader"] = ("zipl_text", ( "ZiplWindow")) |
69 |
|
70 |
class InstallWindow: |
71 |
def __call__ (self, screen): |
72 |
raise RuntimeError, "Unimplemented screen" |
73 |
|
74 |
class WaitWindow: |
75 |
def pop(self): |
76 |
self.screen.popWindow() |
77 |
self.screen.refresh() |
78 |
|
79 |
def refresh(self): |
80 |
pass |
81 |
|
82 |
def __init__(self, screen, title, text): |
83 |
self.screen = screen |
84 |
width = 40 |
85 |
if (len(text) < width): width = len(text) |
86 |
|
87 |
t = TextboxReflowed(width, text) |
88 |
|
89 |
g = GridForm(self.screen, title, 1, 1) |
90 |
g.add(t, 0, 0) |
91 |
g.draw() |
92 |
self.screen.refresh() |
93 |
|
94 |
class OkCancelWindow: |
95 |
def getrc(self): |
96 |
return self.rc |
97 |
|
98 |
def __init__(self, screen, title, text): |
99 |
rc = ButtonChoiceWindow(screen, title, text, |
100 |
buttons=[TEXT_OK_BUTTON, _("Cancel")]) |
101 |
if rc == string.lower(_("Cancel")): |
102 |
self.rc = 1 |
103 |
else: |
104 |
self.rc = 0 |
105 |
|
106 |
class ProgressWindow: |
107 |
def pop(self): |
108 |
self.screen.popWindow() |
109 |
self.screen.refresh() |
110 |
del self.scale |
111 |
self.scale = None |
112 |
|
113 |
def pulse(self): |
114 |
pass |
115 |
|
116 |
def set(self, amount): |
117 |
self.scale.set(int(float(amount) * self.multiplier)) |
118 |
self.screen.refresh() |
119 |
|
120 |
def refresh(self): |
121 |
pass |
122 |
|
123 |
def __init__(self, screen, title, text, total, updpct = 0.05, pulse = False): |
124 |
self.multiplier = 1 |
125 |
if total == 1.0: |
126 |
self.multiplier = 100 |
127 |
self.screen = screen |
128 |
width = 55 |
129 |
if (len(text) > width): width = len(text) |
130 |
|
131 |
t = TextboxReflowed(width, text) |
132 |
|
133 |
g = GridForm(self.screen, title, 1, 2) |
134 |
g.add(t, 0, 0, (0, 0, 0, 1), anchorLeft=1) |
135 |
|
136 |
self.scale = Scale(int(width), int(float(total) * self.multiplier)) |
137 |
if not pulse: |
138 |
g.add(self.scale, 0, 1) |
139 |
|
140 |
g.draw() |
141 |
self.screen.refresh() |
142 |
|
143 |
class LuksPassphraseWindow: |
144 |
def __init__(self, screen, passphrase = "", preexist = False): |
145 |
self.screen = screen |
146 |
self.passphrase = passphrase |
147 |
self.minLength = 8 |
148 |
self.preexist = preexist |
149 |
self.txt = _("Choose a passphrase for the encrypted devices. You " |
150 |
"will be prompted for this passphrase during system boot.") |
151 |
self.rc = None |
152 |
|
153 |
def run(self): |
154 |
toplevel = GridForm(self.screen, _("Passphrase for encrypted device"), |
155 |
1, 5) |
156 |
|
157 |
txt = TextboxReflowed(65, self.txt) |
158 |
toplevel.add(txt, 0, 0) |
159 |
|
160 |
passphraseentry = Entry(60, password = 1) |
161 |
toplevel.add(passphraseentry, 0, 1, (0,0,0,1)) |
162 |
|
163 |
confirmentry = Entry(60, password = 1) |
164 |
toplevel.add(confirmentry, 0, 2, (0,0,0,1)) |
165 |
|
166 |
if self.preexist: |
167 |
globalcheckbox = Checkbox(_("Also add this passphrase to all existing encrypted devices"), isOn = True) |
168 |
toplevel.add(globalcheckbox, 0, 3) |
169 |
|
170 |
buttons = ButtonBar(self.screen, [TEXT_OK_BUTTON, TEXT_CANCEL_BUTTON]) |
171 |
toplevel.add(buttons, 0, 4, growx=1) |
172 |
|
173 |
passphraseentry.set(self.passphrase) |
174 |
confirmentry.set(self.passphrase) |
175 |
|
176 |
while True: |
177 |
rc = toplevel.run() |
178 |
res = buttons.buttonPressed(rc) |
179 |
|
180 |
passphrase = None |
181 |
if res == TEXT_OK_CHECK or rc == "F12": |
182 |
passphrase = passphraseentry.value() |
183 |
confirm = confirmentry.value() |
184 |
|
185 |
if passphrase != confirm: |
186 |
ButtonChoiceWindow(self.screen, |
187 |
_("Error with passphrase"), |
188 |
_("The passphrases you entered were " |
189 |
"different. Please try again."), |
190 |
buttons=[TEXT_OK_BUTTON]) |
191 |
passphraseentry.set("") |
192 |
confirmentry.set("") |
193 |
continue |
194 |
|
195 |
if len(passphrase) < self.minLength: |
196 |
ButtonChoiceWindow(self.screen, |
197 |
_("Error with passphrase"), |
198 |
P_("The passphrase must be at least " |
199 |
"%d character long.", |
200 |
"The passphrase must be at least " |
201 |
"%d characters long.", |
202 |
self.minLength) |
203 |
% (self.minLength,), |
204 |
buttons=[TEXT_OK_BUTTON]) |
205 |
passphraseentry.set("") |
206 |
confirmentry.set("") |
207 |
continue |
208 |
else: |
209 |
passphrase = self.passphrase |
210 |
passphraseentry.set(self.passphrase) |
211 |
confirmentry.set(self.passphrase) |
212 |
|
213 |
retrofit = False |
214 |
if self.preexist: |
215 |
retrofit = globalcheckbox.selected() |
216 |
self.rc = passphrase |
217 |
return (self.rc, retrofit) |
218 |
|
219 |
def pop(self): |
220 |
self.screen.popWindow() |
221 |
|
222 |
class PassphraseEntryWindow: |
223 |
def __init__(self, screen, device): |
224 |
self.screen = screen |
225 |
self.txt = _("Device %s is encrypted. In order to " |
226 |
"access the device's contents during " |
227 |
"installation you must enter the device's " |
228 |
"passphrase below.") % (device,) |
229 |
self.rc = None |
230 |
|
231 |
def run(self): |
232 |
toplevel = GridForm(self.screen, _("Passphrase"), 1, 4) |
233 |
|
234 |
txt = TextboxReflowed(65, self.txt) |
235 |
toplevel.add(txt, 0, 0) |
236 |
|
237 |
passphraseentry = Entry(60, password = 1) |
238 |
toplevel.add(passphraseentry, 0, 1, (0,0,0,1)) |
239 |
|
240 |
globalcheckbox = Checkbox(_("This is a global passphrase")) |
241 |
toplevel.add(globalcheckbox, 0, 2) |
242 |
|
243 |
buttons = ButtonBar(self.screen, [TEXT_OK_BUTTON, TEXT_CANCEL_BUTTON]) |
244 |
toplevel.add(buttons, 0, 3, growx=1) |
245 |
|
246 |
rc = toplevel.run() |
247 |
res = buttons.buttonPressed(rc) |
248 |
|
249 |
passphrase = None |
250 |
isglobal = False |
251 |
if res == TEXT_OK_CHECK or rc == "F12": |
252 |
passphrase = passphraseentry.value().strip() |
253 |
isglobal = globalcheckbox.selected() |
254 |
|
255 |
self.rc = (passphrase, isglobal) |
256 |
return self.rc |
257 |
|
258 |
def pop(self): |
259 |
self.screen.popWindow() |
260 |
|
261 |
class InstallInterface(InstallInterfaceBase): |
262 |
def progressWindow(self, title, text, total, updpct = 0.05, pulse = False): |
263 |
return ProgressWindow(self.screen, title, text, total, updpct, pulse) |
264 |
|
265 |
def exitWindow(self, title, text): |
266 |
return self.messageWindow(title, text, type="custom", |
267 |
custom_buttons=[_("Exit installer")]) |
268 |
|
269 |
def messageWindow(self, title, text, type="ok", default = None, |
270 |
custom_icon=None, custom_buttons=[]): |
271 |
text = str(text) |
272 |
if type == "ok": |
273 |
ButtonChoiceWindow(self.screen, title, text, |
274 |
buttons=[TEXT_OK_BUTTON]) |
275 |
elif type == "yesno": |
276 |
if default and default == "no": |
277 |
btnlist = [TEXT_NO_BUTTON, TEXT_YES_BUTTON] |
278 |
else: |
279 |
btnlist = [TEXT_YES_BUTTON, TEXT_NO_BUTTON] |
280 |
rc = ButtonChoiceWindow(self.screen, title, text, |
281 |
buttons=btnlist) |
282 |
if rc == "yes": |
283 |
return 1 |
284 |
else: |
285 |
return 0 |
286 |
elif type == "custom": |
287 |
tmpbut = [] |
288 |
for but in custom_buttons: |
289 |
tmpbut.append(string.replace(but,"_","")) |
290 |
|
291 |
rc = ButtonChoiceWindow(self.screen, title, text, width=60, |
292 |
buttons=tmpbut) |
293 |
|
294 |
idx = 0 |
295 |
for b in tmpbut: |
296 |
if string.lower(b) == rc: |
297 |
return idx |
298 |
idx = idx + 1 |
299 |
return 0 |
300 |
else: |
301 |
return OkCancelWindow(self.screen, title, text) |
302 |
|
303 |
def detailedMessageWindow(self, title, text, longText=None, type="ok", |
304 |
default=None, custom_icon=None, |
305 |
custom_buttons=[], expanded=False): |
306 |
t = TextboxReflowed(60, text, maxHeight=8) |
307 |
|
308 |
# if it is a string, just print it as it is (#674322) |
309 |
if isinstance(longText, basestring): |
310 |
lt = Textbox(60, 6, longText, scroll=1, wrap=1) |
311 |
# if the argument is anything else we have to join it together (#654074) |
312 |
else: |
313 |
lt = Textbox(60, 6, "\n".join(longText), scroll=1, wrap=1) |
314 |
|
315 |
g = GridFormHelp(self.screen, title, help, 1, 3) |
316 |
g.add(t, 0, 0) |
317 |
g.add(lt, 0, 1, padding = (0, 1, 0, 1)) |
318 |
|
319 |
if type == "ok": |
320 |
bb = ButtonBar(self.screen, [TEXT_OK_BUTTON]) |
321 |
g.add(bb, 0, 2, growx = 1) |
322 |
return bb.buttonPressed(g.runOnce(None, None)) |
323 |
elif type == "yesno": |
324 |
if default and default == "no": |
325 |
buttons = [TEXT_NO_BUTTON, TEXT_YES_BUTTON] |
326 |
else: |
327 |
buttons = [TEXT_YES_BUTTON, TEXT_NO_BUTTON] |
328 |
|
329 |
bb = ButtonBar(self.screen, buttons) |
330 |
g.add(bb, 0, 2, growx = 1) |
331 |
rc = bb.buttonPressed(g.runOnce(None, None)) |
332 |
|
333 |
if rc == "yes": |
334 |
return 1 |
335 |
else: |
336 |
return 0 |
337 |
elif type == "custom": |
338 |
buttons = [] |
339 |
idx = 0 |
340 |
|
341 |
for button in custom_buttons: |
342 |
buttons.append(string.replace(button, "_", "")) |
343 |
|
344 |
bb = ButtonBar(self.screen, buttons) |
345 |
g.add(bb, 0, 2, growx = 1) |
346 |
rc = bb.buttonPressed(g.runOnce(None, None)) |
347 |
|
348 |
for b in buttons: |
349 |
if string.lower(b) == rc: |
350 |
return idx |
351 |
idx += 1 |
352 |
|
353 |
return 0 |
354 |
else: |
355 |
return self.messageWindow(title, text, type, default, custom_icon, |
356 |
custom_buttons) |
357 |
|
358 |
def createRepoWindow(self): |
359 |
self.messageWindow(_("Error"), |
360 |
_("Repository editing is not available in text mode.")) |
361 |
|
362 |
def editRepoWindow(self, repoObj): |
363 |
self.messageWindow(_("Error"), |
364 |
_("Repository editing is not available in text mode.")) |
365 |
|
366 |
def entryWindow(self, title, text, prompt, entrylength = None): |
367 |
(res, value) = EntryWindow(self.screen, title, text, [prompt]) |
368 |
if res == "cancel": |
369 |
return None |
370 |
r = value[0] |
371 |
r.strip() |
372 |
return r |
373 |
|
374 |
def getLuksPassphrase(self, passphrase = "", preexist = False): |
375 |
w = LuksPassphraseWindow(self.screen, passphrase = passphrase, |
376 |
preexist = preexist) |
377 |
rc = w.run() |
378 |
w.pop() |
379 |
return rc |
380 |
|
381 |
def passphraseEntryWindow(self, device): |
382 |
w = PassphraseEntryWindow(self.screen, device) |
383 |
(passphrase, isglobal) = w.run() |
384 |
w.pop() |
385 |
return (passphrase, isglobal) |
386 |
|
387 |
def enableNetwork(self): |
388 |
if len(self.anaconda.id.network.netdevices) == 0: |
389 |
return False |
390 |
from netconfig_text import NetworkConfiguratorText |
391 |
w = NetworkConfiguratorText(self.screen, self.anaconda) |
392 |
ret = w.run() |
393 |
return ret != INSTALL_BACK |
394 |
|
395 |
def kickstartErrorWindow(self, text): |
396 |
s = _("The following error was found while parsing the " |
397 |
"kickstart configuration file:\n\n%s") %(text,) |
398 |
self.messageWindow(_("Error Parsing Kickstart Config"), |
399 |
s, |
400 |
type = "custom", |
401 |
custom_buttons = [("_Reboot")], |
402 |
custom_icon="error") |
403 |
|
404 |
def mainExceptionWindow(self, shortText, longTextFile): |
405 |
from meh.ui.text import MainExceptionWindow |
406 |
log.critical(shortText) |
407 |
exnWin = MainExceptionWindow(shortText, longTextFile, screen=self.screen) |
408 |
return exnWin |
409 |
|
410 |
def saveExceptionWindow(self, accountManager, signature, *args, **kwargs): |
411 |
from meh.ui.text import SaveExceptionWindow |
412 |
network.saveExceptionEnableNetwork(self) |
413 |
win = SaveExceptionWindow (accountManager, signature, screen=self.screen, |
414 |
*args, **kwargs) |
415 |
win.run() |
416 |
|
417 |
def waitWindow(self, title, text): |
418 |
return WaitWindow(self.screen, title, text) |
419 |
|
420 |
def beep(self): |
421 |
# no-op. could call newtBell() if it was bound |
422 |
pass |
423 |
|
424 |
def drawFrame(self): |
425 |
self.screen.drawRootText (0, 0, self.screen.width * " ") |
426 |
if productArch: |
427 |
self.screen.drawRootText (0, 0, _("Welcome to %(productName)s for %(productArch)s") % {'productName': productName, 'productArch': productArch}) |
428 |
else: |
429 |
self.screen.drawRootText (0, 0, _("Welcome to %s") % productName) |
430 |
|
431 |
self.screen.pushHelpLine(_(" <Tab>/<Alt-Tab> between elements | <Space> selects | <F12> next screen")) |
432 |
|
433 |
def setScreen(self, screen): |
434 |
self.screen = screen |
435 |
|
436 |
def shutdown(self): |
437 |
self.screen.finish() |
438 |
self.screen = None |
439 |
|
440 |
def suspend(self): |
441 |
self.screen.suspend() |
442 |
|
443 |
def resume(self): |
444 |
self.screen.resume() |
445 |
|
446 |
def __init__(self): |
447 |
InstallInterfaceBase.__init__(self) |
448 |
signal.signal(signal.SIGINT, signal.SIG_IGN) |
449 |
signal.signal(signal.SIGTSTP, signal.SIG_IGN) |
450 |
self.screen = SnackScreen() |
451 |
self._inconsistentLVMAnswers = {} |
452 |
|
453 |
def __del__(self): |
454 |
if self.screen: |
455 |
self.screen.finish() |
456 |
|
457 |
def isRealConsole(self): |
458 |
"""Returns True if this is a _real_ console that can do things, False |
459 |
for non-real consoles such as serial, i/p virtual consoles or xen.""" |
460 |
if flags.serial or flags.virtpconsole: |
461 |
return False |
462 |
if isys.isPseudoTTY(0): |
463 |
return False |
464 |
if isys.isVioConsole(): |
465 |
return False |
466 |
return True |
467 |
|
468 |
def resetInitializeDiskQuestion(self): |
469 |
pass |
470 |
|
471 |
def questionInitializeDisk(self, path, description, size, details=""): |
472 |
if not path: |
473 |
return False |
474 |
return True |
475 |
|
476 |
def resetReinitInconsistentLVMQuestion(self): |
477 |
self._inconsistentLVMAnswers = {} |
478 |
|
479 |
def questionReinitInconsistentLVM(self, pv_names=None, lv_name=None, vg_name=None): |
480 |
|
481 |
retVal = False # The less destructive default |
482 |
allSet = frozenset(["all"]) |
483 |
|
484 |
if not pv_names or (lv_name is None and vg_name is None): |
485 |
return retVal |
486 |
|
487 |
# We are caching answers so that we don't ask for ignoring |
488 |
# in each storage.reset() again (note that reinitialization is |
489 |
# done right after confirmation in dialog, not as a planned |
490 |
# action). |
491 |
key = frozenset(pv_names) |
492 |
if key in self._inconsistentLVMAnswers: |
493 |
log.info("UI not asking about disk initialization, " |
494 |
"using cached answer: %s" % self._inconsistentLVMAnswers[key]) |
495 |
return self._inconsistentLVMAnswers[key] |
496 |
elif allSet in self._inconsistentLVMAnswers: |
497 |
log.info("UI not asking about disk initialization, " |
498 |
"using cached answer: %s" % self._inconsistentLVMAnswers[allSet]) |
499 |
return self._inconsistentLVMAnswers[allSet] |
500 |
|
501 |
if vg_name is not None: |
502 |
message = "Volume Group %s" % vg_name |
503 |
elif lv_name is not None: |
504 |
message = "Logical Volume %s" % lv_name |
505 |
|
506 |
na = {'msg': message, 'pvs': ", ".join(pv_names)} |
507 |
rc = self.messageWindow(_("Warning"), |
508 |
_("Error processing LVM.\n" |
509 |
"There is inconsistent LVM data on %(msg)s. You can " |
510 |
"reinitialize all related PVs (%(pvs)s) which will erase " |
511 |
"the LVM metadata, or ignore which will preserve the " |
512 |
"contents. This action may also be applied to all other " |
513 |
"PVs with inconsistent metadata.") % na, |
514 |
type="custom", |
515 |
custom_buttons = [ _("_Ignore"), |
516 |
_("Ignore _all"), |
517 |
_("_Re-initialize"), |
518 |
_("Re-ini_tialize all") ], |
519 |
custom_icon="question") |
520 |
if rc == 0: |
521 |
retVal = False |
522 |
elif rc == 1: |
523 |
key = allSet |
524 |
retVal = False |
525 |
elif rc == 2: |
526 |
retVal = True |
527 |
elif rc == 3: |
528 |
key = allSet |
529 |
retVal = True |
530 |
|
531 |
self._inconsistentLVMAnswers[key] = retVal |
532 |
return retVal |
533 |
|
534 |
def run(self, anaconda): |
535 |
self.anaconda = anaconda |
536 |
instLang = anaconda.id.instLanguage |
537 |
|
538 |
if instLang.getFontFile(instLang.instLang) == "none": |
539 |
if not anaconda.isKickstart: |
540 |
ButtonChoiceWindow(self.screen, "Language Unavailable", |
541 |
"%s display is unavailable in text mode. " |
542 |
"The installation will continue in " |
543 |
"English." % (instLang.instLang,), |
544 |
buttons=[TEXT_OK_BUTTON]) |
545 |
|
546 |
if not self.isRealConsole(): |
547 |
self.screen.suspendCallback(spawnShell, self.screen) |
548 |
|
549 |
# drop into the python debugger on ctrl-z if we're running in test mode |
550 |
if flags.debug: |
551 |
self.screen.suspendCallback(debugSelf, self.screen) |
552 |
|
553 |
self.instLanguage = anaconda.id.instLanguage |
554 |
|
555 |
# draw the frame after setting up the fallback |
556 |
self.drawFrame() |
557 |
|
558 |
lastrc = INSTALL_OK |
559 |
(step, instance) = anaconda.dispatch.currentStep() |
560 |
while step: |
561 |
(file, classNames) = stepToClasses[step] |
562 |
|
563 |
if type(classNames) != type(()): |
564 |
classNames = (classNames,) |
565 |
|
566 |
if lastrc == INSTALL_OK: |
567 |
step = 0 |
568 |
else: |
569 |
step = len(classNames) - 1 |
570 |
|
571 |
while step >= 0 and step < len(classNames): |
572 |
# reget the args. they could change (especially direction) |
573 |
(foo, args) = anaconda.dispatch.currentStep() |
574 |
nextWindow = None |
575 |
|
576 |
while 1: |
577 |
try: |
578 |
found = imputil.imp.find_module(file) |
579 |
loaded = imputil.imp.load_module(classNames[step], |
580 |
found[0], found[1], |
581 |
found[2]) |
582 |
nextWindow = loaded.__dict__[classNames[step]] |
583 |
break |
584 |
except ImportError, e: |
585 |
rc = ButtonChoiceWindow(self.screen, _("Error!"), |
586 |
_("An error occurred when attempting " |
587 |
"to load an installer interface " |
588 |
"component.\n\nclassName = %s") |
589 |
% (classNames[step],), |
590 |
buttons=[_("Exit"), _("Retry")]) |
591 |
|
592 |
if rc == string.lower(_("Exit")): |
593 |
sys.exit(0) |
594 |
|
595 |
win = nextWindow() |
596 |
|
597 |
#log.info("TUI running step %s (class %s, file %s)" % |
598 |
#(step, file, classNames)) |
599 |
|
600 |
rc = win(self.screen, instance) |
601 |
|
602 |
if rc == INSTALL_NOOP: |
603 |
rc = lastrc |
604 |
|
605 |
if rc == INSTALL_BACK: |
606 |
step = step - 1 |
607 |
anaconda.dispatch.dir = DISPATCH_BACK |
608 |
elif rc == INSTALL_OK: |
609 |
step = step + 1 |
610 |
anaconda.dispatch.dir = DISPATCH_FORWARD |
611 |
|
612 |
lastrc = rc |
613 |
|
614 |
if step == -1: |
615 |
if not anaconda.dispatch.canGoBack(): |
616 |
ButtonChoiceWindow(self.screen, _("Cancelled"), |
617 |
_("I can't go to the previous step " |
618 |
"from here. You will have to try " |
619 |
"again."), |
620 |
buttons=[_("OK")]) |
621 |
anaconda.dispatch.gotoPrev() |
622 |
else: |
623 |
anaconda.dispatch.gotoNext() |
624 |
|
625 |
(step, args) = anaconda.dispatch.currentStep() |
626 |
|
627 |
self.screen.finish() |
628 |
|
629 |
def setSteps(self, anaconda): |
630 |
anaconda.dispatch.skipStep("filtertype", permanent=1) |
631 |
anaconda.dispatch.skipStep("filter", permanent=1) |
632 |
anaconda.dispatch.skipStep("cleardiskssel", permanent=1) |
633 |
anaconda.dispatch.skipStep("group-selection", permanent=1) |
634 |
|
635 |
def killSelf(screen): |
636 |
screen.finish() |
637 |
os._exit(0) |
638 |
|
639 |
def debugSelf(screen): |
640 |
screen.suspend() |
641 |
import pdb |
642 |
try: |
643 |
pdb.set_trace() |
644 |
except: |
645 |
sys.exit(-1) |
646 |
screen.resume() |
647 |
|
648 |
def spawnShell(screen): |
649 |
screen.suspend() |
650 |
print("\n\nType <exit> to return to the install program.\n") |
651 |
if os.path.exists("/bin/sh"): |
652 |
iutil.execConsole() |
653 |
else: |
654 |
print("Unable to find /bin/sh to execute! Not starting shell") |
655 |
time.sleep(5) |
656 |
screen.resume() |