system-config-kickstart源码阅读(五)安装方法篇

众所周知,Linux支持n种安装方式,例如光盘,本地硬盘,网络安装如NFS,http或ftp等等,当然全自动的也不能例外,我们先从宏观上来观察其类:

除去每个类里均会有的updateKS()、formToKickstart、applyKickstart()方法之外,实现的方法并不复杂,让我们先分析代码,然后画出流程图,也许就是真的理解了一个程序的局部了,整体把握的能力,不仅是积累的过程,还有自我能力的局限。
代码分析:install.py
import gtk
import gtk.glade
import string     //一定会有文本处理,呵呵,你不喜欢吗?
import kickstartGui
class install:
    def __init__(self, parent_class, xml, store, view, notebook, ksHandler):
        self.xml = xml
        self.parent_class = parent_class
        self.store = store
        self.view = view
        self.notebook = notebook
        self.ks = ksHandler
        self.install_radiobutton = xml.get_widget("install_radiobutton")
        self.upgrade_radiobutton = xml.get_widget("upgrade_radiobutton")
        self.partitioning_frame = xml.get_widget("partitioning_frame")
        self.pkg_selection_frame = xml.get_widget("pkg_selection_frame")
        self.install_option_vbox = xml.get_widget("install_option_vbox")
//供安装方式选择的单选框
        self.cdrom_radiobutton = xml.get_widget("cdrom_radiobutton")
        self.nfs_radiobutton = xml.get_widget("nfs_radiobutton")
        self.ftp_radiobutton = xml.get_widget("ftp_radiobutton")
        self.http_radiobutton = xml.get_widget("http_radiobutton")
        self.hd_radiobutton = xml.get_widget("hd_radiobutton")
//提示用的标签
        self.nfsdir_label = xml.get_widget("nfsdir_label")
        self.nfsserver_label = xml.get_widget("nfsserver_label")
        self.ftpdir_label = xml.get_widget("ftpdir_label")
        self.ftpserver_label = xml.get_widget("ftpserver_label")
        self.ftpuser_label = xml.get_widget("ftpuser_label")
        self.ftppasswd_label = xml.get_widget("ftppasswd_label")
        self.hdpart_label = xml.get_widget("hdpart_label")
        self.hddir_label = xml.get_widget("hddir_label")
        self.httpserver_label = xml.get_widget("httpserver_label")
        self.httpdir_label = xml.get_widget("httpdir_label")
//需要用户输入的entry widget.
        self.nfsdir_entry = xml.get_widget("nfsdir_entry")
        self.nfsserver_entry = xml.get_widget("nfsserver_entry")
        self.ftpdir_entry = xml.get_widget("ftpdir_entry")
        self.ftpserver_entry = xml.get_widget("ftpserver_entry")
        self.ftpuser_entry = xml.get_widget("ftpuser_entry")
        self.ftppasswd_entry = xml.get_widget("ftppasswd_entry")
        self.hdpart_entry = xml.get_widget("hdpart_entry")
        self.hddir_entry = xml.get_widget("hddir_entry")
        self.httpserver_entry = xml.get_widget("httpserver_entry")
        self.httpdir_entry = xml.get_widget("httpdir_entry")
        self.ftpuserpass_checkbutton = xml.get_widget("ftpuserpass_checkbutton")
        self.install_notebook = xml.get_widget("install_notebook") //这是个好东东,多个note,仅显示当前
