Molecule:

- started to implement handlers


git-svn-id: http://svn.sabayonlinux.org/projects/molecule/trunk@2980 cd1c1023-2f26-0410-ae45-c471fc1f0318
This commit is contained in:
lxnay
2009-02-02 14:46:34 +00:00
parent 1cda81a93d
commit 1b99b9dbae
8 changed files with 351 additions and 9 deletions
+1
View File
@@ -19,6 +19,7 @@
# source_chroot: /var/tmp/catalyst/tmp/stage1-amd64-2006.0
# Destination chroot directory, where files are pushed to before creating the squashfs image
# NOTE: data will be stored inside an auto-generated subdir
# destination_chroot: /var/tmp/catalyst/tmp/stage1-amd64-2006.0/default/livecd-stage2-amd64-2006.0
# Merge directory with destination chroot
+9 -4
View File
@@ -19,12 +19,17 @@
import sys
sys.path.insert(0,'molecule/')
import molecule.settings
import molecule.cmdline
from molecule.handlers import Runner
molecule_data = molecule.cmdline.parse()
if not molecule_data:
molecule_data, molecule_data_order = molecule.cmdline.parse()
if not molecule_data_order:
molecule.cmdline.print_help()
raise SystemExit(1)
print "valid",molecule_data
for el in molecule_data_order:
my = Runner(el, molecule_data.get(el))
rc = my.run()
my.kill()
if rc != 0: raise SystemExit(rc)
raise SystemExit(0)
+3 -1
View File
@@ -18,4 +18,6 @@
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
import molecule.settings
Config = molecule.settings.Configuration()
import molecule.output
Config = molecule.settings.Configuration()
Output = molecule.output.Output()
+7 -3
View File
@@ -26,26 +26,30 @@ from molecule import Config
from molecule.settings import SpecParser
def parse():
args_to_remove = ["--nocolor"]
data = {}
myargs = sys.argv[1:]
if "--help" in myargs:
return data
return data, []
if "--nocolor" in myargs:
molecule.output.nocolor()
for arg in args_to_remove:
if arg in myargs: myargs.remove(arg)
data_order = []
for el in myargs:
if os.path.isfile(el) and os.access(el,os.R_OK):
obj = SpecParser(el)
el_data = obj.parse()
del obj
if el_data: data[el] = el_data
return data
if el_data:
data_order.append(el)
data[el] = el_data
return data, data_order
def print_help():
help_data = [
+3
View File
@@ -32,4 +32,7 @@ class EnvironmentError(MoleculeException):
"""Environment error, self explanatory"""
class SpecFileError(MoleculeException):
"""Error inside spec file"""
class NotImplementedError(MoleculeException):
"""Error inside spec file"""
+146
View File
@@ -0,0 +1,146 @@
#!/usr/bin/python -O
# -*- coding: iso-8859-1 -*-
# Molecule Disc Image builder for Sabayon Linux
# Copyright (C) 2009 Fabio Erculiani
#
# 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.
from __future__ import with_statement
import os
from molecule.i18n import _
from molecule.output import red, brown, blue, green, purple, darkgreen, darkred, bold, darkblue, readtext
from molecule.exception import EnvironmentError, NotImplementedError
# This is an interface that has to be reimplemented in order to make it doing something useful
class GenericHandlerInterface:
def __init__(self, spec_path, metadata):
from molecule import Output, Config
self.Output = Output
self.Config = Config
self.spec_path = spec_path
self.metadata = metadata
self.spec_name = os.path.basename(self.spec_path)
def pre_run(self):
raise NotImplementedError("NotImplementedError: this needs to be reimplemented")
def run(self):
raise NotImplementedError("NotImplementedError: this needs to be reimplemented")
def post_run(self):
raise NotImplementedError("NotImplementedError: this needs to be reimplemented")
def kill(self):
raise NotImplementedError("NotImplementedError: this needs to be reimplemented")
class MirrorHandler(GenericHandlerInterface):
def __init__(self, *args, **kwargs):
GenericHandlerInterface.__init__(self, *args, **kwargs)
def pre_run(self):
self.Output.updateProgress( "[%s|%s] %s" % (blue("MirrorHandler"),darkred(self.spec_name),_("executing pre_run"),))
return 0
def post_run(self):
self.Output.updateProgress( "[%s|%s] %s" % (blue("MirrorHandler"),darkred(self.spec_name),_("executing post_run"),))
return 0
def kill(self):
self.Output.updateProgress( "[%s|%s] %s" % (blue("MirrorHandler"),darkred(self.spec_name),_("executing kill"),))
return 0
def run(self):
self.Output.updateProgress( "[%s|%s] %s" % (blue("MirrorHandler"),darkred(self.spec_name),_("executing run"),))
# running the syncer
source_dir = self.metadata['source_chroot']
dest_dir = os.path.join(self.metadata['destination_chroot'],os.path.basename(source_dir))
if not os.path.isdir(dest_dir):
os.makedirs(dest_dir,0755)
# FIXME: complete this
return 0
class ChrootHandler(GenericHandlerInterface):
def __init__(self, *args, **kwargs):
GenericHandlerInterface.__init__(self, *args, **kwargs)
def pre_run(self):
self.Output.updateProgress( "[%s|%s] %s" % (blue("ChrootHandler"),darkred(self.spec_name),_("executing pre_run"),))
return 0
def post_run(self):
self.Output.updateProgress( "[%s|%s] %s" % (blue("ChrootHandler"),darkred(self.spec_name),_("executing post_run"),))
return 0
def kill(self):
self.Output.updateProgress( "[%s|%s] %s" % (blue("ChrootHandler"),darkred(self.spec_name),_("executing kill"),))
return 0
def run(self):
self.Output.updateProgress( "[%s|%s] %s" % (blue("ChrootHandler"),darkred(self.spec_name),_("executing run"),))
return 0
class Runner(GenericHandlerInterface):
def __init__(self, spec_path, metadata):
GenericHandlerInterface.__init__(self, spec_path, metadata)
self.execution_order = [MirrorHandler,ChrootHandler]
def pre_run(self):
return 0
def post_run(self):
return 0
def kill(self):
return 0
def run(self):
self.pre_run()
count = 0
maxcount = len(self.execution_order)
self.Output.updateProgress( "[%s|%s] %s" % (darkgreen("Runner"),brown(self.spec_name),_("preparing execution"),), count = (count,maxcount,))
for myclass in self.execution_order:
count += 1
self.Output.updateProgress( "[%s|%s] %s %s" % (darkgreen("Runner"),brown(self.spec_name),_("executing"),str(myclass),), count = (count,maxcount,))
my = myclass(self.spec_path, self.metadata)
rc = 0
while 1:
# pre-run
rc = my.pre_run()
if rc: break
# run
rc = my.run()
if rc: break
# post-run
rc = my.post_run()
if rc: break
break
my.kill()
if rc: return rc
self.post_run()
self.Output.updateProgress( "[%s|%s] %s!" % (darkgreen("Runner"),brown(self.spec_name),_("All done"),))
return 0
+180
View File
@@ -400,3 +400,183 @@ def my_raw_input(txt = ''):
response += y
flush_stdouterr()
return response
class Output:
# @input text: text to write
# @input back: write on on the same line?
# @input importance:
# values: 0,1,2,3 (latter is a blocker - popup menu on a GUI env)
# used to specify information importance, 0<important<2
# @input type:
# values: "info, warning, error"
#
# @input count:
# if you need to print an incremental count ( 100/250...101/251..)
# just pass count = [first integer,second integer] or even a tuple!
# @input header:
# text header (decoration?), that's it
#
# @input footer:
# text footer (decoration?), that's it
#
# @input percent:
# if percent is True: count will be treating as a percentual count[0]/count[1]*100
#
# feel free to reimplement this
def updateProgress(self, text, header = "", footer = "", back = False, importance = 0, type = "info", count = [], percent = False):
flush_stdouterr()
myfunc = print_info
if type == "warning":
myfunc = print_warning
elif type == "error":
myfunc = print_error
count_str = ""
if count:
if len(count) > 1:
if percent:
count_str = " ("+str(round((float(count[0])/count[1])*100,1))+"%) "
else:
count_str = " (%s/%s) " % (red(str(count[0])),blue(str(count[1])),)
if importance == 0:
myfunc(header+count_str+text+footer, back = back, flush = False)
elif importance == 1:
myfunc(header+count_str+text+footer, back = back, flush = False)
elif importance in (2,3):
myfunc(header+count_str+text+footer, back = back, flush = False)
flush_stdouterr()
# @input question: question to do
#
# @input importance:
# values: 0,1,2 (latter is a blocker - popup menu on a GUI env)
# used to specify information importance, 0<important<2
#
# @input responses:
# list of options whose users can choose between
#
# feel free to reimplement this
def askQuestion(self, question, importance = 0, responses = ["Yes","No"]):
colours = [green, red, blue, darkgreen, darkred, darkblue, brown, purple]
colours += colours[:]
if len(responses) > len(colours):
import exceptionTools
raise exceptionTools.IncorrectParameter("IncorrectParameter: %s = %s" % (_("maximum responses length"),len(colours),))
try:
print darkgreen(question),
except UnicodeEncodeError:
print darkgreen(question.encode('utf-8')),
flush_stdouterr()
try:
while True:
xtermTitle(_("Entropy got a question for you"))
flush_stdouterr()
response = my_raw_input("["+"/".join([colours[i](responses[i]) for i in range(len(responses))])+"] ")
flush_stdouterr()
for key in responses:
# An empty response will match the first value in responses.
if response.upper() == key[:len(response)].upper():
xtermTitleReset()
return key
'''
try:
print "%s '%s'" % (_("I cannot understand"),response,),
except UnicodeEncodeError:
print "%s '%s'" % (_("I cannot understand"),response.encode('utf-8'),),
'''
flush_stdouterr()
except (EOFError, KeyboardInterrupt):
print "%s." % (_("Interrupted"),)
xtermTitleReset()
raise SystemExit(100)
xtermTitleReset()
flush_stdouterr()
'''
@ title: title of the input box
@ input_parameters: [
('identifier 1','input text 1',input_verification_callback,False),
('password','Password',input_verification_callback,True),
('item_3',('checkbox','Checkbox option (boolean request) - please choose',),input_verification_callback,True),
('item_4',('combo',('Select your favorite option',['option 1', 'option 2', 'option 3']),),input_verification_callback,True)
]
@ cancel_button: show cancel button ?
@ output: dictionary as follows:
{'identifier 1': result, 'identifier 2': result}
'''
def inputBox(self, title, input_parameters, cancel_button = True):
results = {}
if title:
try:
print title
except UnicodeEncodeError:
print title.encode('utf-8')
flush_stdouterr()
def option_chooser(option_data):
mydict = {}
counter = 1
option_text, option_list = option_data
self.updateProgress(option_text)
for item in option_list:
mydict[counter] = item
txt = "[%s] %s" % (darkgreen(str(counter)), blue(item),)
self.updateProgress(txt)
counter += 1
while 1:
myresult = readtext("%s:" % (_('Selected number'),)).decode('utf-8')
try:
myresult = int(myresult)
except ValueError:
continue
selected = mydict.get(myresult)
if selected != None:
return myresult, selected
for identifier, input_text, callback, password in input_parameters:
while 1:
try:
if isinstance(input_text,tuple):
myresult = False
input_type, data = input_text
if input_type == "checkbox":
answer = self.askQuestion(data)
if answer == "Yes": myresult = True
if input_type == "combo":
myresult = option_chooser(data)
else:
myresult = readtext(input_text+":", password = password).decode('utf-8')
except (KeyboardInterrupt,EOFError,):
if not cancel_button: # use with care
continue
return None
valid = callback(myresult)
if valid:
results[identifier] = myresult
break
return results
# useful for reimplementation
# in this wait you can send a signal to a widget (total progress bar?)
def cycleDone(self):
return
def setTitle(self, title):
xtermTitle(title)
def setTotalCycles(self, total):
return
def outputInstanceTest(self):
return
def nocolor(self):
nocolor()
def notitles(self):
notitles()
+2 -1
View File
@@ -96,13 +96,14 @@ class Configuration(Dictionary):
'version': "0.1",
'chroot_compressor': "mksquashfs",
'iso_builder': "mkisofs",
'mirror_syncer': "rsync",
'iso_builder_builtin_args': ["-J","-R","-l","-no-emul-boot","-boot-load-size","4","-udf","-boot-info-table"],
}
self._settings.clear()
self._settings.update(settings)
self._settings.update(mysettings)
paths_to_check = ["chroot_compressor","iso_builder"]
paths_to_check = ["chroot_compressor","iso_builder","mirror_syncer"]
for key in paths_to_check:
molecule.utils.valid_exec_check(self.get(key))