From 97b111acee9f613289950ce6904c010e86aa3fb8 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Savard Date: Thu, 16 Apr 2009 20:29:54 +0000 Subject: Merge of jc and origin jc Merge branch 'jc' of ssh://bobthebuilder.mine.nu:8080/home/git into jc Conflicts: source/external/source/sugar-toolkit/src/sugar/activity/activity.py source/external/source/sugar-toolkit/src/sugar/tutorius/Makefile.am source/external/source/sugar-toolkit/src/sugar/tutorius/bundler.py source/external/source/sugar-toolkit/src/sugar/tutorius/tests/run-tests.py --- (limited to 'src') diff --git a/src/sugar/activity/activity.py b/src/sugar/activity/activity.py index 3e2d3d4..a5188fd 100644 --- a/src/sugar/activity/activity.py +++ b/src/sugar/activity/activity.py @@ -77,7 +77,6 @@ from sugar.datastore import datastore from sugar.session import XSMPClient from sugar import wm from sugar.tutorius.services import ObjectStore -from sugar.tutorius.tutoserialize import TutoSerializer _ = lambda msg: gettext.dgettext('sugar-toolkit', msg) @@ -129,14 +128,15 @@ class ActivityToolbar(gtk.Toolbar): self.tutorials.combo.connect('changed', self.__tutorial_changed_cb) # Get tutorial list by file logging.debug("************************************ before creating serialize") - serialize = TutoSerializer() - logging.debug("************************************ before calling load_tuto_list()") - - #tutorials = self._activity.get_tutorials() - if getattr(self._activity,"_tutorials",None) is None: - tutorials = serialize.load_tuto_list() +## serialize = TutoSerializer() +## logging.debug("************************************ before calling load_tuto_list()") +## +## #tutorials = self._activity.get_tutorials() +## if getattr(self._activity,"_tutorials",None) is None: +## tutorials = serialize.load_tuto_list() self._current_tutorial = None + tutorials = None if tutorials: for key, tutorial in tutorials.items(): # self.tutorials.combo.append_item(key, _(tutorial.name)) diff --git a/src/sugar/tutorius/Makefile.am b/src/sugar/tutorius/Makefile.am index a74b796..8805314 100644 --- a/src/sugar/tutorius/Makefile.am +++ b/src/sugar/tutorius/Makefile.am @@ -9,5 +9,5 @@ sugar_PYTHON = \ services.py \ overlayer.py \ editor.py \ - linear_creator.py \ - bundler.py + linear_creator.py\ + bundler.py diff --git a/src/sugar/tutorius/bundler.py b/src/sugar/tutorius/bundler.py index 6f61779..8712c86 100644 --- a/src/sugar/tutorius/bundler.py +++ b/src/sugar/tutorius/bundler.py @@ -22,26 +22,38 @@ This module contains all the data handling class of Tutorius import logging import os +import shutil import uuid import xml.dom.minidom -import xml.dom.ext from sugar.tutorius import gtkutils, overlayer from sugar.tutorius.core import Tutorial, State, FiniteStateMachine -import sugar.tutorius.actions -import sugar.tutorius.filters +from sugar.tutorius.actions import DialogMessage, OnceWrapper, BubbleMessage +from sugar.tutorius.filters import GtkWidgetEventFilter, TimerEvent from ConfigParser import SafeConfigParser -def __get_store_root(): - return os.path.join(os.getenv("SUGAR_PREFIX"),"share","tutorius","data") -def __get_bundle_root(): - return os.path.join(os.getenv("SUGAR_BUNDLE_PATH"),"data","tutorius","data") +def _get_store_root(): + path = os.path.join(os.getenv("SUGAR_PREFIX"),"share","tutorius","data") + if os.path.exists(path): + return path + else: + os.makedirs(path) + return path +def _get_bundle_root(): + path = os.path.join(os.getenv("SUGAR_BUNDLE_PATH"),"data","tutorius","data") + if os.path.exists(path): + return path + else: + os.makedirs(path) + return path INI_ACTIVITY_SECTION = "RELATED_ACTIVITIES" INI_METADATA_SECTION = "GENERAL_METADATA" INI_GUID_PROPERTY = "GUID" INI_NAME_PROPERTY = "NAME" INI_XML_FSM_PROPERTY = "FSM_FILENAME" +INI_FILENAME = "meta.ini" +TUTORIAL_FILENAME = "tutorial.xml" class TutorialStore: @@ -51,8 +63,8 @@ class TutorialStore: given activity. """ - store_root = __get_store_root() - bundle_root = __get_bundle_root() + store_root = _get_store_root() + bundle_root = _get_bundle_root() logging.debug("*********** Path of store_root : " + store_root) @@ -119,96 +131,57 @@ class XMLSerializer(Serializer): used in the tutorials to/from a .xml file. Inherit from Serializer """ - def create_state_dict_node(self, state_dict, doc): - """ - Create and return a xml Node from a State dictionnary. - """ - statesList = doc.createElement("States") - for state_name, state in state_dict.items(): - stateNode = statesList.appendChild("State") - stateNode.setAttribute("State:Name", state_name) - stateNode = stateNode.appendChild(create_action_list_node(state.action_list, doc)) - stateNode = stateNode.appendChild(create_event_filters_node(state.event_filters, doc)) - return statesList - def create_action_list_node(self, action_list, doc): - """ - Create and return a xml Node from a Action list. - """ - actionsList = doc.createElement("Actions") - for action in action_list: - actionNode = actionsList.appendChild("Action") - if type(action) is DialogMessage: - actionNode.setAttribute("Action:Class", type(action)) - actionNode.setAttribute("Action:Message", action.message) - actionNode.setAttribute("Action:Position", action.position) - elif type(action) is BubbleMessage: - actionNode.setAttribute("Action:Class", str(type(action))) - actionNode.setAttribute("Action:Message", action.message) - actionNode.setAttribute("Action:Position", action.position) - actionNode.setAttribute("Action:Tail_pos", action.tail_pos) - # TODO : elif for each type of action - elif type(action) is WidgetIdentifyAction: - actionNode.setAttribute("Action:Class", str(type(action))) - # TODO - elif type(action) is ChainAction: - # TODO - actionNode.setAttribute("Action:Class", str(type(action))) - elif type(action) is DisableWidgetAction: - # TODO - actionNode.setAttribute("Action:Class", str(type(action))) - elif type(action) is TypeTextAction: - # TODO - actionNode.setAttribute("Action:Class", str(type(action))) - elif type(action) is ClickAction: - # TODO - actionNode.setAttribute("Action:Class", str(type(action))) - - return actionsList - def create_event_filters_node(self, event_filters, doc): - """ - Create and return a xml Node from a event filters. - """ - eventFiltersList = doc.createElement("EventFiltersList") - for event_f in event_filters: - eventFilterNode = eventFiltersList.appendChild("EventFilter") - # TODO : elif for each type of event filters - if type(event_f) is TimerEvent: - # TODO - eventFilterNode.setAttribute("EventFilter:Class", str(type(event_f))) - elif type(event_f) is GtkWidgetEventFilter: - # TODO - eventFilterNode.setAttribute("EventFilter:Class", str(type(event_f))) - elif type(event_f) is GtkWidgetTypeFilter: - # TODO - eventFilterNode.setAttribute("EventFilter:Class", str(type(event_f))) - - return eventFiltersList - - def save_fsm(self, fsm, xml_filename, path): + def save_fsm(self,fsm, xml_filename, path): """ Save fsm to disk, in the xml file specified by "xml_filename", in the "path" folder. If the specified file dont exist, it will be created. """ - doc = xml.dom.minidom.Document() - fsm_element = doc.createElement("FSM") - doc.appendChild(fsm_element) - fsm_element.setAttribute("fsm:Name", fsm.name) - fsm_element.setAttribute("fsm:StartStateName", fsm.start_state_name) - fsm_element = fsm_element.appendChild(create_state_dict_node(fsm.state_dict, doc)) - fsm_element = fsm_element.appendChild(create_action_list_node(fsm.action_list, doc)) + fsm_xml = xml.dom.minidom.Document() + fsm_element = doc.createElementNS("http://tutorius.org", "FSM") + fsm_xml.appendChild(fsm_element) + fsm_element.setAttributeNS("http://tutorius.org", "fsm:Name", fsm.name) + fsm_element.setAttributeNS("http://tutorius.org", "fsm:StartStateName", fsm.start_state_name) + #fsm_element = doc. + tutorial_element.appendChild(fsm_element) - file_object = open(path + "/" + xml_filename, "w") - xml.dom.ext.PrettyPrint(doc, file_object) - file_object.close() - + +## logging.debug("************ found .tml file : " + file_name) +## key_line = linecache.getline(path + file_name, 1) +## key_line = key_line.split("\n")[0] +## fileKey = key_line.split("--KEY::")[1] +## logging.debug("************ fileKey = " + fileKey) +## if key == fileKey: +## logging.debug("************ Key : " + key + \ +## " = fileKey : " + fileKey) +## tml = file(path + file_name, "r") +## str = tml.read() +## pick = str.split("--PICKLE::")[1] +## +## fsm = pickle.loads(pick) +## tuto = {key:Tutorial(key,fsm)} +## +## return tuto + def load_fsm(self, guid): """ Load fsm from xml file who .ini file guid match argument guid. """ - +## +## path = os.getenv("SUGAR_ACTIVITY_ROOT") + "/data/" +## # Create /data/ folder if no exists +## if not os.path.exists(path): +## os.mkdir(path) +## logging.debug("************* Creating data folder") +## +## # Save the dictionnary to .tml file +## tutoSave = file(path + filename + ".tml", 'w') +## str = "--KEY::" + key + "\n--NAME::" + name + "\n--PICKLE::" + \ +## pickle.dumps(fsm,0) +## tutoSave.write(str) +## tutoSave.close() class TutorialBundler: @@ -217,74 +190,81 @@ class TutorialBundler: editor. """ + + def __init__(self,generated_guid = None): """ - TODO. Tutorial_bundler constructor. If a GUID is given in the parameter, the Tutorial_bundler object will be associated with it. If no GUID is given, a new GUID will be generated, """ - self.Guid = generated_guid or uuid.uuid1() #Look for the file in the path if a uid is supplied if generated_guid: #General store - store_path = os.path.join(__get_store_root(), generated_guid, INI_FILENAME) + store_path = os.path.join(_get_store_root(), generated_guid, INI_FILENAME) if os.path.isfile(store_path): self.Path = os.path.dirname(store_path) else: #Bundle store - bundle_path = os.path.join(__get_bundle_root(), generated_guid, INI_FILENAME) + bundle_path = os.path.join(_get_bundle_root(), generated_guid, INI_FILENAME) if os.path.isfile(bundle_path): self.Path = os.path.dirname(bundle_path) else: raise IOError(2,"Unable to locate metadata file for guid '%s'" % generated_guid) else: - #Create the folder, any failure will go through to the caller for now - store_path = os.path.join(__get_store_root(), generated_guid) - os.mkdir(store_path) - self.Path = store_path - - - def __SetGuid(self, value): - self.__guid = value - - def __GetGuid(self): - return self.__guid - - def __DelGuid(self): - del self.__guid - - def __SetPath(self, value): - self.__path = value - - def __GetPath(self): - return self.__path - - def __DelPath(self): - del self.__path - - Guid = property(fget=__SetGuid, - fset=__GetGuid, - fdel=__DelGuid, - doc="The guid associated with the Tutoria_Bundler") - - Path = property(fget=__SetPath, - fset=__GetPath, - fdel=__DelPath, - doc="The path associated with the Tutoria_Bundler") - + #Create the folder, any failure will go through to the caller for now + store_path = os.path.join(_get_store_root(), generated_guid) + os.mkdir(store_path) + self.Path = store_path + + def __SetGuid(self, value): + self.__guid = value + + def __GetGuid(self): + return self.__guid + + def __DelGuid(self): + del self.__guid + + def __SetPath(self, value): + self.__path = value + + def __GetPath(self): + return self.__path + + def __DelPath(self): + del self.__path - def write_metadata_file(self, data): + Guid = property(fget=__SetGuid, + fset=__GetGuid, + fdel=__DelGuid, + doc="The guid associated with the Tutorial_Bundler") + + Path = property(fget=__SetPath, + fset=__GetPath, + fdel=__DelPath, + doc="The path associated with the Tutorial_Bundler") + + + def write_metadata_file(self, tutorial): """ - Write metadata to a property file. If a GUID is provided, TutorialBundler - will try to find and overwrite the existing property file who contain the - given GUID, and will raise an exception if it cannot find it. + Write metadata to the property file. + @param tutorial Tutorial for which to write metadata """ - NotImplementedError - + #Create the Config Object and populate it + cfg = SafeConfigParser() + cfg.add_section(INI_METADATA_SECTION) + cfg.set(INI_METADATA_SECTION, INI_GUID_PROPERTY, self.Guid) + cfg.set(INI_METADATA_SECTION, INI_NAME_PROPERTY, tutorial.name) + cfg.set(INI_METADATA_SECTION, INI_XML_FSM_PROPERTY, TUTORIAL_FILENAME) + + + #Write the ini file + cfg.write( file( os.path.join(self.Path, INI_FILENAME) ) ) + def get_tutorial_path(self): """ Return the path of the .ini file associated with the guiven guid set in @@ -292,8 +272,8 @@ class TutorialBundler: more than one path, the store_root is given priority. """ - store_root = __get_store_root() - bundle_root = __get_bundle_root() + store_root = _get_store_root() + bundle_root = _get_bundle_root() config = SafeConfigParser() path = None @@ -357,8 +337,30 @@ class TutorialBundler: save_fsm(fsm, xml_filename, store_root) - def add_resources(self, typename, file): + def add_ressource(self, file): """ - Add ressources to metadata. + Add ressource in tutorial directory + return True if success or if file is already in tutorial directory + return False if file is a directory """ - raise NotImplementedError("add_resources not implemented") + path = get_tutorial_path() + if os.path.isfile(file): + filename = os.split(file) + target = os.path.join(path,filename) + if os.path.samefile(file,target): + return True + else: + try: + shutil.copy(file,target) + return True + #This error is raised if the file already exists + except shutil.Error, err: + logger.debug(err) + return True + #General error for copying file + except IOError,err: + logger.debug(err) + return False + else: + logger.debug("file is a directory :"+file) + return False diff --git a/src/sugar/tutorius/tests/bundlertests.py b/src/sugar/tutorius/tests/bundlertests.py new file mode 100644 index 0000000..8da2310 --- /dev/null +++ b/src/sugar/tutorius/tests/bundlertests.py @@ -0,0 +1,65 @@ +# Copyright (C) 2009, Tutorius.org +# Copyright (C) 2009, Charles-Etienne Carriere +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +""" +Bundler tests + +This module contains all the tests for the storage mecanisms for tutorials +This mean testing savins and loading tutorial, .ini file management and +adding ressources to tutorial +""" + +import unittest +import os +import uuid + +from sugar.tutorius import bundler + +class TutorialBundlerTests(unittest.TestCase): + + def setUp(self): + + #generate a test GUID + self.test_guid = uuid.uuid1() + self.guid_path = os.path.join(bundler._get_store_root(),str(self.test_guid)) + os.mkdir(self.guid_path) + + self.ini_file = os.path.join(self.guid_path, "meta.ini") + + f = open(self.ini_file,'w') + f.write("[GENERAL_METADATA]") + f.write(os.linesep) + f.write("GUID:") + f.write(str(self.test_guid)) + f.close() + + def tearDown(self): + os.remove(self.ini_file) + os.rmdir(self.guid_path) + + def test_add_ressource(self): + bund = bundler.TutorialBundler(self.test_guid) + + temp_file = open("test.txt",'w') + temp_file.write('test') + temp_file.close() + + bund.add_resource("test.txt") + + assert os.path.exists(os.path.join(self.guid_path,"test.txt")), "add_ressource did not create the file" + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/src/sugar/tutorius/tests/run-tests.py b/src/sugar/tutorius/tests/run-tests.py index 2e200c2..0c9219b 100755 --- a/src/sugar/tutorius/tests/run-tests.py +++ b/src/sugar/tutorius/tests/run-tests.py @@ -10,17 +10,10 @@ sys.path.insert(0, ) FULL_PATH = os.path.join(INSTALL_PATH,"sugar/tutorius") -SUBDIRS = ["uam"] GLOB_PATH = os.path.join(FULL_PATH,"*.py") import unittest from glob import glob -def report_files(): - ret = glob(GLOB_PATH) - for dir in SUBDIRS: - ret += glob(os.path.join(FULL_PATH,dir,"*.py")) - return ret - import sys if __name__=='__main__': if "--coverage" in sys.argv: @@ -35,38 +28,25 @@ if __name__=='__main__': import gtkutilstests import overlaytests import linear_creatortests - import actiontests - import uamtests - import filterstests - import constraintstests - import propertiestests - + import serializertests + suite = unittest.TestSuite() suite.addTests(unittest.findTestCases(coretests)) suite.addTests(unittest.findTestCases(servicestests)) suite.addTests(unittest.findTestCases(gtkutilstests)) suite.addTests(unittest.findTestCases(overlaytests)) suite.addTests(unittest.findTestCases(linear_creatortests)) - suite.addTests(unittest.findTestCases(actiontests)) - suite.addTests(unittest.findTestCases(uamtests)) - suite.addTests(unittest.findTestCases(filterstests)) - suite.addTests(unittest.findTestCases(constraintstests)) - suite.addTests(unittest.findTestCases(propertiestests)) - + suite.addTests(unittest.findTestCases(serializertests)) runner = unittest.TextTestRunner() runner.run(suite) coverage.stop() - coverage.report(report_files()) + coverage.report(glob(GLOB_PATH)) coverage.erase() else: from coretests import * from servicestests import * from gtkutilstests import * from overlaytests import * - from actiontests import * - from linear_creatortests import * - from uamtests import * - from filterstests import * unittest.main() -- cgit v0.9.1