Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/sugar/activity/activity.py14
-rw-r--r--src/sugar/tutorius/Makefile.am4
-rw-r--r--src/sugar/tutorius/bundler.py274
-rw-r--r--src/sugar/tutorius/tests/bundlertests.py65
-rwxr-xr-xsrc/sugar/tutorius/tests/run-tests.py28
5 files changed, 216 insertions, 169 deletions
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 <iso.swiffer@gmail.com>
+#
+# 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()