system-config-kickstart源码阅读(三)基本设置篇
适兕
|
1#
适兕 发表于 2008-11-05 15:33
system-config-kickstart源码阅读(三)基本设置篇
这篇我开始基本设置之旅---basic.py解析:
如图所示,basic也仅实现了一个类,7个方法。 还是像前两篇一样,我们来将代码贴出来,然后逐行分析,遇到新的模块或者陌生的语法和调用,我会引导外部分析: import gtk import gtk.glade import gobject import string import os import random //python的随机数生成器模块,比如需要一从1到100的随机数,则random.randint(1,100). import crypt //验证unix密码的函数,只有一种可能那就是crypt.crypt(word, salt) import getopt //命令行构造 from rhpl import keyboard_models import rhpl.keyboard as keyboard //rhpl的关于识别系统键盘的库函数 from hardwareLists import langDict //识别系统语言的类,将会详细分析其代码。 import kickstartGui //上篇分析过的,毕竟有些东西是要显示在主要的GUI上的。 import sys from pykickstart.constants import * ## ## I18N ## import gettext gtk.glade.bindtextdomain("system-config-kickstart") _ = lambda x: gettext.ldgettext("system-config-kickstart", x) sys.path.append("/usr/share/system-config-date") //追加另外一个设置日期的工具的PYTHONPATH. class basic: //定义basic类 def __init__(self, parent_class, xml, notebook, ksHandler): self.parent_class = parent_class self.notebook = notebook self.ks = ksHandler self.xml = xml //以下一段为从glade文件获得gtk相应的widget. self.lang_combo = xml.get_widget("lang_combo") self.keyboard_combo = xml.get_widget("keyboard_combo") self.timezone_combo = xml.get_widget("timezone_combo") self.utc_check_button = xml.get_widget("utc_check_button") self.root_passwd_entry = xml.get_widget("root_passwd_entry") self.root_passwd_confirm_entry = xml.get_widget("root_passwd_confirm_entry") self.reboot_checkbutton = xml.get_widget("reboot_checkbutton") self.text_install_checkbutton = xml.get_widget("text_install_checkbutton") self.ks.bootloader(md5pass="", password="") self.interactive_checkbutton = xml.get_widget("interactive_checkbutton") self.encrypt_root_pw_checkbutton = xml.get_widget("encrypt_root_pw_checkbutton") self.lang_support_list = xml.get_widget("lang_support_list") self.platform_combo = xml.get_widget("platform_combo") self.platform_list = [_("x86, AMD64, or Intel EM64T"), _("Intel Itanium"), _("IBM iSeries"), _("IBM pSeries"), _("IBM zSeries/s390")] self.platform_combo.set_popdown_strings(self.platform_list) self.platform_combo.entry.connect("changed", self.platformChanged)//自定义,不是从glade获得,系统所支持的架构。 self.key_checkbutton = xml.get_widget("key_checkbutton") self.key_entry = xml.get_widget("key_entry") self.key_checkbutton.connect("toggled", self.keyChanged)//去找keychanged这个方法吧! self.langDict = langDict //获得系统支持的语言,以python字典形式存储。详见后面。 # set a default platform if not self.ks.platform: self.ks.platform = "x86, AMD64, or Intel EM64T" #populate language combo self.lang_list = self.langDict.keys() self.lang_list.sort() self.lang_combo.set_popdown_strings(self.lang_list) #set default to English self.lang_combo.list.select_item(self.lang_list.index('English (USA)')) #populate keyboard combo, add keyboards here self.keyboard_dict = keyboard_models.KeyboardModels().get_models() keys = self.keyboard_dict.keys() keyboard_list = [] for item in keys: keyboard_list.append(self.keyboard_dict[item][0]) keyboard_list.sort() self.keyboard_combo.set_popdown_strings(keyboard_list) #set default to English kbd = keyboard.Keyboard() kbd.read() currentKeymap = kbd.get() #set keyboard to current keymap try: self.keyboard_combo.entry.set_text(self.keyboard_dict[currentKeymap][0]) except: self.keyboard_combo.entry.set_text(self.keyboard_dict["us"][0]) #populate time zone combo import zonetab //来自system-config-date的类,获取/usr/share/zoneinfo/zone.tab文件内容,此将会在以后对文本处理方面来分析。 zt = zonetab.ZoneTab() self.timezone_list = [ x.tz for x in zt.getEntries() ] //将大洲/国家提取出来。 self.timezone_list.sort() //排序 try: select = self.timezone_list.index("America/New_York") //index,呵呵,狗日的america. except: select = 0 self.timezone_combo.set_popdown_strings(self.timezone_list) //下拉列表框 self.timezone_combo.list.select_item(select) def updateKS(self, ksHandler): //更新ks临时 self.ks = ksHandler def formToKickstart(self, doInstall): //获得信息 self.ks.lang(lang=self.languageLookup(self.lang_combo.entry.get_text())) //语言 keys = self.keyboard_dict.keys() //键盘 keys.sort() for item in keys: if self.keyboard_dict[item][0] == self.keyboard_combo.entry.get_text(): self.ks.keyboard(keyboard=item) break self.ks.timezone(timezone=self.timezone_combo.entry.get_text(), isUtc=self.utc_check_button.get_active()) //以下的密码设置应该注意一下,很多地方都会用到。 //首先判断两次输入的明文是否匹配。不匹配则弹出对话框,并再次输入。(再保存文件时会提示!也就是说在applykickstart时才会调用此方法。) if self.root_passwd_entry.get_text() != self.root_passwd_confirm_entry.get_text(): dlg = gtk.MessageDialog(None, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("Root passwords do not match.")) 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() self.notebook.set_current_page(0)//切还到当前 self.root_passwd_entry.set_text("") //清空 self.root_passwd_confirm_entry.set_text("") //清空 self.root_passwd_entry.grab_focus() //获得光标 return None pure = self.root_passwd_entry.get_text() //注意了,加密出没! if pure != "": if self.encrypt_root_pw_checkbutton.get_active() == True: salt = "$1$" saltLen = 8 if not pure.startswith(salt): for i in range(saltLen): salt = salt + random.choice (string.letters + string.digits + './') self.passwd = crypt.crypt (pure, salt) //类似unix的shadow加密。 temp = unicode (self.passwd, 'iso-8859-1') //编码!! self.ks.rootpw(isCrypted=True, password=temp) else: self.ks.rootpw(isCrypted=True, password=pure) else: self.passwd = self.root_passwd_entry.get_text() self.ks.rootpw(isCrypted=False, password=self.passwd) //大不了不加密就是了。 self.ks.platform = self.platform_combo.entry.get_text() 获取平台列表 if self.reboot_checkbutton.get_active(): self.ks.reboot(action=KS_REBOOT) else: self.ks.reboot(action=KS_WAIT) if self.text_install_checkbutton.get_active(): self.ks.displaymode(displayMode=DISPLAY_MODE_TEXT) else: self.ks.displaymode(displayMode=DISPLAY_MODE_GRAPHICAL) self.ks.interactive(interactive=self.interactive_checkbutton.get_active()) if self.key_checkbutton.get_active(): if self.key_entry.get_text() == "": self.ks.key(key=KS_INSTKEY_SKIP) else: self.ks.key(key=self.key_entry.get_text()) else: self.ks.key(key="") return 0 def languageLookup(self, args): //语言获取 return self.langDict [args] def platformChanged(self, entry): //平台 platform = entry.get_text() if platform: self.parent_class.platformTypeChanged(entry.get_text()) def keyChanged(self, args): self.key_entry.set_sensitive(self.key_checkbutton.get_active()) def applyKickstart(self): //一切都OK?我要保存了阿!!!!!!! if self.ks.platform in self.platform_list: self.platform_combo.entry.set_text(self.ks.platform) if self.ks.lang.lang.find (".") != -1: ksLang = self.ks.lang.lang.split(".")[0] else: ksLang = self.ks.lang.lang for lang in self.langDict.keys(): if self.langDict[lang] == ksLang: self.lang_combo.list.select_item(self.lang_list.index(lang)) if self.ks.keyboard.keyboard != "": self.keyboard_combo.entry.set_text(self.keyboard_dict[self.ks.keyboard.keyboard][0]) if self.ks.timezone.timezone != "": self.timezone_combo.list.select_item(self.timezone_list.index(self.ks.timezone.timezone)) self.reboot_checkbutton.set_active(self.ks.reboot.action == KS_REBOOT) if self.ks.displaymode.displayMode == DISPLAY_MODE_TEXT: self.text_install_checkbutton.set_active(True) if self.ks.interactive.interactive == True: self.interactive_checkbutton.set_active(True) if self.ks.rootpw.password != "": self.root_passwd_entry.set_text(self.ks.rootpw.password) self.root_passwd_confirm_entry.set_text(self.ks.rootpw.password) self.encrypt_root_pw_checkbutton.set_active(self.ks.rootpw.isCrypted) if self.ks.key.key == "": self.key_checkbutton.set_active(False) self.key_entry.set_text("") elif self.ks.key.key == KS_INSTKEY_SKIP: self.key_checkbutton.set_active(True) self.key_entry.set_text("") else: self.key_checkbutton.set_active(True) self.key_entry.set_text(self.ks.key.key) 文章到此,就开始有了疑惑,不就是这些吗?有什么大不了的?但是,喜欢往里专的人都清楚和明白,键盘是怎么被读取到的?时区了呢?加密的过程是什么?语言列表是如何出现的?以上均是一个import就解决了的问题,那么我们该怎么往下走了呢? 一个小小软件,错综复杂到如此地步,真是小看了它!解决问题是程序员的使命,而代码就是解决问题的实现,解决问题是负载的,代码应该是清晰的,但逻辑上应该是复杂的! 还好,就快完了,其实脚本语言的最大的使命之一就是文本处理!!文本能够熟练的处理好了,也就可以成为一名合格的系统管理员了!至于高深的算法、优秀的数据结构那是很遥远的东西,与现在的无关,将来也许会有! 来看代码吧!废话真多! //删除了注释。 import string //仅仅是一个string就够了?string已经很强大了! #pull list of language from system-config-languages langDict = {} //定义一字典 lines = open("/usr/share/system-config-language/locale-list", "r").readlines() //逐行读取指定文件 for line in lines: tokens = string.split(line) //将行中的单词按空格、tab、换行符等分割,存储到list中。 if '.' in tokens[0]: //如果行中的第一个单词里有“点”时 #Chop encoding off so we can compare to self.installedLangs langBase = string.split(tokens[0], '.') //用.将此单词分割,存储到列表。 langBase = langBase[0] //相当于赋值 elif '@' in tokens[0]: //如果行中的第一个单词里有@时 langBase = string.split(tokens[0], '@')//用@将此单词分割,存储到列表。 langBase = langBase[0] else: langBase = tokens[0] //什么都没有,就是没有了! name = "" for token in tokens[3:]: //将行中的第四个词抽取 name = name + " " + token //组成新的名称 name = string.strip(name) //将刚组成的新的名称再按空格、tab、换行符等分割。 langDict[name] = langBase //放到langDict中存储。 我以文件/usr/share/system-config-language/locale-list中的中国那一行为例说明: zh_CN.UTF-8 utf8 lat0-sun16 Chinese (P.R. of China) - 中文(简体) 这是原文,经过此程序的过滤后,输出为: langBase 是zh_CN,name是C h i n e s e. 顺便说一句,关于时区的抽取和语言这个差不了多少,此处我分析了一个例子,贴在此处: import re,string fn = '/usr/share/zoneinfo/zone.tab' def readZoneTab(): f = open(fn, 'r') comment = re.compile("^#") coordre = re.compile("[\+-]") while 1: line = f.readline() if not line: break if comment.search(line): continue fields = string.split(line, '\t') if len(fields) 3: comments = string.strip(fields[3]) else: comments = None f.close() if __name__ == "__main__": readZoneTab() 还用到了正则表达式模块了,呵呵,这是没有几年功夫搞不定的东西。。。。。 好,此篇点到为止,功能篇将继续,自己期待以下自己的时间! |