[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Script per manegar varies configuracions pel kernel



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


Reply to: