[PATCH] Init: Added new file Process.py

Javier Fernandez (via Code Review) gerrit at gerrit.libreoffice.org
Mon Mar 25 03:46:27 PDT 2013


Hi,

I have submitted a patch for review:

    https://gerrit.libreoffice.org/3001

To pull it, you can do:

    git pull ssh://gerrit.libreoffice.org:29418/core refs/changes/01/3001/1

Init: Added new file Process.py

Change-Id: I09a49ec08b89f6fbae27a60d5f9208bea7ba8cf8
---
A wizards/com/sun/star/wizards/web/Process.py
1 file changed, 594 insertions(+), 0 deletions(-)



diff --git a/wizards/com/sun/star/wizards/web/Process.py b/wizards/com/sun/star/wizards/web/Process.py
new file mode 100644
index 0000000..1516cad
--- /dev/null
+++ b/wizards/com/sun/star/wizards/web/Process.py
@@ -0,0 +1,594 @@
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This file incorporates work covered by the following license notice:
+#
+#   Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements. See the NOTICE file distributed
+#   with this work for additional information regarding copyright
+#   ownership. The ASF licenses this file to you under the Apache
+#   License, Version 2.0 (the "License"); you may not use this file
+#   except in compliance with the License. You may obtain a copy of
+#   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+import traceback
+import importlib
+
+from .WebWizardConst import *
+from ..common.UCB import UCB
+from ..common.FileAccess import FileAccess
+from ..ui.event.Task import Task
+from .ProcessErrors import ProcessErrors
+from .ExtensionVerifier import ExtensionVerifier
+from .ErrorHandler import ErrorHandler
+from .data.CGContent import CGContent
+from .data.CGDocument import CGDocument
+from .data.CGExporter import CGExporter
+from .data.CGLayout import CGLayout
+from .data.CGPublish import CGPublish
+from .data.CGSettings import CGSettings
+#from .export.Exporter import Exporter
+#from .export.AbstractExporter import AbstractExporter
+#from .export.CopyExporter import CopyExporter
+
+from com.sun.star.io import IOException
+from com.sun.star.uno import SecurityException
+
+# This class is used to process a CGSession object
+# and generate a site. </br>
+# it does the following: <br/>
+# 1. create a temporary directory.<br/>
+# 2. export documents to the temporary directory.<br/>
+# 3. generate the TOC page, includes copying images from the
+# web wizard work directory and other layout files.<br/>
+# 4. publish, or copy, from the temporary directory to
+# different destinations.<br/>
+# 5. delete the temporary directory.<br/>
+# <br/>
+# to follow up the status/errors it uses a TaskListener object,
+# and an ErrorHandler. <br/>
+# in practice, the TaskListener is the status dialog,
+# and the Errorhandler does the interaction with the user,
+# if something goes wrong.<br/>
+# Note that this class takes it in count that
+# the given session object is prepared for it -
+# all preparations are done in WWD_Events.finishWizard methods.
+# <br/>
+# <br/>
+#
+# note on error handling: <br/>
+# on "catch" clauses I tries to decide whether the
+# exception is fatal or not. For fatal exception an error message
+# is displayed (or rather: the errorHandler is being called...)
+# and a false is returned.
+# In less-fatal errors, the errorHandler "should decide" which means,
+# the user is given the option to "OK" or to "Cancel" and depending
+# on that interaction I cary on.
+class Process(ProcessErrors):
+
+    TASKS_PER_DOC = 5
+    TASKS_PER_XSL = 2
+    TASKS_PER_PUBLISH = 2
+    TASKS_IN_PREPARE = 1
+    TASKS_IN_EXPORT = 2
+    TASKS_IN_GENERATE = 2
+    TASKS_IN_PUBLISH = 2
+    TASKS_IN_FINISHUP = 1
+    settings = None
+    xmsf = None
+    errorHandler = None
+    tempDir = None
+    fileAccess = None
+    ucb = None
+    myTask = None
+    #This is a cache for exporters, so I do not need to
+    #instanciate the same exporter more than once.
+    exporters = {}
+    result = None
+
+    def __init__(self, settings, xmsf, er):
+        self.xmsf = xmsf
+        self.settings = settings
+        self.fileAccess = FileAccess(xmsf)
+        self.errorHandler = er
+
+        self.ucb = UCB(xmsf)
+
+        self.taskSteps = self.getTaskSteps()
+        self.myTask = Task(TASK, TASK_PREPARE, self.taskSteps)
+
+    # @return to how many destinations should the
+    # generated site be published.
+    def countPublish(self):
+        count = 0
+        publishers = self.settings.cp_DefaultSession.cp_Publishing
+        for e in publishers.childrenList:
+            if e.cp_Publish:
+                count += 1
+        return count
+
+    # @return the number of task steps that this
+    # session should have
+    def getTaskSteps(self):
+        docs = self.settings.cp_DefaultSession.cp_Content.cp_Documents.getSize()
+        xsl = 0
+        try:
+            layout = self.settings.cp_DefaultSession.getLayout()
+            xsl = len(layout.getTemplates(self.xmsf))
+        except Exception:
+            traceback.print_exc()
+
+        publish = self.countPublish()
+        return \
+                self.TASKS_IN_PREPARE + \
+                self.TASKS_IN_EXPORT + docs * self.TASKS_PER_DOC + \
+                self.TASKS_IN_GENERATE + xsl * self.TASKS_PER_XSL + \
+                self.TASKS_IN_PUBLISH + publish * self.TASKS_PER_PUBLISH + \
+                self.TASKS_IN_FINISHUP
+
+    # does the job
+    def runProcess(self):
+        self.myTask.start()
+        try:
+            try:
+                # I use here '&&' so if one of the
+                # methods returns false, the next
+                # will not be called.
+                self.result = self.createTempDir(self.myTask) and self.export(self.myTask) and self.generate(self.tempDir, self.myTask) and self.publish(self.tempDir, self.myTask)
+                print ("runProcess -- result: ", self.result)
+            finally:
+                # cleanup must be called.
+                self.result = self.result and self.cleanup(self.myTask)
+                print ("runProcess (cleanup) -- result: ", self.result)
+        except Exception:
+            traceback.print_exc()
+            self.result = False
+            print ("runProcess (Exception) -- result: ", self.result)
+
+        if not self.result:
+            # this is a bug protection.
+            self.myTask.fail()
+
+        while (self.myTask.getStatus() < self.myTask.getMax()):
+            self.myTask.advance(True)
+
+    # creates a temporary directory.
+    # @param task
+    # @return true should continue
+    def createTempDir(self, task):
+        try:
+            self.tempDir = self.fileAccess.createNewDir(self.getSOTempDir(self.xmsf), "/wwiztemp")
+        except Exception:
+            traceback.print_exc()
+        if self.tempDir is None:
+            print ("WARNING !!! createTempDir -- error")
+            #self.error(None, None, ProcessErrors.ERROR_MKDIR, ErrorHandler.ERROR_PROCESS_FATAL)
+            return False
+        else:
+            task.advance(True)
+            return True
+
+    # @param xmsf
+    # @return the staroffice /openoffice temporary directory
+    def getSOTempDir(self, xmsf):
+        try:
+            return FileAccess.getOfficePath(self.xmsf, "Temp", "")
+        except Exception:
+            traceback.print_exc()
+        return None
+
+    # CLEANUP
+
+    # delete the temporary directory
+    # @return true should continue
+    def cleanup(self, task):
+        print ("WARNING !!! cleanup")
+        task.setSubtaskName(TASK_FINISH)
+        b = self.fileAccess.delete(self.tempDir)
+        if not b:
+            print ("WARNING !!! cleanup -- error")
+            self.error(None, None, ProcessErrors.ERROR_CLEANUP, ErrorHandler.ERROR_WARNING)
+        task.advance(b)
+        return b
+
+    # This method is used to copy style files to a target
+    # Directory: css and background.
+    # Note that this method is static since it is
+    # also used when displaying a "preview"
+    def copyMedia(self, copy, settings, targetDir, task):
+        # 1. .css
+        sourceDir = FileAccess.connectURLs(settings.workPath, "styles")
+        filename = settings.cp_DefaultSession.getStyle().cp_CssHref
+        print ("WARNING !!! copyMedia (css) - source, filenamem, target, targetName: ", sourceDir, filename, targetDir, "style.css")
+        copy.copy2(sourceDir, filename, targetDir, "style.css")
+
+        task.advance(True)
+
+        # 2. background image
+        background = settings.cp_DefaultSession.cp_Design.cp_BackgroundImage
+        if (background is not None and background is not ""):
+            sourceDir = FileAccess.getParentDir(background)
+            filename = background[len(sourceDir):]
+            print ("WARNING !!! copyMedia (background) - source, filenamem, target, targetName: ", sourceDir, filename, targetDir + "/images", "background.gif")
+            copy.copy2(sourceDir, filename, targetDir + "/images", "background.gif")
+
+        task.advance(True)
+
+    # Copy "static" files (which are always the same,
+    # thus not user-input-dependant) to a target directory.
+    # Note that this method is static since it is
+    # also used when displaying a "preview"
+    # @param copy
+    # @param settings
+    # @param targetDir
+    # @throws Exception
+    @classmethod
+    def copyStaticImages(self, copy, settings, targetDir):
+        source = FileAccess.connectURLs(settings.workPath, "images")
+        target = targetDir + "/images"
+        print ("WARNING !!! copyStaticImages - source, target: ", source, target)
+        copy.copy(source, target)
+
+    # publish the given directory.
+    # @param dir the source directory to publish from
+    # @param task task tracking.
+    # @return true if should continue
+    def publish(self, folder, task):
+        task.setSubtaskName(TASK_PUBLISH_PREPARE)
+        configSet = self.settings.cp_DefaultSession.cp_Publishing
+        try:
+            self.copyMedia(self.ucb, self.settings, folder, task)
+            self.copyStaticImages(self.ucb, self.settings, folder)
+            task.advance(True)
+        except Exception as ex:
+            # error in copying media
+            traceback.print_exc()
+            print ("WARNING !!! publish -- error")
+            self.error(ex, "", ProcessErrors.ERROR_PUBLISH_MEDIA, ErrorHandler.ERROR_PROCESS_FATAL)
+            return False
+        for p in configSet.childrenList:
+            if p.cp_Publish:
+                key = configSet.getKey(p)
+                task.setSubtaskName(key)
+                if key is ZIP_PUBLISHER:
+                    self.fileAccess.delete(p.cp_URL)
+                if (not self.publish1(folder, p, self.ucb, task)):
+                    return False
+        return True
+
+    # publish the given directory to the
+    # given target CGPublish.
+    # @param dir the dir to copy from
+    # @param publish the object that specifies the target
+    # @param copy ucb encapsulation
+    # @param task task tracking
+    # @return true if should continue
+    def publish1(self, folder, publish, copy, task):
+        try:
+            task.advance(True)
+            url = publish.url
+            print ("WARNING !!! publish1 - source, target: ", folder, url)
+            copy.copy(folder, url)
+            task.advance(True)
+            return True
+        except Exception as e:
+            task.advance(False)
+            traceback.print_exc()
+            print ("WARNING !!! publish1 -- error")
+            return self.error(e, publish, ProcessErrors.ERROR_PUBLISH, ErrorHandler.ERROR_NORMAL_IGNORE)
+
+    # Generates the TOC pages for the current session.
+    # @param targetDir generating to this directory.
+    def generate(self, targetDir, task):
+        result = False
+        task.setSubtaskName(TASK_GENERATE_PREPARE)
+
+
+        layout = self.settings.cp_DefaultSession.getLayout()
+
+        try:
+            # here I create the DOM of the TOC to pass to the XSL
+            doc = self.settings.cp_DefaultSession.createDOM1()
+            self.generate1(self.xmsf, layout, doc, self.fileAccess, targetDir, task)
+        except Exception as ex:
+            print ("WARNING !!! generate (calling generate1  -- error")
+            traceback.print_exc()
+            print ("WARNING !!! publish1 -- error")
+            self.error(ex, "", ProcessErrors.ERROR_GENERATE_XSLT, ErrorHandler.ERROR_PROCESS_FATAL)
+            return False
+
+        # copy files which are not xsl from layout directory to
+        # website root.
+        try:
+            task.setSubtaskName(TASK_GENERATE_COPY)
+
+            self.copyLayoutFiles(self.ucb, self.fileAccess, self.settings, layout, targetDir)
+
+            task.advance(True)
+
+            result = True
+        except Exception as ex:
+            task.advance(False)
+            print ("WARNING !!! generate (copying layouts) -- error")
+            traceback.print_exc()
+            return self.error(ex, None, ProcessErrors.ERROR_GENERATE_COPY, ErrorHandler.ERROR_NORMAL_ABORT)
+        return result
+
+    # copies layout files which are not .xsl files
+    # to the target directory.
+    # @param ucb UCB encapsulatzion object
+    # @param fileAccess filaAccess encapsulation object
+    # @param settings web wizard settings
+    # @param layout the layout object
+    # @param targetDir the target directory to copy to
+    # @throws Exception
+    @classmethod
+    def copyLayoutFiles(self, ucb, fileAccess, settings, layout, targetDir):
+        filesPath = fileAccess.getURL(FileAccess.connectURLs(settings.workPath, "layouts/"), layout.cp_FSName)
+        print ("WARNING !!! copyLayoutFiles - source, target: ", filesPath, targetDir)
+        ucb.copy1(filesPath, targetDir, ExtensionVerifier("xsl"))
+
+    # generates the TOC page for the given layout.
+    # This method might generate more than one file, depending
+    # on how many .xsl files are in the
+    # directory specifies by the given layout object.
+    # @param xmsf
+    # @param layout specifies the layout to use.
+    # @param doc the DOM representation of the web wizard session
+    # @param fileAccess encapsulation of FileAccess
+    # @param targetPath target directory
+    # @param task
+    # @throws Exception
+    @classmethod
+    def generate1(self, xmsf, layout, doc, fileAccess, targetPath, task):
+        # a map that contains xsl templates. the keys are the xsl file names.
+        #templates = layout.getTemplates(xmsf)
+        templates = {}
+
+        task.advance1(True, TASK_GENERATE_XSL)
+
+        # each template generates a page.
+        for key,temp in templates:
+            transformer = temp.newTransformer()
+
+            doc.normalize()
+            task.advance(True)
+
+            # The target file name is like the xsl template filename
+            # without the .xsl extension.
+            #fn = fileAccess.getPath(targetPath, key[:key.length() - 4])
+            #f = File(fn)
+            #oStream = FileOutputStream(f)
+            # Due to a problem occuring when using Xalan-Java 2.6.0 and
+            # Java 1.5.0, wrap f in a FileOutputStream here (otherwise, the
+            # StreamResult's getSystemId would return a "file:/..." URL while
+            # the Xalan code expects a "file:///..." URL):
+            #transformer.transform(DOMSource(doc), StreamResult(oStream))
+            #oStream.close()
+            task.advance(True)
+
+    # I broke the export method to two methods
+    # in a time where a tree with more than one contents was planned.
+    # I left it that way, because it may be used in the future.
+    # @param task
+    # @return
+    def export(self, task):
+        return self.export1(self.settings.cp_DefaultSession.cp_Content, self.tempDir, task)
+
+    # This method could actually, with light modification, use recursion.
+    # In the present situation, where we only use a "flat" list of
+    # documents, instead of the original plan to use a tree,
+    # the recursion is not implemented.
+    # @param content the content ( directory-like, contains documents) 
+    # @param dir (target directory for exporting this content.
+    # @param task
+    # @return true if should continue
+    def export1(self, content, folder, task):
+        toPerform = 1
+        contentDir = None
+
+        try:
+            task.setSubtaskName(TASK_EXPORT_PREPARE)
+
+            # 1. create a content directory.
+            # each content (at the moment there is only one :-( )
+            # is created in its own directory.
+            # faileure here is fatal.
+            print ("export1 - folder and cp_Name: ", folder, content.cp_Name)
+            contentDir = self.fileAccess.createNewDir(folder, content.cp_Name);
+            if (contentDir is None or contentDir is ""):
+                raise IOException("Directory " + folder + " could not be created.")
+
+            content.dirName = FileAccess.getFilename(contentDir)
+
+            task.advance1(True, TASK_EXPORT_DOCUMENTS)
+            toPerform -= 1
+
+            # 2. export all documents and sub contents.
+            # (at the moment, only documents, no subcontents)
+            for item in content.cp_Documents.childrenList:
+                try:
+                    #
+                    # In present this is always the case.
+                    # may be in the future, when
+                    # a tree is used, it will be abit different.
+                    if (isinstance (item, CGDocument)):
+                        if (not self.export2(item, contentDir, task)):
+                            return False
+                    elif (not self.export2(item, contentDir, task)):
+                    # we never get here since we
+                    # did not implement sub-contents.
+                        return False
+                except SecurityException as sx:
+                    # nonfatal
+                    traceback.print_exc()
+                    print ("WARNING !!! export1 (SecurityException -- error")
+                    if (not self.error(sx, item, ProcessErrors.ERROR_EXPORT_SECURITY, ErrorHandler.ERROR_NORMAL_IGNORE)):
+                        return False
+                    self.result = False
+        except IOException as iox:
+            # nonfatal
+            traceback.print_exc()
+            print ("WARNING !!! export1 (IOException -- error")
+            return self.error(iox, content, ProcessErrors.ERROR_EXPORT_IO, ErrorHandler.ERROR_NORMAL_IGNORE)
+        except SecurityException as se:
+            # nonfatal
+            traceback.print_exc()
+            print ("WARNING !!! export1 (SecurityException -- error")
+            return self.error(se, content, ProcessErrors.ERROR_EXPORT_SECURITY, ErrorHandler.ERROR_NORMAL_IGNORE)
+
+        self.failTask(task, toPerform)
+        return True
+
+    # exports a single document
+    # @param doc the document to export
+    # @param dir the target directory
+    # @param task task tracking
+    # @return true if should continue
+    def export2(self, doc, folder, task):
+        # first I check if the document was already validated...
+        if (not doc.valid):
+            try:
+                print ("WARNING !!! export2 -- new validation: ")
+                doc.validate(self.xmsf, task)
+            except Exception as ex:
+                # fatal
+                traceback.print_exc()
+                print ("WARNING !!! export2 (validation) -- error")
+                self.error(ex, doc, ProcessErrors.ERROR_DOC_VALIDATE, ErrorHandler.ERROR_PROCESS_FATAL)
+                return False
+        # get the exporter specified for this document
+        exp = doc.cp_Exporter
+        print ("WARNING !!! export2 -- exporter: ", exp)
+        exporter = self.settings.cp_Exporters.getElement(exp)
+
+        try:
+             # here I calculate the destination filename.
+             # I take the original filename (docFilename), substract the extension, (docExt) -> (fn)
+             # and find an available filename which starts with
+             # this filename, but with the new extension. (destExt)
+            print ("WARNING !!! export2 - doc.cp_URL: ", doc.cp_URL)
+            print ("WARNING !!! export2 - doc.localFilename: ", doc.localFilename)
+            docFilename = FileAccess.getFilename(doc.cp_URL)
+            print ("WARNING !!! export2 - docFilename: ", docFilename)
+
+            docExt = FileAccess.getExtension(docFilename)
+            print ("WARNING !!! export2 - docExt: ", docExt)
+            # filename without extension
+            #fn = doc.localFilename.substring(0, doc.localFilename.length() - docExt.length() - 1)
+            fn = doc.localFilename[:len(doc.localFilename) - len(docExt) - 1]
+            print ("WARNING !!! export2 - fn: ", fn)
+
+            # the copyExporter does not change
+            # the extension of the target...
+            destExt = FileAccess.getExtension(docFilename) \
+                if (exporter.cp_Extension is "") \
+                else exporter.cp_Extension
+            print ("WARNING !!! export2 - destExt: ", destExt)
+
+            # if this filter needs to export to its own directory...
+            # this is the case in, for example, impress html export
+            if (exporter.cp_OwnDirectory):
+                # +++
+                folder = self.fileAccess.createNewDir(folder, fn)
+                doc.dirName = FileAccess.getFilename(folder)
+
+            # if two files with the same name
+            # need to be exported ? So here
+            # i get a new filename, so I do not
+            # overwrite files...
+            f = self.fileAccess.getNewFile(folder, fn, destExt)
+            print ("WARNING !!! export2 - f: ", f)
+
+
+            # set filename with extension.
+            # this will be used by the exporter,
+            # and to generate the TOC.
+            doc.urlFilename = FileAccess.getFilename(f)
+            print ("WARNING !!! export2 - : doc.urlFilename", doc.urlFilename)
+
+            task.advance(True)
+
+            try:
+                # export
+                self.getExporter(exporter).export(doc, f, self.xmsf, task)
+                task.advance(True)
+             # getExporter(..) throws
+             # IllegalAccessException, InstantiationException, ClassNotFoundException
+             # export() throws Exception
+            except Exception as ex:
+                # nonfatal
+                traceback.print_exc()
+                print ("WARNING !!! export2 (getting exporters) -- error")
+                if (not self.error(ex, doc, ProcessErrors.ERROR_EXPORT, ErrorHandler.ERROR_NORMAL_IGNORE)):
+                    return False
+        except Exception as ex:
+            # nonfatal
+            traceback.print_exc()
+            print ("WARNING !!! export2 (general) -- error")
+            if (not self.error(ex, doc, ProcessErrors.ERROR_EXPORT_MKDIR, ErrorHandler.ERROR_NORMAL_ABORT)):
+                return False
+
+        return True
+
+    # submit an error.
+    # @param ex the exception
+    # @param arg1 error argument
+    # @param arg2 error argument 2
+    # @param errType error type
+    # @return the interaction result
+    def error(self, ex, arg1, arg2, errType):
+        self.result = False
+        print ("error -- result: ", self.result)
+        return self.errorHandler.error(ex, arg1, arg2, errType)
+
+
+    # advances the given task in the given count of steps,
+    # marked as failed.
+    # @param task the task to advance
+    # @param count the number of steps to advance
+    def failTask(self, task, count):
+        while (count > 0):
+            task.advance(False)
+            count -= 1
+
+    # creates an instance of the exporter class
+    # as specified by the
+    # exporter object.
+    # @param export specifies the exporter to be created
+    # @return the Exporter instance
+    # @throws ClassNotFoundException
+    # @throws IllegalAccessException
+    # @throws InstantiationException
+    def createExporter(self, export):
+        print ("WANRING !!!! Creating exporter -- class: ", export.cp_ExporterClass)
+        pkgname = ".".join(export.cp_ExporterClass.split(".")[3:])
+        className = export.cp_ExporterClass.split(".")[-1]
+        mod = importlib.import_module(pkgname)
+        return getattr(mod, className)(export)
+
+    # searches the an exporter for the given CGExporter object
+    # in the cache.
+    # If its not there, creates it, stores it in the cache and
+    # returns it.
+    # @param export specifies the needed exporter.
+    # @return an Exporter instance
+    # @throws ClassNotFoundException thrown when using Class.forName(string)
+    # @throws IllegalAccessException thrown when using Class.forName(string)
+    # @throws InstantiationException thrown when using Class.forName(string)
+    def getExporter(self, export):
+        exp = self.exporters.get(export.cp_Name)
+        if (exp is None):
+            exp = self.createExporter(export)
+            self.exporters[export.cp_Name] = exp
+        return exp
+
+    # @return tru if everything went smooth, false
+    # if error(s) accured.
+    def getResult(self):
+        print ("Process -- getFailed: ", self.myTask.getFailed())
+        print ("Process -- result: ", self.result)
+        return (self.myTask.getFailed() == 0) and self.result

-- 
To view, visit https://gerrit.libreoffice.org/3001
To unsubscribe, visit https://gerrit.libreoffice.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I09a49ec08b89f6fbae27a60d5f9208bea7ba8cf8
Gerrit-PatchSet: 1
Gerrit-Project: core
Gerrit-Branch: master
Gerrit-Owner: Javier Fernandez <javier.fgb at gmail.com>



More information about the LibreOffice mailing list