buenas! doncs be, resulta que, aprofitant que estic aprenent python, he passat a python uns scripts que tenia per a manegar un repositori de configuracions pel nucli que tinc que per a que serveix? doncs per a tenir guardats en un directori una serie de fitxers amb diferents configuracions del kernel (un per cada maquina - per si com jo, es compilen kernels per a diverses maquines des d'una mateixa maquina, la mes potent - , per cada versio - especialitzada o no - del kernel, etc) ara per ara, permet: - reconfigurar una configuracio existent - netejar els fonts del nucli - compilar el nucli, generant un .deb amb el nucli i d'altres amb els diferents moduls externs que s'utilitzin - configurar una nova versio, ja sigui des de zero o utilitzant una versio antiga (un fitxer ja existent); si s'utilitza una versio anterior, es recomana no utilitzar la opcio -c, ja que aixi, al fer un 'make oldconfig' al nucli, nomes es pregunta el que ha aparescut de nou en la nova versio del nucli coses que el codi permet pero no he fet per mandra: - traduccio dels missatges a diversos idiomes -> substituint la tipica funcio _() per una que tingui en compte els llenguatges (gettext) - utilitzacio d'altres interficies d'usuari que no siguin text pla (ncurses, gtk, ...) -> classe UI (python te suport tant per ncurses com gtk, entre d'altres) altres coses interessants que es poden afegir amb poc esforc,: - us de CVS o Subversion al canviar un fitxer de configuracio, per tal de tenir-los controlats al llarg del temps - generacio al fer un 'kpkger make' d'altres paquets (.deb amb els fonts, paquet amb capc,aleres, etc) per utilitzar-lo, n'hi ha prou amb posar-lo en algun directori dins el path (/usr/local/bin); es pot utilitzar com a usuari no privilegiat, pero aleshores es recomana utilitzar 'sudo' com a <root_command> (que es la opcio per defecte) i per a aixo fa falta que l'usuari amb el que s'executa kpkger estigui al fitxer sudoers per a poder fer sudo <elquesigui> (si s'executa com a root, no hi ha absolutament cap problema) be doncs, no es que sigui a prova de bombes (si podeu, qualsevol millora o error, feu-me'l saber), pero a mi em funciona ;) apa! PD: perdoneu pel crossposting, pero suposo (desitjo) que us pot ser util -- "And it's much the same thing with knowledge, for whenever you learn something new, the whole world becomes that much richer." -- The Princess of Pure Reason, as told by Norton Juster in The Phantom Tollbooth
#!/usr/bin/env python
# --------------------------------------------
# kpkger - Maintain make-kpkg configurations
# --------------------------------------------
# Module: standalone program
# File: kpkger
# Author: Lluis Vilanova <xscript@gmx.net>
# CVS Id: $Id: $
#
# Copyright (C) 2005 Lluis Vilanova <xscript@gmx.net> {{{
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# }}}
#
"""
Tool to maintain make-kpkg with various configurations
"""
# -----------
# Imports {{{
import sys
import os
import time
import getopt
# }}}
# -----------
# -----------
# Classes {{{
# Option class {{{
class Option:
def __init__(self, name, params, default, desc):
self.name = name
self.default = default
self.value = default
self.params = params
self.desc = desc
def help_short(self):
str = "[-%s " % self.name
if self.params != None:
str += self.params
str += "]"
return str
def help_long(self):
if self.params != None:
str = "-%-2s %s" % (self.name, self.params)
else:
str = "-%s" % self.name
str = " %-20s %s" % (str, self.desc)
if self.default != None:
str += " (default: %s)" % self.default
str += "\n"
return str
# }}}
# Options class {{{
class Options:
def __init__(self):
self.ids = {}
self.options = {}
def __getitem__(self, key):
return self.ids[key].value
def __setitem__(self, key, val):
self.ids[key] = val
self.options[val.name] = val
def help_short(self):
str = ""
for opt in self.options.values():
str += opt.help_short()+" "
return str
def help_long(self):
str = ""
for opt in self.options.values():
str += "%s" % opt.help_long()
return str
def parse(self, args):
soptions = ""
for name, opt in self.options.items():
if opt.params != None:
soptions += "%s:" % name
else:
soptions += name
opts, args = getopt.getopt(args, soptions)
for opt, val in opts:
# delete the initial '-' flag indicator
opt = opt[1:]
self.options[opt].value = val
return args
# }}}
# Conf class {{{
class Conf:
ui = None
self_name = None
cmd_name = None
opts = []
usage_extra = ""
kern_dir = os.path.abspath(os.curdir)
conf_dir = "/usr/src/configs"
# }}}
# Output class {{{
class UI:
def msg_err(self, text):
pass
def msg_info(self, text):
pass
def msg_ask(self, title, text):
pass
def msg_choose(self, title, text, list, default):
pass
# }}}
# OutputText class {{{
class UIText(UI):
def msg_err(self, text):
print text
sys.exit(1)
def msg_info(self, text):
print text
def msg_ask(self, title, text, default=True):
if default:
print text, _("[Y/n] "),
defaults = [_("Y"), _("y"), ""]
else:
print text, _("[y/N] "),
defaults = [_("Y"), _("y")]
sys.stdout.flush()
res = sys.stdin.readline()
if res[:-1] in defaults:
return True
else:
return False
def msg_choose(self, title, text, list, default):
print text, "\n"
for obj in list:
print obj
print "\n[%s] " % default,
sys.stdout.flush()
res = sys.stdin.readline()[:-1]
while res != "" and not res in list:
print _("'%s' is not a valid value, please try again") % res
print text, "\n"
for obj in list:
print obj
print "\n[%s] " % default,
sys.stdout.flush()
res = sys.stdin.readline()[:-1]
if res == "":
return default
else:
return res
# }}}
# }}}
# -----------
# -------------
# Functions {{{
def _(text):
return text
# checks & gets {{{
def check_dir(path, ask=False):
if not os.access(path, os.F_OK):
if ask:
if Conf.ui.msg_ask(_("Directory '%s' does not exist") % path,
_("Directory '%s' does not exist, do you want to create it?") % path):
os.mkdir(path, 0775)
else:
Conf.ui.msg_err(_("Directory '%s' does not exist") % path)
else:
Conf.ui.msg_err(_("Directory '%s' does not exist") % path)
if not os.path.isdir(path):
Conf.ui.msg_err(_("'%s' is not a directory!") % path)
if not os.access(path, os.R_OK):
Conf.ui.msg_err(_("Can't access directory '%s' for reading") % path)
def check_file(path, kernel=False):
if kernel:
kernelstr = _("\nIs '%s' really a kernel source directory?") % \
os.path.dirname(path)
else:
kernelstr = ""
if not os.access(path, os.F_OK):
Conf.ui.msg_err(_("File '%s' does not exist%s") % (path, kernelstr))
if not os.path.isfile(path):
Conf.ui.msg_err(_("'%s' is not a file!%s") % (path, kernelstr))
if not os.access(path, os.R_OK):
Conf.ui.msg_err(_("Can't access file '%s' for reading%s") %
(path, kernelstr))
def get_fields(path, fields):
filed = file(path)
line = filed.readline()
while line != "":
lfields = [ text.strip() for text in line.split("=") ]
if lfields[0] in fields.keys():
fields[lfields[0]] = lfields[1]
line = filed.readline()
filed.close()
for afield, avalue in fields.items():
if avalue == None:
Conf.ui.msg_err(_("Couldn't find '%s' field on '%s'\n\
Is '%s' really a kernel source directory?") %
(afield, path, os.path.dirname(path)))
def get_kernelrelease(path):
fields = {
"VERSION" : None,
"PATCHLEVEL" : None,
"SUBLEVEL" : None,
"EXTRAVERSION" : None,
}
get_fields(path, fields)
return "%s.%s.%s%s" % (fields["VERSION"], fields["PATCHLEVEL"],
fields["SUBLEVEL"], fields["EXTRAVERSION"])
def get_file_list(path, tag, ver, suffix):
list = os.listdir(path)
if list == None:
list = []
res = []
# list *-$ver.$suffix
for obj in list:
if obj.endswith("%s.%s" % (ver, suffix)):
res.append(obj)
# list $tag-*.$suffix
for obj in list:
if obj.startswith(tag) and obj.endswith(".%s" % suffix):
res.append(obj)
# give precedence to older configurations for the same tag, as the last one
# will be the default
return res
def check_conf(path, tag, ver, suffix, type, oldtag=None, oldver=None):
basename = "%s-%s.%s" % (tag, ver, suffix)
filename = os.path.join(path, basename)
if os.access(filename, os.F_OK):
if os.path.isfile(filename):
if os.access(filename, os.R_OK):
Conf.ui.msg_info(_("File for %s found: %s") % (type, basename))
return filename
else:
Conf.ui.msg_err(_("Can't access %s file '%s' for reading") %
(type, filename))
else:
Conf.ui.msg_err(_("'%s' is not a file") % filename)
else:
list = get_file_list(path, tag, ver, suffix)
if len(list) == 0:
if Conf.ui.msg_ask(_("Previous %s file") % type,
_("Can't find any previous %s file for %s\n\
Do you want me to create an empty one?") % (type, basename)):
Conf.ui.msg_info(_("Created a %s file: %s") % (type, basename))
file(filename, "w").close()
return filename
else:
Conf.ui.msg_err(_("Couldn't find a %s file") % type)
else:
if Conf.ui.msg_ask(_("Previous %s file") % type,
_("Can't find any previous %s file for %s\n\
Do you want to use an old one?") % (type, basename)):
oldbasename = Conf.ui.msg_choose(_("Previous %s file") % type,
_("Please choose one of these:"), list, list[-1])
oldfilename = os.path.join(path, oldbasename)
if Conf.ui.msg_ask(_("Previous %s file") % type,
_("Do you want to delete the old %s file '%s'?") % (type,
oldbasename), False):
os.rename(oldfilename, filename)
else:
execute("cp %s %s" % (oldfilename, filename))
return filename
else:
if Conf.ui.msg_ask(_("Previous %s file") % type,
_("Do you want me to create an empty one?")):
Conf.ui.msg_info(_("Created a %s file: %s") % (type, basename))
file(filename, "w").close()
return filename
else:
Conf.ui.msg_err(_("Couldn't find a %s file") % type)
def get_file_contents(filename):
filed = file(filename)
line = filed.readline().strip()
filed.close()
return line
def check_confs(path, tag, kernelrelease):
Conf.conf_file = check_conf(path, tag, kernelrelease, "conf", _("configuration"))
Conf.conf_patches = get_file_contents(check_conf(path, tag, kernelrelease,
"patch", _("patches")))
if Conf.conf_patches != "":
Conf.conf_patches = "--added-patches %s" % Conf.conf_patches
Conf.conf_modules = get_file_contents(check_conf(path, tag, kernelrelease,
"mods", _("modules")))
if Conf.conf_modules != "":
Conf.conf_modules = "--added-modules %s" % Conf.conf_modules
def get_date_str():
year, month, day, null, null, null, null, null, null = time.localtime()
return "%d%02d%02d" % (year, month, day)
def check_changelog(filename, tag):
if not os.access(filename, os.F_OK):
return
filed = file(filename)
line = filed.readline()
if line.startswith("kernel-source-%s" % Conf.kernelrelease) and \
not "%s.%s" % (tag, get_date_str()) in line:
if Conf.ui.msg_ask(_("Previosly configured"),
_("This kernel has been previosly configured.\n\
It is recommended that you clean it before proceeding.\n\
Do you want to continue?")):
rep = line[line.index("(")+1:line.index(")")]
line = line.replace(rep, "%s.%s" % (tag, get_date_str()))
newfiled = file("%s.new" % filename, "w")
lines = [line]
lines.extend(filed.readlines())
newfiled.writelines(lines)
os.rename("%s.new" % filename, filename)
newfiled.close()
else:
sys.exit(0)
filed.close()
# }}}
def execute(cmd, fail=True):
res = os.system(cmd)
if res != 0 and fail:
Conf.ui.msg_err(_("%s: %s") % (cmd, os.strerror(res)))
return res
def usage_command():
opts_short = ""
opts_long = ""
for opts in Conf.opts:
opts_short += opts.help_short()
opts_long += opts.help_long()
str = _("\nUsage: %s %s %s%s") % (Conf.self_name, Conf.cmd_name,
opts_short, Conf.usage_extra)
str += _("\n\n Options:\n%s") % opts_long
Conf.ui.msg_err(str)
def opts_parse(args):
for opt in Conf.opts:
args = opt.parse(args)
return args
# config command {{{
def command_config(args, opts_common):
opts_config = Options()
opts_config["conf_method"] = Option("c", _("<conf_method>"), "oldconfig",
_("Configration method used by kernel's make"))
Conf.opts.append(opts_config)
Conf.usage_extra = "<tag> [<revision>]"
args = opts_parse(args)
if len(args) < 1:
usage_command()
# if args[0] == "-c":
# if len(args) < 3:
# usage_config()
# Conf.conf_method = args[1]
# del args[:2]
tag = args[0]
del args[0]
if len(args) > 0:
if len(args) > 1:
usage_command()
revision = args[0]
else:
revision = ""
check_confs(Conf.conf_dir, tag, Conf.kernelrelease)
# do the real work
execute("cp -f %s %s/.config" % (Conf.conf_file, Conf.kern_dir))
krevision = "%s.%s" % (tag, get_date_str())
if revision != "":
krevision = "%s.%s" % (krevision, revision)
check_changelog(os.path.join(Conf.kern_dir, "debian/changelog"), tag)
if os.geteuid() != 0:
cmd_pre = "fakeroot"
cmd_rootcmd = "--rootcmd %s" % opts_common["rootcmd"]
else:
cmd_pre = ""
cmd_rootcmd = ""
cmd = "%s make-kpkg %s --revision %s %s %s --config %s configure" \
% (cmd_pre, cmd_rootcmd, krevision, Conf.conf_modules,
Conf.conf_patches, opts_config["conf_method"])
Conf.ui.msg_info("executing: %s" % cmd)
execute(cmd)
res = execute("diff %s/.config %s > /dev/null" % (Conf.kern_dir, Conf.conf_file),
False)
if res != 0:
Conf.ui.msg_info(_("Saving the new configuration"))
execute("cp -f %s %s.old" % (Conf.conf_file, Conf.conf_file))
execute("cp -f %s/.config %s" % (Conf.kern_dir, Conf.conf_file))
# }}}
# make command {{{
def command_make(args, opts_common):
Conf.usage_extra = "<tag> [<revision>]"
args = opts_parse(args)
if len(args) < 1:
usage_command()
tag = args[0]
del args[0]
if len(args) > 0:
if len(args) > 1:
usage_command()
revision = args[0]
else:
revision = ""
check_confs(Conf.conf_dir, tag, Conf.kernelrelease)
# do the real work
execute("cp -f %s %s/.config" % (Conf.conf_file, Conf.kern_dir))
krevision = "%s.%s" % (tag, get_date_str())
if revision != "":
krevision = "%s.%s" % (krevision, revision)
check_changelog(os.path.join(Conf.kern_dir, "debian/changelog"), tag)
if Conf.conf_modules != "":
modules = "modules-image"
else:
modules = ""
if os.geteuid() != 0:
cmd_pre = "fakeroot"
cmd_rootcmd = "--rootcmd %s" % opts_common["rootcmd"]
else:
cmd_pre = ""
cmd_rootcmd = ""
cmd = "%s make-kpkg %s --revision %s %s %s kernel-image %s" \
% (cmd_pre, cmd_rootcmd, krevision, Conf.conf_modules,
Conf.conf_patches, modules)
Conf.ui.msg_info("executing: %s" % cmd)
execute(cmd)
# }}}
# clean command {{{
def command_clean(args, opts_common):
Conf.usage_extra = "<tag>"
args = opts_parse(args)
if len(args) < 1:
usage_command()
tag = args[0]
del args[0]
if len(args) > 0:
usage_command()
check_confs(Conf.conf_dir, tag, Conf.kernelrelease)
# do the real work
if os.geteuid() != 0:
cmd_pre = "fakeroot"
cmd_rootcmd = "--rootcmd %s" % opts_common["rootcmd"]
else:
cmd_pre = ""
cmd_rootcmd = ""
if Conf.conf_modules != "":
cmd = "%s make-kpkg %s %s %s modules-clean" % \
(cmd_pre, cmd_rootcmd, Conf.conf_patches, Conf.conf_modules)
Conf.ui.msg_info("executing: %s" % cmd)
execute(cmd)
cmd = "%s make-kpkg %s %s %s clean" % \
(cmd_pre, cmd_rootcmd, Conf.conf_patches, Conf.conf_modules)
Conf.ui.msg_info("executing: %s" % cmd)
execute(cmd)
# }}}
commanders = {
"config": command_config,
"make" : command_make,
"clean" : command_clean,
}
# }}}
# -------------
# --------
# MAIN {{{
def main():
opts_common = Options()
opts_common["rootcmd"] = Option("r", _("<root_command>"), "sudo",
_("make-kpkg's 'rootcmd'"))
Conf.opts.append(opts_common)
# default user interface
Conf.ui = UIText()
# get our name
args = sys.argv
Conf.self_name = os.path.basename(args[0])
del args[0]
# check files and directories
check_dir(Conf.conf_dir, True)
check_dir(Conf.kern_dir)
makefile = os.path.join(Conf.kern_dir, "Makefile")
check_file(makefile, True)
Conf.kernelrelease = get_kernelrelease(makefile)
# get command
if len(args) == 0:
Conf.ui.msg_err(_("""
Usage: %s <command> <command_options>
Available commands:
config - configure a kernel
make - make kernel packages
clean - clean kernel
""") % (Conf.self_name))
Conf.cmd_name = args[0]
del args[0]
if Conf.cmd_name in commanders:
commanders[Conf.cmd_name](args, opts_common)
else:
Conf.ui.msg_err(_("Unknown command '%s'") % Conf.cmd_name)
# }}}
# --------
if __name__ == "__main__":
main()
# vim:set ts=3 sw=3 tw=78 foldmethod=marker expandtab:
Attachment:
pgpk_X31r6oeu.pgp
Description: PGP signature