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:
@@ -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
@@ -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)
|
||||
@@ -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
@@ -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 = [
|
||||
|
||||
@@ -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"""
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user