home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / share / ubiquity / install.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2006-08-31  |  36.2 KB  |  1,237 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.4)
  3.  
  4. import sys
  5. import os
  6. import platform
  7. import errno
  8. import stat
  9. import re
  10. import textwrap
  11. import shutil
  12. import subprocess
  13. import time
  14. import struct
  15. import socket
  16. import fcntl
  17. import traceback
  18. import debconf
  19. import apt_pkg
  20. from apt.package import Package
  21. from apt.cache import Cache
  22. from apt.progress import FetchProgress, InstallProgress
  23. sys.path.insert(0, '/usr/lib/ubiquity')
  24. from ubiquity import misc
  25. from ubiquity.components import language_apply, apt_setup, timezone_apply, clock_setup, kbd_chooser_apply, usersetup_apply, hw_detect, check_kernels
  26.  
  27. class DebconfFetchProgress(FetchProgress):
  28.     """An object that reports apt's fetching progress using debconf."""
  29.     
  30.     def __init__(self, db, title, info_starting, info):
  31.         FetchProgress.__init__(self)
  32.         self.db = db
  33.         self.title = title
  34.         self.info_starting = info_starting
  35.         self.info = info
  36.         self.old_capb = None
  37.         self.eta = 0.0
  38.  
  39.     
  40.     def start(self):
  41.         self.db.progress('START', 0, 100, self.title)
  42.         if self.info_starting is not None:
  43.             self.db.progress('INFO', self.info_starting)
  44.         
  45.         self.old_capb = self.db.capb()
  46.         capb_list = self.old_capb.split()
  47.         capb_list.append('progresscancel')
  48.         self.db.capb(' '.join(capb_list))
  49.  
  50.     
  51.     def pulse(self):
  52.         FetchProgress.pulse(self)
  53.         
  54.         try:
  55.             self.db.progress('SET', int(self.percent))
  56.         except debconf.DebconfError:
  57.             return False
  58.  
  59.         if self.eta != 0.0:
  60.             time_str = '%d:%02d' % divmod(int(self.eta), 60)
  61.             self.db.subst(self.info, 'TIME', time_str)
  62.             
  63.             try:
  64.                 self.db.progress('INFO', self.info)
  65.             except debconf.DebconfError:
  66.                 return False
  67.             except:
  68.                 None<EXCEPTION MATCH>debconf.DebconfError
  69.             
  70.  
  71.         None<EXCEPTION MATCH>debconf.DebconfError
  72.         return True
  73.  
  74.     
  75.     def stop(self):
  76.         if self.old_capb is not None:
  77.             self.db.capb(self.old_capb)
  78.             self.old_capb = None
  79.             self.db.progress('STOP')
  80.         
  81.  
  82.  
  83.  
  84. class DebconfInstallProgress(InstallProgress):
  85.     """An object that reports apt's installation progress using debconf."""
  86.     
  87.     def __init__(self, db, title, info, error = None):
  88.         InstallProgress.__init__(self)
  89.         self.db = db
  90.         self.title = title
  91.         self.info = info
  92.         self.error_template = error
  93.         self.started = False
  94.         flags = fcntl.fcntl(self.statusfd.fileno(), fcntl.F_GETFL)
  95.         fcntl.fcntl(self.statusfd.fileno(), fcntl.F_SETFL, flags & ~(os.O_NONBLOCK))
  96.  
  97.     
  98.     def startUpdate(self):
  99.         self.db.progress('START', 0, 100, self.title)
  100.         self.started = True
  101.  
  102.     
  103.     def error(self, pkg, errormsg):
  104.         if self.error_template is not None:
  105.             self.db.subst(self.error_template, 'PACKAGE', pkg)
  106.             self.db.subst(self.error_template, 'MESSAGE', errormsg)
  107.             self.db.input('critical', self.error_template)
  108.             self.db.go()
  109.         
  110.  
  111.     
  112.     def statusChange(self, pkg, percent, status):
  113.         self.percent = percent
  114.         self.status = status
  115.         self.db.progress('SET', int(percent))
  116.         self.db.subst(self.info, 'DESCRIPTION', status)
  117.         self.db.progress('INFO', self.info)
  118.  
  119.     
  120.     def updateInterface(self):
  121.         if self.statusfd is None:
  122.             return False
  123.         
  124.         
  125.         try:
  126.             while not self.read.endswith('\n'):
  127.                 r = os.read(self.statusfd.fileno(), 1)
  128.                 if not r:
  129.                     return False
  130.                 
  131.                 self.read += r
  132.                 continue
  133.                 self
  134.         except OSError:
  135.             (err, errstr) = None
  136.             print errstr
  137.  
  138.         if self.read.endswith('\n'):
  139.             s = self.read
  140.             (status, pkg, percent, status_str) = s.split(':', 3)
  141.             if status == 'pmerror':
  142.                 self.error(pkg, status_str)
  143.             elif status == 'pmconffile':
  144.                 match = re.compile("\\s*'(.*)'\\s*'(.*)'.*").match(status_str)
  145.                 if match:
  146.                     self.conffile(match.group(1), match.group(2))
  147.                 
  148.             else:
  149.                 self.statusChange(pkg, float(percent), status_str.strip())
  150.             self.read = ''
  151.         
  152.         return True
  153.  
  154.     
  155.     def run(self, pm):
  156.         child_pid = self.fork()
  157.         if child_pid == 0:
  158.             os.close(self.writefd)
  159.             
  160.             try:
  161.                 while self.updateInterface():
  162.                     pass
  163.             except (KeyboardInterrupt, SystemExit):
  164.                 pass
  165.             except:
  166.                 traceback.print_exc(file = sys.stderr)
  167.  
  168.             os._exit(0)
  169.         
  170.         self.statusfd.close()
  171.         saved_stdout = os.dup(1)
  172.         os.dup2(2, 1)
  173.         saved_environ_keys = ('DEBIAN_FRONTEND', 'DEBIAN_HAS_FRONTEND', 'DEBCONF_USE_CDEBCONF')
  174.         saved_environ = { }
  175.         for key in saved_environ_keys:
  176.             if key in os.environ:
  177.                 saved_environ[key] = os.environ[key]
  178.                 continue
  179.         
  180.         os.environ['DEBIAN_FRONTEND'] = 'noninteractive'
  181.         if 'DEBIAN_HAS_FRONTEND' in os.environ:
  182.             del os.environ['DEBIAN_HAS_FRONTEND']
  183.         
  184.         if 'DEBCONF_USE_CDEBCONF' in os.environ:
  185.             del os.environ['DEBCONF_USE_CDEBCONF']
  186.         
  187.         res = pm.ResultFailed
  188.         
  189.         try:
  190.             res = pm.DoInstall(self.writefd)
  191.         finally:
  192.             os.close(self.writefd)
  193.             while True:
  194.                 
  195.                 try:
  196.                     (pid, status) = os.waitpid(child_pid, 0)
  197.                     if pid != child_pid:
  198.                         break
  199.                     
  200.                     if os.WIFEXITED(status) or os.WIFSIGNALED(status):
  201.                         break
  202.                 continue
  203.                 except OSError:
  204.                     break
  205.                     continue
  206.                 
  207.  
  208.                 None<EXCEPTION MATCH>OSError
  209.             os.dup2(saved_stdout, 1)
  210.             os.close(saved_stdout)
  211.             for key in saved_environ_keys:
  212.                 if key in saved_environ:
  213.                     os.environ[key] = saved_environ[key]
  214.                     continue
  215.                 if key in os.environ:
  216.                     del os.environ[key]
  217.                     continue
  218.             
  219.  
  220.         return res
  221.  
  222.     
  223.     def finishUpdate(self):
  224.         if self.started:
  225.             self.db.progress('STOP')
  226.             self.started = False
  227.         
  228.  
  229.  
  230.  
  231. class InstallStepError(Exception):
  232.     '''Raised when an install step fails.
  233.  
  234.     Attributes:
  235.         message -- message returned with exception
  236.  
  237.     '''
  238.     
  239.     def __init__(self, message):
  240.         Exception.__init__(self, message)
  241.         self.message = message
  242.  
  243.  
  244.  
  245. class Install:
  246.     
  247.     def __init__(self):
  248.         '''Initial attributes.'''
  249.         if os.path.isdir('/rofs'):
  250.             self.source = '/rofs'
  251.         elif os.path.isdir('/UNIONFS'):
  252.             self.source = '/UNIONFS'
  253.         else:
  254.             self.source = '/source'
  255.         self.target = '/target'
  256.         self.unionfs = False
  257.         self.kernel_version = platform.release()
  258.         self.db = debconf.Debconf()
  259.         apt_pkg.InitConfig()
  260.         apt_pkg.Config.Set('Dir', '/target')
  261.         apt_pkg.Config.Set('Dir::State::status', '/target/var/lib/dpkg/status')
  262.         apt_pkg.Config.Set('APT::GPGV::TrustedKeyring', '/target/etc/apt/trusted.gpg')
  263.         apt_pkg.Config.Set('Acquire::gpgv::Options::', '--ignore-time-conflict')
  264.         apt_pkg.Config.Set('DPkg::Options::', '--root=/target')
  265.         apt_pkg.Config.Clear('DPkg::Pre-Install-Pkgs')
  266.         apt_pkg.InitSystem()
  267.  
  268.     
  269.     def excepthook(self, exctype, excvalue, exctb):
  270.         '''Crash handler. Dump the traceback to a file so that it can be
  271.         read by the caller.'''
  272.         if issubclass(exctype, KeyboardInterrupt) or issubclass(exctype, SystemExit):
  273.             return None
  274.         
  275.         tbtext = ''.join(traceback.format_exception(exctype, excvalue, exctb))
  276.         print >>sys.stderr, 'Exception during installation:'
  277.         print >>sys.stderr, tbtext
  278.         tbfile = open('/var/lib/ubiquity/install.trace', 'w')
  279.         print >>tbfile, tbtext
  280.         tbfile.close()
  281.         sys.exit(1)
  282.  
  283.     
  284.     def run(self):
  285.         '''Run the install stage: copy everything to the target system, then
  286.         configure it as necessary.'''
  287.         self.db.progress('START', 0, 100, 'ubiquity/install/title')
  288.         self.db.progress('INFO', 'ubiquity/install/mounting_source')
  289.         
  290.         try:
  291.             if self.source == '/source':
  292.                 self.mount_source()
  293.             
  294.             self.db.progress('SET', 1)
  295.             self.db.progress('REGION', 1, 75)
  296.             self.copy_all()
  297.             self.db.progress('SET', 75)
  298.             self.db.progress('INFO', 'ubiquity/install/cleanup')
  299.             if self.source == '/source':
  300.                 self.umount_source()
  301.             
  302.             self.db.progress('SET', 76)
  303.             self.db.progress('REGION', 76, 77)
  304.             self.run_target_config_hooks()
  305.             self.db.progress('SET', 77)
  306.             self.db.progress('REGION', 77, 78)
  307.             self.db.progress('INFO', 'ubiquity/install/locales')
  308.             self.configure_locales()
  309.             self.db.progress('SET', 78)
  310.             self.db.progress('REGION', 78, 79)
  311.             self.db.progress('INFO', 'ubiquity/install/network')
  312.             self.configure_network()
  313.             self.db.progress('SET', 79)
  314.             self.db.progress('REGION', 79, 80)
  315.             self.db.progress('INFO', 'ubiquity/install/apt')
  316.             self.configure_apt()
  317.             self.db.progress('SET', 80)
  318.             self.db.progress('REGION', 80, 84)
  319.             
  320.             try:
  321.                 self.install_language_packs()
  322.             except InstallStepError:
  323.                 pass
  324.             except IOError:
  325.                 pass
  326.             except SystemError:
  327.                 pass
  328.  
  329.             self.db.progress('SET', 84)
  330.             self.db.progress('REGION', 84, 85)
  331.             self.db.progress('INFO', 'ubiquity/install/timezone')
  332.             self.configure_timezone()
  333.             self.db.progress('SET', 85)
  334.             self.db.progress('REGION', 85, 87)
  335.             self.db.progress('INFO', 'ubiquity/install/keyboard')
  336.             self.configure_keyboard()
  337.             self.db.progress('SET', 87)
  338.             self.db.progress('REGION', 87, 88)
  339.             self.db.progress('INFO', 'ubiquity/install/user')
  340.             self.configure_user()
  341.             self.db.progress('SET', 88)
  342.             self.db.progress('REGION', 88, 92)
  343.             self.db.progress('INFO', 'ubiquity/install/hardware')
  344.             self.configure_hardware()
  345.             self.db.progress('SET', 92)
  346.             self.db.progress('REGION', 92, 93)
  347.             self.remove_unusable_kernels()
  348.             self.db.progress('SET', 93)
  349.             self.db.progress('REGION', 93, 94)
  350.             self.db.progress('INFO', 'ubiquity/install/bootloader')
  351.             self.configure_bootloader()
  352.             self.db.progress('SET', 94)
  353.             self.db.progress('REGION', 94, 99)
  354.             self.db.progress('INFO', 'ubiquity/install/removing')
  355.             self.remove_extras()
  356.             self.db.progress('SET', 99)
  357.             self.db.progress('INFO', 'ubiquity/install/log_files')
  358.             self.copy_logs()
  359.             self.cleanup()
  360.             self.db.progress('SET', 100)
  361.         finally:
  362.             
  363.             try:
  364.                 self.db.progress('STOP')
  365.             except (KeyboardInterrupt, SystemExit):
  366.                 raise 
  367.             except:
  368.                 pass
  369.  
  370.  
  371.  
  372.     
  373.     def copy_all(self):
  374.         '''Core copy process. This is the most important step of this
  375.         stage. It clones live filesystem into a local partition in the
  376.         selected hard disk.'''
  377.         files = []
  378.         total_size = 0
  379.         self.db.progress('START', 0, 100, 'ubiquity/install/title')
  380.         self.db.progress('INFO', 'ubiquity/install/scanning')
  381.         walklen = 0
  382.         for entry in os.walk(self.source):
  383.             walklen += 1
  384.         
  385.         walkpos = 0
  386.         walkprogress = 0
  387.         for dirpath, dirnames, filenames in os.walk(self.source):
  388.             walkpos += 1
  389.             if int((float(walkpos) / walklen) * 10) != walkprogress:
  390.                 walkprogress = int((float(walkpos) / walklen) * 10)
  391.                 self.db.progress('SET', walkprogress)
  392.             
  393.             sourcepath = dirpath[len(self.source) + 1:]
  394.             for name in dirnames + filenames:
  395.                 relpath = os.path.join(sourcepath, name)
  396.                 fqpath = os.path.join(self.source, dirpath, name)
  397.                 total_size += os.lstat(fqpath).st_size
  398.                 files.append(relpath)
  399.             
  400.         
  401.         self.db.progress('SET', 10)
  402.         self.db.progress('INFO', 'ubiquity/install/copying')
  403.         copy_progress = 0
  404.         (copied_size, counter) = (0, 0)
  405.         directory_times = []
  406.         time_start = time.time()
  407.         times = [
  408.             (time_start, copied_size)]
  409.         long_enough = False
  410.         time_last_update = time_start
  411.         old_umask = os.umask(0)
  412.         for path in files:
  413.             sourcepath = os.path.join(self.source, path)
  414.             targetpath = os.path.join(self.target, path)
  415.             st = os.lstat(sourcepath)
  416.             mode = stat.S_IMODE(st.st_mode)
  417.             if stat.S_ISLNK(st.st_mode):
  418.                 if not os.path.lexists(targetpath):
  419.                     linkto = os.readlink(sourcepath)
  420.                     os.symlink(linkto, targetpath)
  421.                 
  422.             elif stat.S_ISDIR(st.st_mode):
  423.                 if not os.path.isdir(targetpath):
  424.                     os.mkdir(targetpath, mode)
  425.                 
  426.             elif stat.S_ISCHR(st.st_mode):
  427.                 os.mknod(targetpath, stat.S_IFCHR | mode, st.st_rdev)
  428.             elif stat.S_ISBLK(st.st_mode):
  429.                 os.mknod(targetpath, stat.S_IFBLK | mode, st.st_rdev)
  430.             elif stat.S_ISFIFO(st.st_mode):
  431.                 os.mknod(targetpath, stat.S_IFIFO | mode)
  432.             elif stat.S_ISSOCK(st.st_mode):
  433.                 os.mknod(targetpath, stat.S_IFSOCK | mode)
  434.             elif stat.S_ISREG(st.st_mode):
  435.                 if not os.path.exists(targetpath):
  436.                     shutil.copyfile(sourcepath, targetpath)
  437.                 
  438.             
  439.             copied_size += st.st_size
  440.             os.lchown(targetpath, st.st_uid, st.st_gid)
  441.             if not stat.S_ISLNK(st.st_mode):
  442.                 os.chmod(targetpath, mode)
  443.             
  444.             if stat.S_ISDIR(st.st_mode):
  445.                 directory_times.append((targetpath, st.st_atime, st.st_mtime))
  446.             elif not stat.S_ISLNK(st.st_mode):
  447.                 os.utime(targetpath, (st.st_atime, st.st_mtime))
  448.             
  449.             if int(copied_size * 90 / total_size) != copy_progress:
  450.                 copy_progress = int(copied_size * 90 / total_size)
  451.                 self.db.progress('SET', 10 + copy_progress)
  452.             
  453.             time_now = time.time()
  454.             if time_now - times[-1][0] >= 0.5:
  455.                 times.append((time_now, copied_size))
  456.                 if not long_enough and time_now - times[0][0] >= 10:
  457.                     long_enough = True
  458.                 
  459.                 if long_enough and time_now - time_last_update >= 2:
  460.                     time_last_update = time_now
  461.                     while time_now - times[0][0] > 60 and time_now - times[1][0] >= 60:
  462.                         times.pop(0)
  463.                     speed = (times[-1][1] - times[0][1]) / (times[-1][0] - times[0][0])
  464.                     time_remaining = int((total_size - copied_size) / speed)
  465.                     time_str = '%d:%02d' % divmod(time_remaining, 60)
  466.                     self.db.subst('ubiquity/install/copying_time', 'TIME', time_str)
  467.                     self.db.progress('INFO', 'ubiquity/install/copying_time')
  468.                 
  469.             time_now - time_last_update >= 2
  470.         
  471.         for dirtime in directory_times:
  472.             (directory, atime, mtime) = dirtime
  473.             os.utime(directory, (atime, mtime))
  474.         
  475.         os.umask(old_umask)
  476.         self.db.progress('SET', 100)
  477.         self.db.progress('STOP')
  478.  
  479.     
  480.     def copy_logs(self):
  481.         '''copy log files into installed system.'''
  482.         target_dir = os.path.join(self.target, 'var/log/installer')
  483.         if not os.path.exists(target_dir):
  484.             os.makedirs(target_dir)
  485.         
  486.         for log_file in ('/var/log/installer/syslog', '/var/log/partman', '/var/log/installer/version'):
  487.             target_log_file = os.path.join(target_dir, os.path.basename(log_file))
  488.             if not misc.ex('cp', '-a', log_file, target_log_file):
  489.                 misc.pre_log('error', 'Failed to copy installation log file')
  490.             
  491.             os.chmod(target_log_file, stat.S_IRUSR | stat.S_IWUSR)
  492.         
  493.  
  494.     
  495.     def mount_source(self):
  496.         '''mounting loop system from cloop or squashfs system.'''
  497.         self.dev = ''
  498.         if not os.path.isdir(self.source):
  499.             
  500.             try:
  501.                 os.mkdir(self.source)
  502.             except Exception:
  503.                 e = None
  504.                 print e
  505.  
  506.             misc.pre_log('info', 'mkdir %s' % self.source)
  507.         
  508.         for line in open('/proc/mounts'):
  509.             (device, fstype) = line.split()[1:3]
  510.             if fstype == 'squashfs' and os.path.exists(device):
  511.                 misc.ex('mount', '--bind', device, self.source)
  512.                 self.unionfs = True
  513.                 return None
  514.                 continue
  515.         
  516.         fsfiles = [
  517.             '/cdrom/casper/filesystem.cloop',
  518.             '/cdrom/casper/filesystem.squashfs',
  519.             '/cdrom/META/META.squashfs']
  520.         for fsfile in fsfiles:
  521.             if os.path.isfile(fsfile):
  522.                 if os.path.splitext(fsfile)[1] == '.cloop':
  523.                     self.dev = '/dev/cloop1'
  524.                     break
  525.                 elif os.path.splitext(fsfile)[1] == '.squashfs':
  526.                     self.dev = '/dev/loop3'
  527.                     break
  528.                 
  529.             os.path.splitext(fsfile)[1] == '.cloop'
  530.         
  531.         if self.dev == '':
  532.             raise InstallStepError('No source device found')
  533.         
  534.         misc.ex('losetup', self.dev, file)
  535.         
  536.         try:
  537.             misc.ex('mount', self.dev, self.source)
  538.         except Exception:
  539.             e = None
  540.             print e
  541.  
  542.  
  543.     
  544.     def umount_source(self):
  545.         '''umounting loop system from cloop or squashfs system.'''
  546.         if not misc.ex('umount', self.source):
  547.             raise InstallStepError('Failed to unmount source device')
  548.         
  549.         if self.unionfs:
  550.             return None
  551.         
  552.         if not misc.ex('losetup', '-d', self.dev) and self.dev != '':
  553.             raise InstallStepError('Failed to detach loopback source device')
  554.         
  555.  
  556.     
  557.     def run_target_config_hooks(self):
  558.         '''Run hook scripts from /usr/lib/ubiquity/target-config. This allows
  559.         casper to hook into us and repeat bits of its configuration in the
  560.         target system.'''
  561.         hookdir = '/usr/lib/ubiquity/target-config'
  562.         if os.path.isdir(hookdir):
  563.             hooks = filter((lambda entry: '.' not in entry), os.listdir(hookdir))
  564.             self.db.progress('START', 0, len(hooks), 'ubiquity/install/title')
  565.             for hookentry in hooks:
  566.                 hook = os.path.join(hookdir, hookentry)
  567.                 if not os.access(hook, os.X_OK):
  568.                     self.db.progress('STEP', 1)
  569.                     continue
  570.                 
  571.                 self.db.subst('ubiquity/install/target_hook', 'SCRIPT', hookentry)
  572.                 self.db.progress('INFO', 'ubiquity/install/target_hook')
  573.                 subprocess.call(hook)
  574.                 self.db.progress('STEP', 1)
  575.             
  576.             self.db.progress('STOP')
  577.         
  578.  
  579.     
  580.     def configure_locales(self):
  581.         '''Apply locale settings to installed system.'''
  582.         dbfilter = language_apply.LanguageApply(None)
  583.         ret = dbfilter.run_command(auto_process = True)
  584.         if ret != 0:
  585.             raise InstallStepError('LanguageApply failed with code %d' % ret)
  586.         
  587.  
  588.     
  589.     def configure_apt(self):
  590.         '''Configure /etc/apt/sources.list.'''
  591.         apt_conf_itc = open(os.path.join(self.target, 'etc/apt/apt.conf.d/00IgnoreTimeConflict'), 'w')
  592.         print >>apt_conf_itc, 'Acquire::gpgv::Options { "--ignore-time-conflict"; };'
  593.         apt_conf_itc.close()
  594.         dbfilter = apt_setup.AptSetup(None)
  595.         ret = dbfilter.run_command(auto_process = True)
  596.         if ret != 0:
  597.             raise InstallStepError('AptSetup failed with code %d' % ret)
  598.         
  599.  
  600.     
  601.     def get_cache_pkg(self, cache, pkg):
  602.         
  603.         try:
  604.             return cache[pkg]
  605.         except KeyError:
  606.             return None
  607.  
  608.  
  609.     
  610.     def record_installed(self, pkgs):
  611.         """Record which packages we've explicitly installed so that we don't
  612.         try to remove them later."""
  613.         record_file = '/var/lib/ubiquity/apt-installed'
  614.         if not os.path.exists(os.path.dirname(record_file)):
  615.             os.makedirs(os.path.dirname(record_file))
  616.         
  617.         record = open(record_file, 'a')
  618.         for pkg in pkgs:
  619.             print >>record, pkg
  620.         
  621.         record.close()
  622.  
  623.     
  624.     def mark_install(self, cache, pkg):
  625.         cachedpkg = self.get_cache_pkg(cache, pkg)
  626.         if cachedpkg is not None and not (cachedpkg.isInstalled):
  627.             apt_error = False
  628.             
  629.             try:
  630.                 cachedpkg.markInstall()
  631.             except SystemError:
  632.                 apt_error = True
  633.  
  634.             if cache._depcache.BrokenCount > 0 or apt_error:
  635.                 cachedpkg.markKeep()
  636.                 if not cache._depcache.BrokenCount == 0:
  637.                     raise AssertionError
  638.             
  639.         
  640.  
  641.     
  642.     def install_language_packs(self):
  643.         langpacks = []
  644.         
  645.         try:
  646.             langpack_db = self.db.get('base-config/language-packs')
  647.             langpacks = langpack_db.replace(',', '').split()
  648.         except debconf.DebconfError:
  649.             pass
  650.  
  651.         if not langpacks:
  652.             
  653.             try:
  654.                 langpack_db = self.db.get('pkgsel/language-packs')
  655.                 langpacks = langpack_db.replace(',', '').split()
  656.             except debconf.DebconfError:
  657.                 pass
  658.             except:
  659.                 None<EXCEPTION MATCH>debconf.DebconfError
  660.             
  661.  
  662.         None<EXCEPTION MATCH>debconf.DebconfError
  663.         if not langpacks:
  664.             
  665.             try:
  666.                 langpack_db = self.db.get('localechooser/supported-locales')
  667.                 langpack_set = set()
  668.                 for locale in langpack_db.replace(',', '').split():
  669.                     langpack_set.add(locale.split('_')[0])
  670.                 
  671.                 langpacks = sorted(langpack_set)
  672.             except debconf.DebconfError:
  673.                 pass
  674.             except:
  675.                 None<EXCEPTION MATCH>debconf.DebconfError
  676.             
  677.  
  678.         None<EXCEPTION MATCH>debconf.DebconfError
  679.         if not langpacks:
  680.             langpack_db = self.db.get('debian-installer/locale')
  681.             langpacks = [
  682.                 langpack_db.split('_')[0]]
  683.         
  684.         misc.pre_log('info', 'keeping language packs for: %s' % ' '.join(langpacks))
  685.         
  686.         try:
  687.             lppatterns = self.db.get('pkgsel/language-pack-patterns').split()
  688.         except debconf.DebconfError:
  689.             return None
  690.  
  691.         to_install = []
  692.         for lp in langpacks:
  693.             to_install.append('language-pack-%s' % lp)
  694.             for pattern in lppatterns:
  695.                 to_install.append(pattern.replace('$LL', lp))
  696.             
  697.             to_install.append('language-support-%s' % lp)
  698.         
  699.         self.record_installed(to_install)
  700.         self.db.progress('START', 0, 100, 'ubiquity/langpacks/title')
  701.         self.db.progress('REGION', 0, 10)
  702.         fetchprogress = DebconfFetchProgress(self.db, 'ubiquity/langpacks/title', 'ubiquity/install/apt_indices_starting', 'ubiquity/install/apt_indices')
  703.         cache = Cache()
  704.         
  705.         try:
  706.             if cache.update(fetchprogress) not in (0, True):
  707.                 fetchprogress.stop()
  708.                 self.db.progress('STOP')
  709.                 return None
  710.         except IOError:
  711.             e = None
  712.             print >>sys.stderr, e
  713.             sys.stderr.flush()
  714.             self.db.progress('STOP')
  715.             raise 
  716.  
  717.         cache.open(None)
  718.         self.db.progress('SET', 10)
  719.         self.db.progress('REGION', 10, 100)
  720.         fetchprogress = DebconfFetchProgress(self.db, 'ubiquity/langpacks/title', None, 'ubiquity/langpacks/packages')
  721.         installprogress = DebconfInstallProgress(self.db, 'ubiquity/langpacks/title', 'ubiquity/install/apt_info')
  722.         for lp in to_install:
  723.             self.mark_install(cache, lp)
  724.         
  725.         installed_pkgs = []
  726.         for pkg in cache.keys():
  727.             if cache[pkg].markedInstall and cache[pkg].markedUpgrade and cache[pkg].markedReinstall or cache[pkg].markedDowngrade:
  728.                 installed_pkgs.append(pkg)
  729.                 continue
  730.         
  731.         self.record_installed(installed_pkgs)
  732.         
  733.         try:
  734.             if not cache.commit(fetchprogress, installprogress):
  735.                 fetchprogress.stop()
  736.                 installprogress.finishUpdate()
  737.                 self.db.progress('STOP')
  738.                 return None
  739.         except IOError:
  740.             e = None
  741.             print >>sys.stderr, e
  742.             sys.stderr.flush()
  743.             self.db.progress('STOP')
  744.             raise 
  745.         except SystemError:
  746.             e = None
  747.             print >>sys.stderr, e
  748.             sys.stderr.flush()
  749.             self.db.progress('STOP')
  750.             raise 
  751.  
  752.         self.db.progress('SET', 100)
  753.         self.db.progress('STOP')
  754.  
  755.     
  756.     def configure_timezone(self):
  757.         '''Set timezone on installed system.'''
  758.         dbfilter = timezone_apply.TimezoneApply(None)
  759.         ret = dbfilter.run_command(auto_process = True)
  760.         if ret != 0:
  761.             raise InstallStepError('TimezoneApply failed with code %d' % ret)
  762.         
  763.         dbfilter = clock_setup.ClockSetup(None)
  764.         ret = dbfilter.run_command(auto_process = True)
  765.         if ret != 0:
  766.             raise InstallStepError('ClockSetup failed with code %d' % ret)
  767.         
  768.  
  769.     
  770.     def configure_keyboard(self):
  771.         '''Set keyboard in installed system.'''
  772.         
  773.         try:
  774.             keymap = self.db.get('debian-installer/keymap')
  775.             self.set_debconf('debian-installer/keymap', keymap)
  776.         except debconf.DebconfError:
  777.             pass
  778.  
  779.         dbfilter = kbd_chooser_apply.KbdChooserApply(None)
  780.         ret = dbfilter.run_command(auto_process = True)
  781.         if ret != 0:
  782.             raise InstallStepError('KbdChooserApply failed with code %d' % ret)
  783.         
  784.  
  785.     
  786.     def configure_user(self):
  787.         '''create the user selected along the installation process
  788.         into the installed system. Default user from live system is
  789.         deleted and skel for this new user is copied to $HOME.'''
  790.         dbfilter = usersetup_apply.UserSetupApply(None)
  791.         ret = dbfilter.run_command(auto_process = True)
  792.         if ret != 0:
  793.             raise InstallStepError('UserSetupApply failed with code %d' % ret)
  794.         
  795.  
  796.     
  797.     def get_resume_partition(self):
  798.         biggest_size = 0
  799.         biggest_partition = None
  800.         swaps = open('/proc/swaps')
  801.         for line in swaps:
  802.             words = line.split()
  803.             if words[1] != 'partition':
  804.                 continue
  805.             
  806.             size = int(words[2])
  807.             if size > biggest_size:
  808.                 biggest_size = size
  809.                 biggest_partition = words[0]
  810.                 continue
  811.         
  812.         swaps.close()
  813.         return biggest_partition
  814.  
  815.     
  816.     def configure_hardware(self):
  817.         '''reconfiguring several packages which depends on the
  818.         hardware system in which has been installed on and need some
  819.         automatic configurations to get work.'''
  820.         dbfilter = hw_detect.HwDetect(None, self.db)
  821.         ret = dbfilter.run_command(auto_process = True)
  822.         if ret != 0:
  823.             raise InstallStepError('HwDetect failed with code %d' % ret)
  824.         
  825.         self.db.progress('INFO', 'ubiquity/install/hardware')
  826.         subprocess.call([
  827.             '/usr/lib/ubiquity/debian-installer-utils/register-module.post-base-installer'])
  828.         resume = self.get_resume_partition()
  829.         if resume is not None:
  830.             resume_uuid = None
  831.             
  832.             try:
  833.                 resume_uuid = subprocess.Popen([
  834.                     'vol_id',
  835.                     '-u',
  836.                     resume], stdout = subprocess.PIPE).communicate()[0].rstrip('\n')
  837.             except OSError:
  838.                 pass
  839.  
  840.             if resume_uuid:
  841.                 resume = 'UUID=%s' % resume_uuid
  842.             
  843.             if os.path.exists(os.path.join(self.target, 'etc/initramfs-tools/conf.d')):
  844.                 configdir = os.path.join(self.target, 'etc/initramfs-tools/conf.d')
  845.             elif os.path.exists(os.path.join(self.target, 'etc/mkinitramfs/conf.d')):
  846.                 configdir = os.path.join(self.target, 'etc/mkinitramfs/conf.d')
  847.             else:
  848.                 configdir = None
  849.             if configdir is not None:
  850.                 configfile = open(os.path.join(configdir, 'resume'), 'w')
  851.                 print >>configfile, 'RESUME=%s' % resume
  852.                 configfile.close()
  853.             
  854.         
  855.         self.chrex('mount', '-t', 'proc', 'proc', '/proc')
  856.         self.chrex('mount', '-t', 'sysfs', 'sysfs', '/sys')
  857.         packages = [
  858.             'linux-image-' + self.kernel_version,
  859.             'linux-restricted-modules-' + self.kernel_version]
  860.         
  861.         try:
  862.             for package in packages:
  863.                 self.reconfigure(package)
  864.         finally:
  865.             self.chrex('umount', '/proc')
  866.             self.chrex('umount', '/sys')
  867.  
  868.  
  869.     
  870.     def get_all_interfaces(self):
  871.         '''Get all non-local network interfaces.'''
  872.         ifs = []
  873.         ifs_file = open('/proc/net/dev')
  874.         ifs_file.readline()
  875.         ifs_file.readline()
  876.         for line in ifs_file:
  877.             name = re.match('(.*?(?::\\d+)?):', line.strip()).group(1)
  878.             if name == 'lo':
  879.                 continue
  880.             
  881.             ifs.append(name)
  882.         
  883.         ifs_file.close()
  884.         return ifs
  885.  
  886.     
  887.     def configure_network(self):
  888.         """Automatically configure the network.
  889.         
  890.         At present, the only thing the user gets to tweak in the UI is the
  891.         hostname. Some other things will be copied from the live filesystem,
  892.         so changes made there will be reflected in the installed system.
  893.         
  894.         Unfortunately, at present we have to duplicate a fair bit of netcfg
  895.         here, because it's hard to drive netcfg in a way that won't try to
  896.         bring interfaces up and down."""
  897.         for path in ('/etc/network/interfaces', '/etc/resolv.conf'):
  898.             if os.path.exists(path):
  899.                 shutil.copy2(path, os.path.join(self.target, path[1:]))
  900.                 continue
  901.         
  902.         
  903.         try:
  904.             hostname = self.db.get('netcfg/get_hostname')
  905.         except debconf.DebconfError:
  906.             hostname = ''
  907.  
  908.         if hostname == '':
  909.             hostname = 'ubuntu'
  910.         
  911.         fp = open(os.path.join(self.target, 'etc/hostname'), 'w')
  912.         print >>fp, hostname
  913.         fp.close()
  914.         hosts = open(os.path.join(self.target, 'etc/hosts'), 'w')
  915.         print >>hosts, '127.0.0.1\tlocalhost'
  916.         print >>hosts, '127.0.1.1\t%s' % hostname
  917.         print >>hosts, textwrap.dedent('\n            # The following lines are desirable for IPv6 capable hosts\n            ::1     ip6-localhost ip6-loopback\n            fe00::0 ip6-localnet\n            ff00::0 ip6-mcastprefix\n            ff02::1 ip6-allnodes\n            ff02::2 ip6-allrouters\n            ff02::3 ip6-allhosts')
  918.         hosts.close()
  919.         SIOCGIFHWADDR = 35111
  920.         ARPHRD_ETHER = 1
  921.         if_names = { }
  922.         sock = socket.socket(socket.SOCK_DGRAM)
  923.         interfaces = self.get_all_interfaces()
  924.         for i in range(len(interfaces)):
  925.             if_names[interfaces[i]] = struct.unpack('H6s', fcntl.ioctl(sock.fileno(), SIOCGIFHWADDR, struct.pack('256s', interfaces[i]))[16:24])
  926.         
  927.         sock.close()
  928.         iftab = open(os.path.join(self.target, 'etc/iftab'), 'w')
  929.         print >>iftab, textwrap.dedent('            # This file assigns persistent names to network interfaces.\n            # See iftab(5) for syntax.\n            ')
  930.         for i in range(len(interfaces)):
  931.             dup = False
  932.             with_arp = False
  933.             if_name = if_names[interfaces[i]]
  934.             if if_name is None or if_name[0] != ARPHRD_ETHER:
  935.                 continue
  936.             
  937.             for j in range(len(interfaces)):
  938.                 if i == j or if_names[interfaces[j]] is None:
  939.                     continue
  940.                 
  941.                 if if_name[1] != if_names[interfaces[j]][1]:
  942.                     continue
  943.                 
  944.                 if if_names[interfaces[j]][0] == ARPHRD_ETHER:
  945.                     dup = True
  946.                     continue
  947.             
  948.             if dup:
  949.                 continue
  950.             
  951.             line = [] + []([ '%02x' % ord(if_name[1][c]) for c in range(6) ])
  952.             line += ' arp %d' % if_name[0]
  953.             print >>iftab, line
  954.         
  955.         iftab.close()
  956.  
  957.     
  958.     def configure_bootloader(self):
  959.         '''configuring and installing boot loader into installed
  960.         hardware system.'''
  961.         misc.ex('mount', '--bind', '/proc', self.target + '/proc')
  962.         misc.ex('mount', '--bind', '/dev', self.target + '/dev')
  963.         
  964.         try:
  965.             grubinstaller = grubinstaller
  966.             import ubiquity.components
  967.             dbfilter = grubinstaller.GrubInstaller(None)
  968.             ret = dbfilter.run_command(auto_process = True)
  969.             if ret != 0:
  970.                 raise InstallStepError('GrubInstaller failed with code %d' % ret)
  971.         except ImportError:
  972.             
  973.             try:
  974.                 yabootinstaller = yabootinstaller
  975.                 import ubiquity.components
  976.                 dbfilter = yabootinstaller.YabootInstaller(None)
  977.                 ret = dbfilter.run_command(auto_process = True)
  978.                 if ret != 0:
  979.                     raise InstallStepError('YabootInstaller failed with code %d' % ret)
  980.             except ImportError:
  981.                 raise InstallStepError('No bootloader installer found')
  982.             except:
  983.                 None<EXCEPTION MATCH>ImportError
  984.             
  985.  
  986.             None<EXCEPTION MATCH>ImportError
  987.  
  988.         misc.ex('umount', '-f', self.target + '/proc')
  989.         misc.ex('umount', '-f', self.target + '/dev')
  990.  
  991.     
  992.     def do_remove(self, to_remove, recursive = False):
  993.         self.db.progress('START', 0, 5, 'ubiquity/install/title')
  994.         self.db.progress('INFO', 'ubiquity/install/find_removables')
  995.         fetchprogress = DebconfFetchProgress(self.db, 'ubiquity/install/title', 'ubiquity/install/apt_indices_starting', 'ubiquity/install/apt_indices')
  996.         cache = Cache()
  997.         while True:
  998.             removed = set()
  999.             for pkg in to_remove:
  1000.                 cachedpkg = self.get_cache_pkg(cache, pkg)
  1001.                 if cachedpkg is not None and cachedpkg.isInstalled:
  1002.                     apt_error = False
  1003.                     
  1004.                     try:
  1005.                         cachedpkg.markDelete(autoFix = False, purge = True)
  1006.                     except SystemError:
  1007.                         apt_error = True
  1008.  
  1009.                     if apt_error:
  1010.                         cachedpkg.markKeep()
  1011.                     elif cache._depcache.BrokenCount > 0:
  1012.                         brokenpkgs = set()
  1013.                         for pkg in cache.keys():
  1014.                             if cache._depcache.IsInstBroken(cache._cache[pkg]):
  1015.                                 brokenpkgs.add(pkg)
  1016.                                 continue
  1017.                         
  1018.                         broken_removed = set()
  1019.                         if recursive or brokenpkgs <= to_remove:
  1020.                             for pkg in brokenpkgs:
  1021.                                 cachedpkg2 = self.get_cache_pkg(cache, pkg)
  1022.                                 if cachedpkg2 is not None:
  1023.                                     broken_removed.add(pkg)
  1024.                                     
  1025.                                     try:
  1026.                                         cachedpkg2.markDelete(autoFix = False, purge = True)
  1027.                                     except SystemError:
  1028.                                         apt_error = True
  1029.                                         break
  1030.                                     except:
  1031.                                         None<EXCEPTION MATCH>SystemError
  1032.                                     
  1033.  
  1034.                                 None<EXCEPTION MATCH>SystemError
  1035.                             
  1036.                         
  1037.                         if apt_error or cache._depcache.BrokenCount > 0:
  1038.                             for pkg in broken_removed:
  1039.                                 self.get_cache_pkg(cache, pkg).markKeep()
  1040.                             
  1041.                             cachedpkg.markKeep()
  1042.                         else:
  1043.                             removed.add(pkg)
  1044.                             removed |= broken_removed
  1045.                     else:
  1046.                         removed.add(pkg)
  1047.                     if not cache._depcache.BrokenCount == 0:
  1048.                         raise AssertionError
  1049.                     continue
  1050.             
  1051.             if len(removed) == 0:
  1052.                 break
  1053.             
  1054.             to_remove -= removed
  1055.         self.db.progress('SET', 1)
  1056.         self.db.progress('REGION', 1, 5)
  1057.         fetchprogress = DebconfFetchProgress(self.db, 'ubiquity/install/title', None, 'ubiquity/install/fetch_remove')
  1058.         installprogress = DebconfInstallProgress(self.db, 'ubiquity/install/title', 'ubiquity/install/apt_info', 'ubiquity/install/apt_error_remove')
  1059.         
  1060.         try:
  1061.             if not cache.commit(fetchprogress, installprogress):
  1062.                 fetchprogress.stop()
  1063.                 installprogress.finishUpdate()
  1064.                 self.db.progress('STOP')
  1065.                 return None
  1066.         except SystemError:
  1067.             e = None
  1068.             print >>sys.stderr, e
  1069.             sys.stderr.flush()
  1070.             self.db.progress('STOP')
  1071.             raise 
  1072.  
  1073.         self.db.progress('SET', 5)
  1074.         self.db.progress('STOP')
  1075.  
  1076.     
  1077.     def remove_unusable_kernels(self):
  1078.         '''Remove unusable kernels; keeping them may cause us to be unable
  1079.         to boot.'''
  1080.         self.db.progress('START', 0, 6, 'ubiquity/install/title')
  1081.         self.db.progress('INFO', 'ubiquity/install/find_removables')
  1082.         dbfilter = check_kernels.CheckKernels(None)
  1083.         dbfilter.run_command(auto_process = True)
  1084.         remove_kernels = set()
  1085.         if os.path.exists('/var/lib/ubiquity/remove-kernels'):
  1086.             for line in open('/var/lib/ubiquity/remove-kernels'):
  1087.                 remove_kernels.add(line.strip())
  1088.             
  1089.         
  1090.         if len(remove_kernels) == 0:
  1091.             self.db.progress('STOP')
  1092.             return None
  1093.         
  1094.         self.db.progress('SET', 1)
  1095.         self.db.progress('REGION', 1, 5)
  1096.         
  1097.         try:
  1098.             self.do_remove(remove_kernels, recursive = True)
  1099.         except:
  1100.             self.db.progress('STOP')
  1101.             raise 
  1102.  
  1103.         self.db.progress('SET', 5)
  1104.         bootdir = os.path.join(self.target, 'boot')
  1105.         if self.db.get('base-installer/kernel/linux/link_in_boot') == 'true':
  1106.             linkdir = bootdir
  1107.             linkprefix = ''
  1108.         else:
  1109.             linkdir = self.target
  1110.             linkprefix = 'boot'
  1111.         re_symlink = re.compile('vmlinu[xz]|initrd.img$')
  1112.         for entry in os.listdir(linkdir):
  1113.             if re_symlink.match(entry) is not None:
  1114.                 filename = os.path.join(linkdir, entry)
  1115.                 if os.path.islink(filename):
  1116.                     os.unlink(filename)
  1117.                 
  1118.             os.path.islink(filename)
  1119.         
  1120.         if linkdir != self.target:
  1121.             for entry in os.listdir(self.target):
  1122.                 if re_symlink.match(entry) is not None:
  1123.                     filename = os.path.join(self.target, entry)
  1124.                     if os.path.islink(filename):
  1125.                         os.unlink(filename)
  1126.                     
  1127.                 os.path.islink(filename)
  1128.             
  1129.         
  1130.         re_image = re.compile('(vmlinu[xz]|initrd.img)-')
  1131.         for entry in os.listdir(bootdir):
  1132.             match = re_image.match(entry)
  1133.             if match is not None:
  1134.                 imagetype = match.group(1)
  1135.                 linksrc = os.path.join(linkprefix, entry)
  1136.                 linkdst = os.path.join(linkdir, imagetype)
  1137.                 if os.path.exists(linkdst):
  1138.                     if entry.endswith('-' + self.kernel_version):
  1139.                         os.unlink(linkdst)
  1140.                     
  1141.                 
  1142.                 os.symlink(linksrc, linkdst)
  1143.                 continue
  1144.         
  1145.         self.db.progress('SET', 6)
  1146.         self.db.progress('STOP')
  1147.  
  1148.     
  1149.     def remove_extras(self):
  1150.         '''Try to remove packages that are needed on the live CD but not on
  1151.         the installed system.'''
  1152.         if os.path.exists('/cdrom/casper/filesystem.manifest-desktop') and os.path.exists('/cdrom/casper/filesystem.manifest'):
  1153.             desktop_packages = set()
  1154.             for line in open('/cdrom/casper/filesystem.manifest-desktop'):
  1155.                 if line.strip() != '' and not line.startswith('#'):
  1156.                     desktop_packages.add(line.split()[0])
  1157.                     continue
  1158.             
  1159.             live_packages = set()
  1160.             for line in open('/cdrom/casper/filesystem.manifest'):
  1161.                 if line.strip() != '' and not line.startswith('#'):
  1162.                     live_packages.add(line.split()[0])
  1163.                     continue
  1164.             
  1165.             difference = live_packages - desktop_packages
  1166.         else:
  1167.             difference = set()
  1168.         apt_installed = set()
  1169.         if os.path.exists('/var/lib/ubiquity/apt-installed'):
  1170.             for line in open('/var/lib/ubiquity/apt-installed'):
  1171.                 apt_installed.add(line.strip())
  1172.             
  1173.         
  1174.         difference -= apt_installed
  1175.         if len(difference) == 0:
  1176.             return None
  1177.         
  1178.         self.do_remove(difference)
  1179.  
  1180.     
  1181.     def cleanup(self):
  1182.         '''Miscellaneous cleanup tasks.'''
  1183.         os.unlink(os.path.join(self.target, 'etc/apt/apt.conf.d/00IgnoreTimeConflict'))
  1184.  
  1185.     
  1186.     def chrex(self, *args):
  1187.         '''executes commands on chroot system (provided by *args).'''
  1188.         msg = ''
  1189.         for word in args:
  1190.             msg += str(word) + ' '
  1191.         
  1192.         if not misc.ex('chroot', self.target, *args):
  1193.             misc.pre_log('error', 'chroot ' + msg)
  1194.             return False
  1195.         
  1196.         return True
  1197.  
  1198.     
  1199.     def copy_debconf(self, package):
  1200.         '''setting debconf database into installed system.'''
  1201.         targetdb = os.path.join(self.target, 'var/cache/debconf/config.dat')
  1202.         misc.ex('debconf-copydb', 'configdb', 'targetdb', '-p', '^%s/' % package, '--config=Name:targetdb', '--config=Driver:File', '--config=Filename:' + targetdb)
  1203.  
  1204.     
  1205.     def set_debconf(self, question, value):
  1206.         dccomm = subprocess.Popen([
  1207.             'chroot',
  1208.             self.target,
  1209.             'debconf-communicate',
  1210.             '-fnoninteractive',
  1211.             'ubiquity'], stdin = subprocess.PIPE, stdout = subprocess.PIPE, close_fds = True)
  1212.         dc = debconf.Debconf(read = dccomm.stdout, write = dccomm.stdin)
  1213.         dc.set(question, value)
  1214.         dc.fset(question, 'seen', 'true')
  1215.         dccomm.stdin.close()
  1216.         dccomm.wait()
  1217.  
  1218.     
  1219.     def reconfigure(self, package):
  1220.         '''executes a dpkg-reconfigure into installed system to each
  1221.         package which provided by args.'''
  1222.         self.chrex('dpkg-reconfigure', '-fnoninteractive', package)
  1223.  
  1224.  
  1225. if __name__ == '__main__':
  1226.     if not os.path.exists('/var/lib/ubiquity'):
  1227.         os.makedirs('/var/lib/ubiquity')
  1228.     
  1229.     if os.path.exists('/var/lib/ubiquity/install.trace'):
  1230.         os.unlink('/var/lib/ubiquity/install.trace')
  1231.     
  1232.     install = Install()
  1233.     sys.excepthook = install.excepthook
  1234.     install.run()
  1235.     sys.exit(0)
  1236.  
  1237.