众所周知,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的前端开发打基础。路还很长!