//信号的定义,以及触发信号后的调用事件函数
        self.install_radiobutton.connect("toggled", self.toggleInstall)
        self.cdrom_radiobutton.connect("toggled", self.setState)
        self.nfs_radiobutton.connect("toggled", self.setState)
        self.ftp_radiobutton.connect("toggled", self.setState)
        self.http_radiobutton.connect("toggled", self.setState)
        self.hd_radiobutton.connect("toggled", self.setState)
        self.ftpuserpass_checkbutton.connect("toggled", self.toggleFtp)
        self.ftpuser_entry.set_sensitive(False)       默认为空
        self.ftppasswd_entry.set_sensitive(False)
    def updateKS(self, ksHandler):
        self.ks = ksHandler
    def toggleFtp (self, args):  //响应ftpuserpass_checkbutton按钮的事件方法
        userpass = self.ftpuserpass_checkbutton.get_active()
        self.ftpuser_entry.set_sensitive(userpass)
        self.ftppasswd_entry.set_sensitive(userpass)
    def toggleInstall (self, args)://响应install_radiobutton按钮的事件方法
        #gray out package selection and partitions if upgrade
        install = self.install_radiobutton.get_active()
        self.parent_class.installTypeChanged(install)
    def setState (self, args):             //方法只能选一种!
        if self.cdrom_radiobutton.get_active():
            self.install_notebook.set_current_page(0)
            return
        elif self.nfs_radiobutton.get_active():
            self.install_notebook.set_current_page(1)
            return
        elif self.ftp_radiobutton.get_active():
            self.install_notebook.set_current_page(2)
            return
        elif self.http_radiobutton.get_active():
            self.install_notebook.set_current_page(3)
            return
        elif self.hd_radiobutton.get_active():
            self.install_notebook.set_current_page(4)
    def formToKickstart(self): //好多if else阿,
        self.ks.upgrade(upgrade=self.upgrade_radiobutton.get_active())
        if self.cdrom_radiobutton.get_active():
            self.ks.method.method = "cdrom"
        elif self.nfs_radiobutton.get_active():
            server = self.nfsserver_entry.get_text()
            dir = self.nfsdir_entry.get_text()
            if server == "":         当将nfs的按钮激活时,在保存或预览时的提示信息。
                self.showDialog(_("Please enter an NFS server."), self.nfsserver_entry)
                return None
            if dir == "":
                self.showDialog(_("Please enter an NFS directory."), self.nfsdir_entry)
                return None
            if server [-1] == "/":
                server = server[:-1]
            self.ks.method.method = "nfs"   //写入到文件时的格式,也就时传入ks类的参数
            self.ks.method.server = server
            self.ks.method.dir = dir
        elif self.ftp_radiobutton.get_active()://当将ftp的按钮激活时,在保存或预览时的提示信息。
            ftpserver = string.strip(self.ftpserver_entry.get_text())
            if ftpserver == "":
                self.showDialog(_("Please enter an FTP server."), self.ftpserver_entry)
                return None
            if ftpserver[:6] == "ftp://":
                ftpserver = ftpserver[6:]
            if ftpserver[-1] == "/":
                ftpserver = ftpserver[:-1]
            if self.ftpdir_entry.get_text() == "":
                self.showDialog(_("Please enter an FTP directory."), self.ftpserver_entry)
                return None
            buf = "ftp://"
            if self.ftpuserpass_checkbutton.get_active():   //必须输入用户名和密码
                if self.ftpuser_entry.get_text() == "":
                    self.showDialog(_("Please enter an FTP user name."), self.ftpuser_entry)
                    return None
                if self.ftppasswd_entry.get_text() == "":
                    self.showDialog(_("Please enter an FTP password."), self.ftpuser_entry)
                    return None
                buf = buf + self.ftpuser_entry.get_text() + ":" + self.ftppasswd_entry.get_text() + "@"           //将用户的输入,联合起来:ftp://用户名:密码@
            buf = buf + ftpserver  //继续联合:ftp://用户名:密码@服务器
            directory = self.ftpdir_entry.get_text()
            if directory[0] == '/':
                buf = buf + directory
            else:
                buf = buf + "/" + directory  //最后形成完整的URL表示法。ftp://用户名:密码@服务器/目录
            self.ks.method.method = "url"  
            self.ks.method.url = buf
        elif self.http_radiobutton.get_active():
            if self.httpserver_entry.get_text() == "":
                self.showDialog(_("Please enter an HTTP server."), self.httpserver_entry)
                return None
            if self.httpdir_entry.get_text() == "":
                self.showDialog(_("Please enter an HTTP server directory."), self.httpdir_entry)
                return None
            loc = string.strip(self.httpserver_entry.get_text())
            if loc[:7] == "http://":
                #strip the "http://" out
                loc = loc[7:]
            if loc [-1] == "/":
                loc = loc[:-1]
            buf = "http://" + loc
            directory = self.httpdir_entry.get_text()
            if directory[0] == '/':
                buf = buf + directory
            else:
                buf = buf + "/" + directory
            self.ks.method.method = "url"
            self.ks.method.url = buf
        elif self.hd_radiobutton.get_active(): //硬盘安装
            if self.hddir_entry.get_text() == "":
                self.showDialog(_("Please enter a hard drive directory."), self.hddir_entry)
                return None
            if self.hdpart_entry.get_text() == "":
                self.showDialog(_("Please enter a hard drive partition."), self.hdpart_entry)
                return None
             //这就是程序的功能缺失了,并没有检查用户的输入。也不清楚是否支持LVM。
            self.ks.method.method = "harddrive"
            self.ks.method.partition = self.hdpart_entry.get_text()
            self.ks.method.dir = self.hddir_entry.get_text()
        return 0
    def showDialog(self, text, widget): //显示一对话框。
            dlg = gtk.MessageDialog(None, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, text)
            dlg.set_title(_("Error"))
            dlg.set_default_size(100, 100)
            dlg.set_position (gtk.WIN_POS_CENTER)
            dlg.set_icon(kickstartGui.iconPixbuf)
            dlg.set_border_width(2)
            dlg.set_modal(True)
            toplevel = self.xml.get_widget("main_window")
            dlg.set_transient_for(toplevel)
            dlg.run()
            dlg.hide()
            iter = self.store.get_iter_first()
            iter = self.store.iter_next(iter)
            self.view.get_selection().select_iter(iter)
            self.notebook.set_current_page(1)
            widget.grab_focus()
            return
    def splitUrl(self, data):         //文本处理开始了。。将URL中的主机地址和目录区分开。
        tokens = string.split(data, "/")
        host = tokens[0]
        dir = tokens[1:]
        dir = string.join(dir, '/')
        dir = "/" + dir
        return host, dir
    def applyKickstart(self): //最终传给主类的信息,一系列的判断。。
        if not self.ks.upgrade.upgrade:   肯定不选升级?是,全新安装激活了,否,升就升呗。
            self.install_radiobutton.set_active(True)   
        else:
            self.upgrade_radiobutton.set_active(True)
        if self.ks.method.method == "cdrom":     选择cd  ?
            self.cdrom_radiobutton.set_active(True) 好,那就cd.
        elif self.ks.method.method == "harddrive":   选择硬盘?
            self.hd_radiobutton.set_active(True)  好阿
            if self.ks.method.partition != "":   用户输入不为空,
                self.hdpart_entry.set_text(self.ks.method.partition)  接收用户的输入,随别什么都可以。
            if self.ks.method.dir != "":
                self.hddir_entry.set_text(self.ks.method.dir)
        elif self.ks.method.method == "nfs":  NFS?
            self.nfs_radiobutton.set_active(True)   
            if self.ks.method.server != "":
                self.nfsserver_entry.set_text(self.ks.method.server)
            if self.ks.method.dir  != "":
                self.nfsdir_entry.set_text(self.ks.method.dir)
        elif self.ks.method.method == "url":   http?ftp?靠,还得判断协议/
            tokens = string.split(self.ks.method.url, "://")   分割。

            protocol = tokens[0]        tokens就是一list,里面只有两项,这是第一项,不是http就是ftp
            data = tokens[1]   url除去协议的那部分。
            if protocol == "ftp":  ftp?
                self.ftp_radiobutton.set_active(True)
                if "@" in data:  一定得包含用户名和密码,即是是访问匿名服务器。
                    self.ftpuserpass_checkbutton.set_active(True)
                    loginData, data = string.split(data, "@")
                    username, password = string.split(loginData, ":")
                    self.ftpuser_entry.set_text(username)  因为要满足ks文件固定的格式,也就是必须迎合anaconda.
                    self.ftppasswd_entry.set_text(password)
                    host, dir = self.splitUrl(data)
                    self.ftpserver_entry.set_text(host)
                    self.ftpdir_entry.set_text(dir)
                else:
                    host, dir = self.splitUrl(data)
            elif protocol == "http":  ftp都分析完了,还说什么http。
                host, dir = self.splitUrl(data)
                self.http_radiobutton.set_active(True)
                self.httpserver_entry.set_text(host)
                self.httpdir_entry.set_text(dir)
5种安装方式也不过如此而已,具体处理string也是很简单的操作,此程序功能的缺失不够意思,竟然不去检查硬盘安装时的输入。
输入越多,需要检查输入的地方就越多。比如网络安装不是主机名的话,IP地址是否合法?这是功能性需要改进的地方。
然而从程序本身我能说些什么了呢?我仅仅感慨GTK notebook widget的好玩?类、方法、参数、调用均是我现在看不到的,基本也没有算法,仅是一个结构上的问题,几乎都是放在UI方面。对于我来说,越是简单的越便于我为更深入的奠定基础,为anaconda,heartbeat3之pacermaker的前端开发打基础。路还很长!