Example #1
0
 def dump(self, obj, filePath=None, format=None):
     '''Exports this file to disk (outside the db-controller filesystem).
        The tied Appy p_obj(ect) is required. If p_filePath is specified, it
        is the path name where the file will be dumped; folders mentioned in
        it must exist. If not, the file will be dumped in the OS temp folder.
        The absolute path name of the dumped file is returned. If an error
        occurs, the method returns None. If p_format is specified,
        LibreOffice will be called for converting the dumped file to the
        desired format.'''
     if not filePath:
         filePath = '%s/file%f.%s' % (sutils.getOsTempFolder(), time.time(),
                                      self.fsName)
     # Copies the file to disk.
     shutil.copyfile(self.getFilePath(obj), filePath)
     if format:
         # Convert the dumped file using LibreOffice
         errorMessage = obj.tool.convert(filePath, format)
         # Even if we have an "error" message, it could be a simple warning.
         # So we will continue here and, as a subsequent check for knowing if
         # an error occurred or not, we will test the existence of the
         # converted file (see below).
         os.remove(filePath)
         # Return the name of the converted file.
         baseName, ext = os.path.splitext(filePath)
         if (ext == '.%s' % format):
             filePath = '%s.res.%s' % (baseName, format)
         else:
             filePath = '%s.%s' % (baseName, format)
         if not os.path.exists(filePath):
             obj.log(CONVERSION_ERROR % errorMessage, type='error')
             return
     return filePath
Example #2
0
 def generateDocument(self):
     '''Generates the document from field-related info. UID of object that
        is the template target is given in the request.'''
     rq = self.REQUEST
     appyTool = self.appy()
     # Get the object
     objectUid = rq.get('objectUid')
     obj = self.uid_catalog(UID=objectUid)[0].getObject()
     appyObj = obj.appy()
     # Get information about the document to render.
     specificPodContext = None
     fieldName = rq.get('fieldName')
     format = rq.get('podFormat')
     podInfo = self.getPodInfo(obj, fieldName)
     template = podInfo['template'].content
     podTitle = podInfo['title']
     if podInfo['context']:
         if type(podInfo['context']) == types.FunctionType:
             specificPodContext = podInfo['context'](appyObj)
         else:
             specificPodContext = podInfo['context']
     doAction = rq.get('askAction') == 'True'
     # Temporary file where to generate the result
     tempFileName = '%s/%s_%f.%s' % (
         getOsTempFolder(), obj.UID(), time.time(), format)
     # Define parameters to pass to the appy.pod renderer
     currentUser = self.portal_membership.getAuthenticatedMember()
     podContext = {'tool': appyTool, 'user': currentUser, 'self': appyObj,
                   'now': self.getProductConfig().DateTime(),
                   'projectFolder': appyTool.getDiskFolder(),
                   }
     if specificPodContext:
         podContext.update(specificPodContext)
     rendererParams = {'template': StringIO.StringIO(template),
                       'context': podContext, 'result': tempFileName}
     if appyTool.unoEnabledPython:
         rendererParams['pythonWithUnoPath'] = appyTool.unoEnabledPython
     if appyTool.openOfficePort:
         rendererParams['ooPort'] = appyTool.openOfficePort
     # Launch the renderer
     try:
         renderer = Renderer(**rendererParams)
         renderer.run()
     except appy.pod.PodError, pe:
         if not os.path.exists(tempFileName):
             # In some (most?) cases, when OO returns an error, the result is
             # nevertheless generated.
             appyTool.log(str(pe), type='error')
             appyTool.say(POD_ERROR)
             return self.goto(rq.get('HTTP_REFERER'))
Example #3
0
 def tempFile(self):
     '''A temp file has been created in a temp folder. This method returns
        this file to the browser.'''
     rq = self.REQUEST
     baseFolder = os.path.join(getOsTempFolder(), self.getAppName())
     baseFolder = os.path.join(baseFolder, rq.SESSION.id)
     fileName   = os.path.join(baseFolder, rq.get('name', ''))
     if os.path.exists(fileName):
         f = file(fileName)
         content = f.read()
         f.close()
         # Remove the temp file
         os.remove(fileName)
         return content
     return 'File does not exist'
Example #4
0
 def tempFile(self):
     '''A temp file has been created in a temp folder. This method returns
        this file to the browser.'''
     rq = self.REQUEST
     baseFolder = os.path.join(getOsTempFolder(), self.getAppName())
     baseFolder = os.path.join(baseFolder, rq.SESSION.id)
     fileName = os.path.join(baseFolder, rq.get('name', ''))
     if os.path.exists(fileName):
         f = file(fileName)
         content = f.read()
         f.close()
         # Remove the temp file
         os.remove(fileName)
         return content
     return 'File does not exist'
Example #5
0
 def getPoFile(self):
     '''Computes and returns the PO file corresponding to this
        translation.'''
     tool = self.tool
     fileName = os.path.join(getOsTempFolder(),
                             '%s-%s.po' % (tool.o.getAppName(), self.id))
     poFile = PoFile(fileName)
     for field in self.fields:
         if (field.name == 'title') or (field.type != 'String'): continue
         # Adds the PO message corresponding to this field
         msg = field.getValue(self.o) or ''
         for old, new in self.poReplacements:
             msg = msg.replace(old, new)
         poFile.addMessage(PoMessage(field.name, msg, ''))
     poFile.generate()
     return True, file(fileName)
Example #6
0
 def getPoFile(self):
     '''Computes and returns the PO file corresponding to this
        translation.'''
     tool = self.tool
     fileName = os.path.join(getOsTempFolder(),
                             '%s-%s.po' % (tool.o.getAppName(), self.id))
     poFile = PoFile(fileName)
     for field in self.fields:
         if (field.name == 'title') or (field.type != 'String'): continue
         # Adds the PO message corresponding to this field
         msg = field.getValue(self.o) or ''
         for old, new in self.poReplacements:
             msg = msg.replace(old, new)
         poFile.addMessage(PoMessage(field.name, msg, ''))
     poFile.generate()
     return True, file(fileName)
Example #7
0
 def migrateBinaryFields(obj):
     '''Ensures all file and frozen pod fields on p_obj are FileInfo
        instances.'''
     migrated = 0  # Count the number of migrated fields
     for field in obj.fields:
         if field.type == 'File':
             oldValue = getattr(obj, field.name)
             if oldValue and not isinstance(oldValue, FileInfo):
                 # A legacy File object. Convert it to a FileInfo instance
                 # and extract the binary to the filesystem.
                 setattr(obj, field.name, oldValue)
                 migrated += 1
         elif field.type == 'Pod':
             frozen = getattr(obj.o, field.name, None)
             if frozen:
                 # Dump this file on disk.
                 tempFolder = sutils.getOsTempFolder()
                 fmt = os.path.splitext(frozen.filename)[1][1:]
                 fileName = os.path.join(tempFolder,
                                         '%f.%s' % (time.time(), fmt))
                 f = file(fileName, 'wb')
                 if frozen.data.__class__.__name__ == 'Pdata':
                     # The file content is splitted in several chunks.
                     f.write(frozen.data.data)
                     nextPart = frozen.data.next
                     while nextPart:
                         f.write(nextPart.data)
                         nextPart = nextPart.next
                 else:
                     # Only one chunk
                     f.write(frozen.data)
                 f.close()
                 f = file(fileName)
                 field.freeze(obj,
                              template=field.template[0],
                              format=fmt,
                              noSecurity=True,
                              upload=f,
                              freezeOdtOnError=False)
                 f.close()
                 # Remove the legacy in-zodb file object
                 setattr(obj.o, field.name, None)
                 migrated += 1
     return migrated
Example #8
0
 def dump(self, filePath=None, format=None, tool=None):
     '''Writes the file on disk. If p_filePath is specified, it is the
        path name where the file will be dumped; folders mentioned in it
        must exist. If not, the file will be dumped in the OS temp folder.
        The absolute path name of the dumped file is returned.
        If an error occurs, the method returns None. If p_format is
        specified, OpenOffice will be called for converting the dumped file
        to the desired format. In this case, p_tool, a Appy tool, must be
        provided. Indeed, any Appy tool contains parameters for contacting
        OpenOffice in server mode.'''
     if not filePath:
         filePath = '%s/file%f.%s' % (getOsTempFolder(), time.time(),
             normalizeString(self.name))
     f = file(filePath, 'w')
     if self.content.__class__.__name__ == 'Pdata':
         # The file content is splitted in several chunks.
         f.write(self.content.data)
         nextPart = self.content.next
         while nextPart:
             f.write(nextPart.data)
             nextPart = nextPart.next
     else:
         # Only one chunk
         f.write(self.content)
     f.close()
     if format:
         if not tool: return
         # Convert the dumped file using OpenOffice
         errorMessage = tool.convert(filePath, format)
         # Even if we have an "error" message, it could be a simple warning.
         # So we will continue here and, as a subsequent check for knowing if
         # an error occurred or not, we will test the existence of the
         # converted file (see below).
         os.remove(filePath)
         # Return the name of the converted file.
         baseName, ext = os.path.splitext(filePath)
         if (ext == '.%s' % format):
             filePath = '%s.res.%s' % (baseName, format)
         else:
             filePath = '%s.%s' % (baseName, format)
         if not os.path.exists(filePath):
             tool.log(CONVERSION_ERROR % (cmd, errorMessage), type='error')
             return
     return filePath
 def export(self, at='string', format='xml', include=None, exclude=None):
     '''Creates an "exportable" version of this object. p_format is "xml" by
        default, but can also be "csv". If p_format is:
        * "xml", if p_at is "string", this method returns the XML version,
                 without the XML prologue. Else, (a) if not p_at, the XML
                 will be exported on disk, in the OS temp folder, with an
                 ugly name; (b) else, it will be exported at path p_at.
        * "csv", if p_at is "string", this method returns the CSV data as a
                 string. If p_at is an opened file handler, the CSV line will
                 be appended in it.
        If p_include is given, only fields whose names are in it will be
        included. p_exclude, if given, contains names of fields that will
        not be included in the result.
     '''
     if format == 'xml':
         # Todo: take p_include and p_exclude into account.
         # Determine where to put the result
         toDisk = (at != 'string')
         if toDisk and not at:
             at = getOsTempFolder() + '/' + self.o.UID() + '.xml'
         # Create the XML version of the object
         marshaller = XmlMarshaller(cdata=True,
                                    dumpUnicode=True,
                                    dumpXmlPrologue=toDisk,
                                    rootTag=self.klass.__name__)
         xml = marshaller.marshall(self.o, objectType='appy')
         # Produce the desired result
         if toDisk:
             f = file(at, 'w')
             f.write(xml.encode('utf-8'))
             f.close()
             return at
         else:
             return xml
     elif format == 'csv':
         if isinstance(at, basestring):
             marshaller = CsvMarshaller(include=include, exclude=exclude)
             return marshaller.marshall(self)
         else:
             marshaller = CsvMarshaller(at,
                                        include=include,
                                        exclude=exclude)
             marshaller.marshall(self)
Example #10
0
 def migrateBinaryFields(obj):
     '''Ensures all file and frozen pod fields on p_obj are FileInfo
        instances.'''
     migrated = 0 # Count the number of migrated fields
     for field in obj.fields:
         if field.type == 'File':
             oldValue = getattr(obj, field.name)
             if oldValue and not isinstance(oldValue, FileInfo):
                 # A legacy File object. Convert it to a FileInfo instance
                 # and extract the binary to the filesystem.
                 setattr(obj, field.name, oldValue)
                 migrated += 1
         elif field.type == 'Pod':
             frozen = getattr(obj.o, field.name, None)
             if frozen:
                 # Dump this file on disk.
                 tempFolder = sutils.getOsTempFolder()
                 fmt = os.path.splitext(frozen.filename)[1][1:]
                 fileName = os.path.join(tempFolder,
                                         '%f.%s' % (time.time(), fmt))
                 f = file(fileName, 'wb')
                 if frozen.data.__class__.__name__ == 'Pdata':
                     # The file content is splitted in several chunks.
                     f.write(frozen.data.data)
                     nextPart = frozen.data.next
                     while nextPart:
                         f.write(nextPart.data)
                         nextPart = nextPart.next
                 else:
                     # Only one chunk
                     f.write(frozen.data)
                 f.close()
                 f = file(fileName)
                 field.freeze(obj, template=field.template[0], format=fmt,
                              noSecurity=True, upload=f,
                              freezeOdtOnError=False)
                 f.close()
                 # Remove the legacy in-zodb file object
                 setattr(obj.o, field.name, None)
                 migrated += 1
     return migrated
Example #11
0
 def export(self, at="string", format="xml", include=None, exclude=None):
     """Creates an "exportable" version of this object. p_format is "xml" by
        default, but can also be "csv". If p_format is:
        * "xml", if p_at is "string", this method returns the XML version,
                 without the XML prologue. Else, (a) if not p_at, the XML
                 will be exported on disk, in the OS temp folder, with an
                 ugly name; (b) else, it will be exported at path p_at.
        * "csv", if p_at is "string", this method returns the CSV data as a
                 string. If p_at is an opened file handler, the CSV line will
                 be appended in it.
        If p_include is given, only fields whose names are in it will be
        included. p_exclude, if given, contains names of fields that will
        not be included in the result.
     """
     if format == "xml":
         # Todo: take p_include and p_exclude into account.
         # Determine where to put the result
         toDisk = at != "string"
         if toDisk and not at:
             at = getOsTempFolder() + "/" + self.o.UID() + ".xml"
         # Create the XML version of the object
         marshaller = XmlMarshaller(
             cdata=True, dumpUnicode=True, dumpXmlPrologue=toDisk, rootTag=self.klass.__name__
         )
         xml = marshaller.marshall(self.o, objectType="appy")
         # Produce the desired result
         if toDisk:
             f = file(at, "w")
             f.write(xml.encode("utf-8"))
             f.close()
             return at
         else:
             return xml
     elif format == "csv":
         if isinstance(at, basestring):
             marshaller = CsvMarshaller(include=include, exclude=exclude)
             return marshaller.marshall(self)
         else:
             marshaller = CsvMarshaller(at, include=include, exclude=exclude)
             marshaller.marshall(self)
Example #12
0
 def export(self, at='string'):
     '''Creates an "exportable", XML version of this object. If p_at is
        "string", this method returns the XML version, without the XML
        prologue. Else, (a) if not p_at, the XML will be exported on disk,
        in the OS temp folder, with an ugly name; (b) else, it will be
        exported at path p_at.'''
     # Determine where to put the result
     toDisk = (at != 'string')
     if toDisk and not at:
         at = getOsTempFolder() + '/' + self.o.UID() + '.xml'
     # Create the XML version of the object
     marshaller = XmlMarshaller(cdata=True, dumpUnicode=True,
                                dumpXmlPrologue=toDisk,
                                rootTag=self.klass.__name__)
     xml = marshaller.marshall(self.o, objectType='appy')
     # Produce the desired result
     if toDisk:
         f = file(at, 'w')
         f.write(xml.encode('utf-8'))
         f.close()
         return at
     else:
         return xml
Example #13
0
 def __init__(self, fileOrFolder, keyword):
     self.fileOrFolder = fileOrFolder
     self.keyword = keyword
     self.tempFolder = getOsTempFolder()
Example #14
0
 def run(self):
     '''Generates the Debian package.'''
     curdir = os.getcwd()
     j = os.path.join
     tempFolder = getOsTempFolder()
     # Create, in the temp folder, the required sub-structure for the Debian
     # package.
     debFolder = j(tempFolder, 'debian')
     if os.path.exists(debFolder):
         FolderDeleter.delete(debFolder)
     # Copy the Python package into it
     srcFolder = j(debFolder, 'usr', 'lib')
     for version in self.pythonVersions:
         libFolder = j(srcFolder, 'python%s' % version)
         os.makedirs(libFolder)
         destFolder = j(libFolder, self.appName)
         shutil.copytree(self.app, destFolder)
         # Clean dest folder (.svn/.bzr files)
         cleanFolder(destFolder, folders=('.svn', '.bzr'))
     # When packaging Appy itself, everything is in /usr/lib/pythonX. When
     # packaging an Appy app, we will generate more files for creating a
     # running instance.
     if self.appName != 'appy':
         # Create the folders that will collectively represent the deployed
         # Zope instance.
         binFolder = j(debFolder, 'usr', 'bin')
         os.makedirs(binFolder)
         # <app>ctl
         name = '%s/%sctl' % (binFolder, self.appNameLower)
         f = file(name, 'w')
         f.write(appCtl % self.appNameLower)
         os.chmod(name, 0744) # Make it executable by owner.
         f.close()
         # <app>run
         name = '%s/%srun' % (binFolder, self.appNameLower)
         f = file(name, 'w')
         f.write(appRun % self.appNameLower)
         os.chmod(name, 0744) # Make it executable by owner.
         f.close()
         # startlo
         name = '%s/startlo' % binFolder
         f = file(name, 'w')
         f.write(loStart)
         f.close()
         os.chmod(name, 0744) # Make it executable by owner.
         # /var/lib/<app> (will store Data.fs, lock files, etc)
         varLibFolder = j(debFolder, 'var', 'lib', self.appNameLower)
         os.makedirs(varLibFolder)
         f = file('%s/README' % varLibFolder, 'w')
         f.write('This folder stores the %s database.\n' % self.appName)
         f.close()
         # /var/log/<app> (will store event.log and Z2.log)
         varLogFolder = j(debFolder, 'var', 'log', self.appNameLower)
         os.makedirs(varLogFolder)
         f = file('%s/README' % varLogFolder, 'w')
         f.write('This folder stores the log files for %s.\n' % self.appName)
         f.close()
         # /etc/<app>.conf (Zope configuration file)
         etcFolder = j(debFolder, 'etc')
         os.makedirs(etcFolder)
         name = '%s/%s.conf' % (etcFolder, self.appNameLower)
         n = self.appNameLower
         f = file(name, 'w')
         productsFolder = '/usr/lib/python%s/%s/zope' % \
                          (self.pythonVersions[0], self.appName)
         f.write(zopeConf % ('/var/lib/%s' % n, '/var/lib/%s' % n,
                             '/var/log/%s' % n, str(self.zopePort),
                             'products %s\n' % productsFolder))
         f.close()
         # /etc/init.d/<app> (start the app at boot time)
         initdFolder = j(etcFolder, 'init.d')
         os.makedirs(initdFolder)
         name = '%s/%s' % (initdFolder, self.appNameLower)
         f = file(name, 'w')
         n = self.appNameLower
         f.write(initScript % (n, n, 'Start Zope with the Appy-based %s ' \
                               'application.' % n, '%sctl start' % n,
                               '%sctl restart' % n, '%sctl stop' % n))
         f.close()
         os.chmod(name, 0744) # Make it executable by owner
         # /etc/init.d/lo (start LibreOffice at boot time)
         name = '%s/lo' % initdFolder
         f = file(name, 'w')
         f.write(initScript % ('lo','lo', 'Start LibreOffice in server mode',
                               'startlo', 'startlo', "#Can't stop LO."))
         f.write('\n')
         f.close()
         os.chmod(name, 0744) # Make it executable by owner.
     # Get the size of the app, in Kb.
     os.chdir(tempFolder)
     out, err = executeCommand(['du', '-b', '-s', 'debian'])
     size = int(int(out.split()[0])/1024.0)
     os.chdir(debFolder)
     # Create data.tar.gz based on it
     executeCommand(['tar', 'czvf', 'data.tar.gz', '*'])
     # Create the control file
     f = file('control', 'w')
     nameSuffix = ''
     dependencies = []
     if self.appName != 'appy':
         nameSuffix = '-%s' % self.appNameLower
         dependencies.append('python-appy')
     if self.depends:
         for d in self.depends: dependencies.append(d)
     depends = ''
     if dependencies:
         depends = ', ' + ', '.join(dependencies)
     f.write(debianInfo % (nameSuffix, self.appVersion, size,
                           self.pythonVersions[0], depends))
     f.close()
     # Create md5sum file
     f = file('md5sums', 'w')
     toWalk = ['usr']
     if self.appName != 'appy':
         toWalk += ['etc', 'var']
     for folderToWalk in toWalk:
         for dir, dirnames, filenames in os.walk(folderToWalk):
             for name in filenames:
                 m = md5.new()
                 pathName = j(dir, name)
                 currentFile = file(pathName, 'rb')
                 while True:
                     data = currentFile.read(8096)
                     if not data:
                         break
                     m.update(data)
                 currentFile.close()
                 # Add the md5 sum to the file
                 f.write('%s  %s\n' % (m.hexdigest(), pathName))
     f.close()
     # Create postinst, a script that will:
     # - bytecompile Python files after the Debian install
     # - change ownership of some files if required
     # - [in the case of an app-package] call update-rc.d for starting it at
     #   boot time.
     f = file('postinst', 'w')
     content = '#!/bin/sh\nset -e\n'
     for version in self.pythonVersions:
         bin = '/usr/bin/python%s' % version
         lib = '/usr/lib/python%s' % version
         cmds = ' %s -m compileall -q %s/%s 2> /dev/null\n' % (bin, lib,
                                                               self.appName)
         content += 'if [ -e %s ]\nthen\n%sfi\n' % (bin, cmds)
     if self.appName != 'appy':
         # Allow user "zope", that runs the Zope instance, to write the
         # database and log files.
         content += 'chown -R zope:root /var/lib/%s\n' % self.appNameLower
         content += 'chown -R zope:root /var/log/%s\n' % self.appNameLower
         # Call update-rc.d for starting the app at boot time
         content += 'update-rc.d %s defaults\n' % self.appNameLower
         content += 'update-rc.d lo defaults\n'
         # (re-)start the app
         content += '%sctl restart\n' % self.appNameLower
         # (re-)start lo
         content += 'startlo\n'
     f.write(content)
     f.close()
     # Create prerm, a script that will remove all pyc files before removing
     # the Debian package.
     f = file('prerm', 'w')
     content = '#!/bin/sh\nset -e\n'
     for version in self.pythonVersions:
         content += 'find /usr/lib/python%s/%s -name "*.pyc" -delete\n' % \
                    (version, self.appName)
     f.write(content)
     f.close()
     # Create control.tar.gz
     executeCommand(['tar', 'czvf', 'control.tar.gz', './control',
                     './md5sums', './postinst', './prerm'])
     # Create debian-binary
     f = file('debian-binary', 'w')
     f.write('2.0\n')
     f.close()
     # Create the signature if required
     if self.sign:
         # Create the concatenated version of all files within the deb
         out, err = executeCommand(['cat', 'debian-binary', 'control.tar.gz',
                                    'data.tar.gz'])
         f = file('/tmp/combined-contents', 'wb')
         f.write(out)
         f.close()
         executeCommand(['gpg', '-abs', '-o', '_gpgorigin',
                         '/tmp/combined-contents'])
         signFile = '_gpgorigin'
         os.remove('/tmp/combined-contents')
         # Export the public key and name it according to its ID as found by
         # analyzing the result of command "gpg --fingerprint".
         out, err = executeCommand(['gpg', '--fingerprint'])
         fingerprint = out.split('\n')
         id = 'pubkey'
         for line in fingerprint:
             if '=' not in line: continue
             id = line.split('=')[1].strip()
             id = ''.join(id.split()[-4:])
             break
         out, err = executeCommand(['gpg', '--export', '-a'])
         f = file('%s/%s.asc' % (self.out, id), 'w')
         f.write(out)
         f.close()
     else:
         signFile = None
     # Create the .deb package
     debName = 'python-appy%s-%s.deb' % (nameSuffix, self.appVersion)
     cmd = ['ar', '-r', debName]
     if signFile: cmd.append(signFile)
     cmd += ['debian-binary', 'control.tar.gz', 'data.tar.gz']
     out, err = executeCommand(cmd)
     # Move it to self.out
     os.rename(j(debFolder, debName), j(self.out, debName))
     # Clean temp files
     FolderDeleter.delete(debFolder)
     os.chdir(curdir)
Example #15
0
 def getValue(self, obj, name=None, template=None, format=None, result=None,
              queryData=None, customContext=None, noSecurity=False):
     '''For a pod field, getting its value means computing a pod document or
        returning a frozen one. A pod field differs from other field types
        because there can be several ways to produce the field value (ie:
        self.template can hold various templates; output file format can be
        odt, pdf,.... We get those precisions about the way to produce the
        file, either from params, or from default values.
        * p_template is the specific template, among self.template, that must
          be used as base for generating the document;
        * p_format is the output format of the resulting document;
        * p_result, if given, must be the absolute path of the document that
          will be computed by pod. If not given, pod will produce a doc in
          the OS temp folder;
        * if the pod document is related to a query, the query parameters
          needed to re-trigger the query are given in p_queryData;
        * dict p_customContext may be specified and will override any other
          value available in the context, including values from the
          field-specific context.
     '''
     obj = obj.appy()
     template = template or self.template[0]
     format = format or 'odt'
     # Security check
     if not noSecurity and not queryData:
         if self.showTemplate and not self.showTemplate(obj, template):
             raise Exception(UNAUTHORIZED)
     # Return the possibly frozen document (not applicable for query-related
     # pods).
     if not queryData:
         frozen = self.isFrozen(obj, template, format)
         if frozen:
             fileName = self.getDownloadName(obj, template, format, False)
             return FileInfo(frozen, inDb=False, uploadName=fileName)
     # We must call pod to compute a pod document from "template"
     tool = obj.tool
     ztool = tool.o
     diskFolder = tool.getDiskFolder()
     # Get the path to the pod template
     templatePath = self.getTemplatePath(diskFolder, template)
     # Get or compute the specific POD context
     specificContext = None
     if callable(self.context):
         specificContext = self.callMethod(obj, self.context)
     else:
         specificContext = self.context
     # Compute the name of the result file
     if not result:
         result = '%s/%s_%f.%s' % (sutils.getOsTempFolder(), obj.id,
                                   time.time(), format)
     # Define parameters to give to the appy.pod renderer
     podContext = {'tool': tool, 'user': obj.user, 'self': obj, 'field':self,
                   'now': ztool.getProductConfig().DateTime(),
                   '_': obj.translate, 'projectFolder': diskFolder,
                   'template': template, 'request': tool.request}
     # If the pod document is related to a query, re-trigger it and put the
     # result in the pod context.
     if queryData:
         # Retrieve query params
         cmd = ', '.join(Pod.queryParams)
         cmd += " = queryData.split(';')"
         exec cmd
         # (re-)execute the query, but without any limit on the number of
         # results; return Appy objects.
         objs = ztool.executeQuery(obj.o.portal_type, searchName=search,
                  sortBy=sortKey, sortOrder=sortOrder, filterKey=filterKey,
                  filterValue=filterValue, maxResults='NO_LIMIT')
         podContext['objects'] = [o.appy() for o in objs.objects]
         podContext['queryData'] = queryData.split(';')
     # Add the field-specific and custom contexts if present.
     if specificContext: podContext.update(specificContext)
     if customContext: podContext.update(customContext)
     # Variable "_checked" can be expected by a template but absent (ie,
     # when generating frozen documents).
     if '_checked' not in podContext: podContext['_checked'] = Object()
     # Define a potential global styles mapping
     if callable(self.stylesMapping):
         stylesMapping = self.callMethod(obj, self.stylesMapping)
     else:
         stylesMapping = self.stylesMapping
     rendererParams = {'template': templatePath, 'context': podContext,
       'result': result, 'stylesMapping': stylesMapping,
       'imageResolver': ztool.getApp(), 'overwriteExisting': True,
       'forceOoCall': self.forceOoCall}
     cfg = ztool.getProductConfig(True)
     if cfg.unoEnabledPython:
         rendererParams['pythonWithUnoPath'] = cfg.unoEnabledPython
     if cfg.libreOfficePort:
         rendererParams['ooPort'] = cfg.libreOfficePort
     # Launch the renderer
     try:
         renderer = Renderer(**rendererParams)
         renderer.run()
     except PodError, pe:
         if not os.path.exists(result):
             # In some (most?) cases, when OO returns an error, the result is
             # nevertheless generated.
             obj.log(str(pe).strip(), type='error')
             return POD_ERROR
 def run(self):
     '''Generates the Debian package.'''
     curdir = os.getcwd()
     j = os.path.join
     tempFolder = getOsTempFolder()
     # Create, in the temp folder, the required sub-structure for the Debian
     # package.
     debFolder = j(tempFolder, 'debian')
     if os.path.exists(debFolder):
         FolderDeleter.delete(debFolder)
     # Copy the Python package into it
     srcFolder = j(debFolder, 'usr', 'lib')
     for version in self.pythonVersions:
         libFolder = j(srcFolder, 'python%s' % version)
         os.makedirs(libFolder)
         destFolder = j(libFolder, self.appName)
         shutil.copytree(self.app, destFolder)
         # Clean dest folder (.svn/.bzr files)
         cleanFolder(destFolder, folders=('.svn', '.bzr'))
     # When packaging Appy itself, everything is in /usr/lib/pythonX. When
     # packaging an Appy app, we will generate more files for creating a
     # running instance.
     if self.appName != 'appy':
         # Create the folders that will collectively represent the deployed
         # Zope instance.
         binFolder = j(debFolder, 'usr', 'bin')
         os.makedirs(binFolder)
         # <app>ctl
         name = '%s/%sctl' % (binFolder, self.appNameLower)
         f = file(name, 'w')
         f.write(appCtl % self.appNameLower)
         os.chmod(name, 0744)  # Make it executable by owner.
         f.close()
         # <app>run
         name = '%s/%srun' % (binFolder, self.appNameLower)
         f = file(name, 'w')
         f.write(appRun % self.appNameLower)
         os.chmod(name, 0744)  # Make it executable by owner.
         f.close()
         # startoo
         name = '%s/startoo' % binFolder
         f = file(name, 'w')
         f.write(ooStart)
         f.close()
         os.chmod(name, 0744)  # Make it executable by owner.
         # /var/lib/<app> (will store Data.fs, lock files, etc)
         varLibFolder = j(debFolder, 'var', 'lib', self.appNameLower)
         os.makedirs(varLibFolder)
         f = file('%s/README' % varLibFolder, 'w')
         f.write('This folder stores the %s database.\n' % self.appName)
         f.close()
         # /var/log/<app> (will store event.log and Z2.log)
         varLogFolder = j(debFolder, 'var', 'log', self.appNameLower)
         os.makedirs(varLogFolder)
         f = file('%s/README' % varLogFolder, 'w')
         f.write('This folder stores the log files for %s.\n' %
                 self.appName)
         f.close()
         # /etc/<app>.conf (Zope configuration file)
         etcFolder = j(debFolder, 'etc')
         os.makedirs(etcFolder)
         name = '%s/%s.conf' % (etcFolder, self.appNameLower)
         n = self.appNameLower
         f = file(name, 'w')
         productsFolder = '/usr/lib/python%s/%s/zope' % \
                          (self.pythonVersions[0], self.appName)
         f.write(zopeConf %
                 ('/var/lib/%s' % n, '/var/lib/%s' % n, '/var/log/%s' % n,
                  str(self.zopePort), 'products %s\n' % productsFolder))
         f.close()
         # /etc/init.d/<app> (start the app at boot time)
         initdFolder = j(etcFolder, 'init.d')
         os.makedirs(initdFolder)
         name = '%s/%s' % (initdFolder, self.appNameLower)
         f = file(name, 'w')
         n = self.appNameLower
         f.write(initScript % (n, n, 'Start Zope with the Appy-based %s ' \
                               'application.' % n, '%sctl start' % n,
                               '%sctl restart' % n, '%sctl stop' % n))
         f.close()
         os.chmod(name, 0744)  # Make it executable by owner.
         # /etc/init.d/oo (start OpenOffice at boot time)
         name = '%s/oo' % initdFolder
         f = file(name, 'w')
         f.write(initScript %
                 ('oo', 'oo', 'Start OpenOffice in server mode', 'startoo',
                  'startoo', "#Can't stop OO."))
         f.write('\n')
         f.close()
         os.chmod(name, 0744)  # Make it executable by owner.
     # Get the size of the app, in Kb.
     os.chdir(tempFolder)
     cmd = subprocess.Popen(['du', '-b', '-s', 'debian'],
                            stdout=subprocess.PIPE)
     size = int(int(cmd.stdout.read().split()[0]) / 1024.0)
     os.chdir(debFolder)
     # Create data.tar.gz based on it.
     os.system('tar czvf data.tar.gz *')
     # Create the control file
     f = file('control', 'w')
     nameSuffix = ''
     dependencies = []
     if self.appName != 'appy':
         nameSuffix = '-%s' % self.appNameLower
         dependencies.append('python-appy')
     if self.depends:
         for d in self.depends:
             dependencies.append(d)
     depends = ''
     if dependencies:
         depends = ', ' + ', '.join(dependencies)
     f.write(debianInfo % (nameSuffix, self.appVersion, size,
                           self.pythonVersions[0], depends))
     f.close()
     # Create md5sum file
     f = file('md5sums', 'w')
     toWalk = ['usr']
     if self.appName != 'appy':
         toWalk += ['etc', 'var']
     for folderToWalk in toWalk:
         for dir, dirnames, filenames in os.walk(folderToWalk):
             for name in filenames:
                 m = md5.new()
                 pathName = j(dir, name)
                 currentFile = file(pathName, 'rb')
                 while True:
                     data = currentFile.read(8096)
                     if not data:
                         break
                     m.update(data)
                 currentFile.close()
                 # Add the md5 sum to the file
                 f.write('%s  %s\n' % (m.hexdigest(), pathName))
     f.close()
     # Create postinst, a script that will:
     # - bytecompile Python files after the Debian install
     # - change ownership of some files if required
     # - [in the case of an app-package] call update-rc.d for starting it at
     #   boot time.
     f = file('postinst', 'w')
     content = '#!/bin/sh\nset -e\n'
     for version in self.pythonVersions:
         bin = '/usr/bin/python%s' % version
         lib = '/usr/lib/python%s' % version
         cmds = ' %s -m compileall -q %s/%s 2> /dev/null\n' % (bin, lib,
                                                               self.appName)
         content += 'if [ -e %s ]\nthen\n%sfi\n' % (bin, cmds)
     if self.appName != 'appy':
         # Allow user "zope", that runs the Zope instance, to write the
         # database and log files.
         content += 'chown -R zope:root /var/lib/%s\n' % self.appNameLower
         content += 'chown -R zope:root /var/log/%s\n' % self.appNameLower
         # Call update-rc.d for starting the app at boot time
         content += 'update-rc.d %s defaults\n' % self.appNameLower
         content += 'update-rc.d oo defaults\n'
         # (re-)start the app
         content += '%sctl restart\n' % self.appNameLower
         # (re-)start oo
         content += 'startoo\n'
     f.write(content)
     f.close()
     # Create prerm, a script that will remove all pyc files before removing
     # the Debian package.
     f = file('prerm', 'w')
     content = '#!/bin/sh\nset -e\n'
     for version in self.pythonVersions:
         content += 'find /usr/lib/python%s/%s -name "*.pyc" -delete\n' % \
                    (version, self.appName)
     f.write(content)
     f.close()
     # Create control.tar.gz
     os.system('tar czvf control.tar.gz ./control ./md5sums ./postinst ' \
               './prerm')
     # Create debian-binary
     f = file('debian-binary', 'w')
     f.write('2.0\n')
     f.close()
     # Create the signature if required
     if self.sign:
         # Create the concatenated version of all files within the deb
         os.system('cat debian-binary control.tar.gz data.tar.gz > ' \
                   '/tmp/combined-contents')
         os.system('gpg -abs -o _gpgorigin /tmp/combined-contents')
         signFile = '_gpgorigin '
         os.remove('/tmp/combined-contents')
         # Export the public key and name it according to its ID as found by
         # analyzing the result of command "gpg --fingerprint".
         cmd = subprocess.Popen(['gpg', '--fingerprint'],
                                stdout=subprocess.PIPE)
         fingerprint = cmd.stdout.read().split('\n')
         id = 'pubkey'
         for line in fingerprint:
             if '=' not in line: continue
             id = line.split('=')[1].strip()
             id = ''.join(id.split()[-4:])
             break
         os.system('gpg --export -a > %s/%s.asc' % (self.out, id))
     else:
         signFile = ''
     # Create the .deb package
     debName = 'python-appy%s-%s.deb' % (nameSuffix, self.appVersion)
     os.system('ar -r %s %sdebian-binary control.tar.gz data.tar.gz' % \
               (debName, signFile))
     # Move it to self.out
     os.rename(j(debFolder, debName), j(self.out, debName))
     # Clean temp files
     FolderDeleter.delete(debFolder)
     os.chdir(curdir)
Example #17
0
 def getValue(
     self, obj, template=None, format=None, result=None, queryData=None, customParams=None, noSecurity=False
 ):
     """For a pod field, getting its value means computing a pod document or
        returning a frozen one. A pod field differs from other field types
        because there can be several ways to produce the field value (ie:
        self.template can hold various templates; output file format can be
        odt, pdf,.... We get those precisions about the way to produce the
        file, either from params, or from default values.
        * p_template is the specific template, among self.template, that must
          be used as base for generating the document;
        * p_format is the output format of the resulting document;
        * p_result, if given, must be the absolute path of the document that
          will be computed by pod. If not given, pod will produce a doc in
          the OS temp folder;
        * if the pod document is related to a query, the query parameters
          needed to re-trigger the query are given in p_queryData;
        * p_customParams may be specified. Every custom param must have form
          "name:value". Custom params override any other value available in
          the context, including values from the field-specific context.
     """
     obj = obj.appy()
     template = template or self.template[0]
     format = format or "odt"
     # Security check.
     if not noSecurity and not queryData:
         if self.showTemplate and not self.showTemplate(obj, template):
             raise Exception(self.UNAUTHORIZED)
     # Return the possibly frozen document (not applicable for query-related
     # pods).
     if not queryData:
         frozen = self.isFrozen(obj, template, format)
         if frozen:
             fileName = self.getDownloadName(obj, template, format, False)
             return FileInfo(frozen, inDb=False, uploadName=fileName)
     # We must call pod to compute a pod document from "template".
     tool = obj.tool
     diskFolder = tool.getDiskFolder()
     # Get the path to the pod template.
     templatePath = os.path.join(diskFolder, template)
     if not os.path.isfile(templatePath):
         raise Exception(self.TEMPLATE_NOT_FOUND % templatePath)
     # Get or compute the specific POD context
     specificContext = None
     if callable(self.context):
         specificContext = self.callMethod(obj, self.context)
     else:
         specificContext = self.context
     # Compute the name of the result file.
     if not result:
         result = "%s/%s_%f.%s" % (sutils.getOsTempFolder(), obj.uid, time.time(), format)
     # Define parameters to give to the appy.pod renderer
     podContext = {
         "tool": tool,
         "user": obj.user,
         "self": obj,
         "field": self,
         "now": obj.o.getProductConfig().DateTime(),
         "_": obj.translate,
         "projectFolder": diskFolder,
     }
     # If the pod document is related to a query, re-trigger it and put the
     # result in the pod context.
     if queryData:
         # Retrieve query params
         cmd = ", ".join(tool.o.queryParamNames)
         cmd += " = queryData.split(';')"
         exec cmd
         # (re-)execute the query, but without any limit on the number of
         # results; return Appy objects.
         objs = tool.o.executeQuery(
             obj.o.portal_type,
             searchName=search,
             sortBy=sortKey,
             sortOrder=sortOrder,
             filterKey=filterKey,
             filterValue=filterValue,
             maxResults="NO_LIMIT",
         )
         podContext["objects"] = [o.appy() for o in objs.objects]
     # Add the field-specific context if present.
     if specificContext:
         podContext.update(specificContext)
     # If a custom param comes from the request, add it to the context.
     if customParams:
         paramsDict = eval(customParams)
         podContext.update(paramsDict)
     # Define a potential global styles mapping
     if callable(self.stylesMapping):
         stylesMapping = self.callMethod(obj, self.stylesMapping)
     else:
         stylesMapping = self.stylesMapping
     rendererParams = {
         "template": templatePath,
         "context": podContext,
         "result": result,
         "stylesMapping": stylesMapping,
         "imageResolver": tool.o.getApp(),
         "overwriteExisting": True,
     }
     if tool.unoEnabledPython:
         rendererParams["pythonWithUnoPath"] = tool.unoEnabledPython
     if tool.openOfficePort:
         rendererParams["ooPort"] = tool.openOfficePort
     # Launch the renderer
     try:
         renderer = Renderer(**rendererParams)
         renderer.run()
     except PodError, pe:
         if not os.path.exists(result):
             # In some (most?) cases, when OO returns an error, the result is
             # nevertheless generated.
             obj.log(str(pe).strip(), type="error")
             return Pod.POD_ERROR
Example #18
0
 def __init__(self, fileOrFolder, keyword):
     self.fileOrFolder = fileOrFolder
     self.keyword = keyword
     self.tempFolder = getOsTempFolder()
Example #19
0
 def __init__(self, fileOrFolder, script):
     self.fileOrFolder = fileOrFolder
     self.script = script
     self.tempFolder = getOsTempFolder()
Example #20
0
 def getValue(self, obj):
     '''Gets, on_obj, the value conforming to self's type definition. For a
        Pod field, if a file is stored in the field, it means that the
        field has been frozen. Else, it means that the value must be
        retrieved by calling pod to compute the result.'''
     rq = getattr(obj, 'REQUEST', None)
     res = getattr(obj.aq_base, self.name, None)
     if res and res.size:
         # Return the frozen file.
         return sutils.FileWrapper(res)
     # If we are here, it means that we must call pod to compute the file.
     # A Pod field differs from other field types because there can be
     # several ways to produce the field value (ie: output file format can be
     # odt, pdf,...; self.action can be executed or not...). We get those
     # precisions about the way to produce the file from the request object
     # and from the tool. If we don't find the request object (or if it does
     # not exist, ie, when Zope runs in test mode), we use default values.
     obj = obj.appy()
     tool = obj.tool
     # Get POD template and available formats from the tool.
     template, availFormats = self.getToolInfo(obj)
     # Get the output format
     defaultFormat = 'pdf'
     if defaultFormat not in availFormats: defaultFormat = availFormats[0]
     outputFormat = getattr(rq, 'podFormat', defaultFormat)
     # Get or compute the specific POD context
     specificContext = None
     if callable(self.context):
         specificContext = self.callMethod(obj, self.context)
     else:
         specificContext = self.context
     # Temporary file where to generate the result
     tempFileName = '%s/%s_%f.%s' % (sutils.getOsTempFolder(), obj.uid,
                                     time.time(), outputFormat)
     # Define parameters to give to the appy.pod renderer
     podContext = {
         'tool': tool,
         'user': obj.user,
         'self': obj,
         'field': self,
         'now': obj.o.getProductConfig().DateTime(),
         '_': obj.translate,
         'projectFolder': tool.getDiskFolder()
     }
     # If the POD document is related to a query, get it from the request,
     # execute it and put the result in the context.
     isQueryRelated = rq.get('queryData', None)
     if isQueryRelated:
         # Retrieve query params from the request
         cmd = ', '.join(tool.o.queryParamNames)
         cmd += " = rq['queryData'].split(';')"
         exec cmd
         # (re-)execute the query, but without any limit on the number of
         # results; return Appy objects.
         objs = tool.o.executeQuery(obj.o.portal_type,
                                    searchName=search,
                                    sortBy=sortKey,
                                    sortOrder=sortOrder,
                                    filterKey=filterKey,
                                    filterValue=filterValue,
                                    maxResults='NO_LIMIT')
         podContext['objects'] = [o.appy() for o in objs['objects']]
     # Add the field-specific context if present.
     if specificContext:
         podContext.update(specificContext)
     # If a custom param comes from the request, add it to the context. A
     # custom param must have format "name:value". Custom params override any
     # other value in the request, including values from the field-specific
     # context.
     customParams = rq.get('customParams', None)
     if customParams:
         paramsDict = eval(customParams)
         podContext.update(paramsDict)
     # Define a potential global styles mapping
     if callable(self.stylesMapping):
         stylesMapping = self.callMethod(obj, self.stylesMapping)
     else:
         stylesMapping = self.stylesMapping
     rendererParams = {
         'template': StringIO.StringIO(template.content),
         'context': podContext,
         'result': tempFileName,
         'stylesMapping': stylesMapping,
         'imageResolver': tool.o.getApp()
     }
     if tool.unoEnabledPython:
         rendererParams['pythonWithUnoPath'] = tool.unoEnabledPython
     if tool.openOfficePort:
         rendererParams['ooPort'] = tool.openOfficePort
     # Launch the renderer
     try:
         renderer = Renderer(**rendererParams)
         renderer.run()
     except PodError, pe:
         if not os.path.exists(tempFileName):
             # In some (most?) cases, when OO returns an error, the result is
             # nevertheless generated.
             obj.log(str(pe), type='error')
             return Pod.POD_ERROR
Example #21
0
 def getValue(self, obj, template=None, format=None, result=None,
              queryData=None, customParams=None, noSecurity=False):
     '''For a pod field, getting its value means computing a pod document or
        returning a frozen one. A pod field differs from other field types
        because there can be several ways to produce the field value (ie:
        self.template can hold various templates; output file format can be
        odt, pdf,.... We get those precisions about the way to produce the
        file, either from params, or from default values.
        * p_template is the specific template, among self.template, that must
          be used as base for generating the document;
        * p_format is the output format of the resulting document;
        * p_result, if given, must be the absolute path of the document that
          will be computed by pod. If not given, pod will produce a doc in
          the OS temp folder;
        * if the pod document is related to a query, the query parameters
          needed to re-trigger the query are given in p_queryData;
        * p_customParams may be specified. Every custom param must have form
          "name:value". Custom params override any other value available in
          the context, including values from the field-specific context.
     '''
     obj = obj.appy()
     template = template or self.template[0]
     format = format or 'odt'
     # Security check.
     if not noSecurity and not queryData:
         if self.showTemplate and not self.showTemplate(obj, template):
             raise Exception(self.UNAUTHORIZED)
     # Return the possibly frozen document (not applicable for query-related
     # pods).
     if not queryData:
         frozen = self.isFrozen(obj, template, format)
         if frozen:
             fileName = self.getDownloadName(obj, template, format, False)
             return FileInfo(frozen, inDb=False, uploadName=fileName)
     # We must call pod to compute a pod document from "template".
     tool = obj.tool
     diskFolder = tool.getDiskFolder()
     # Get the path to the pod template.
     templatePath = os.path.join(diskFolder, template)
     if not os.path.isfile(templatePath):
         raise Exception(self.TEMPLATE_NOT_FOUND % templatePath)
     # Get or compute the specific POD context
     specificContext = None
     if callable(self.context):
         specificContext = self.callMethod(obj, self.context)
     else:
         specificContext = self.context
     # Compute the name of the result file.
     if not result:
         result = '%s/%s_%f.%s' % (sutils.getOsTempFolder(),
                                   obj.uid, time.time(), format)
     # Define parameters to give to the appy.pod renderer
     podContext = {'tool': tool, 'user': obj.user, 'self': obj, 'field':self,
                   'now': obj.o.getProductConfig().DateTime(),
                   '_': obj.translate, 'projectFolder': diskFolder}
     # If the pod document is related to a query, re-trigger it and put the
     # result in the pod context.
     if queryData:
         # Retrieve query params
         cmd = ', '.join(tool.o.queryParamNames)
         cmd += " = queryData.split(';')"
         exec cmd
         # (re-)execute the query, but without any limit on the number of
         # results; return Appy objects.
         objs = tool.o.executeQuery(obj.o.portal_type, searchName=search,
                  sortBy=sortKey, sortOrder=sortOrder, filterKey=filterKey,
                  filterValue=filterValue, maxResults='NO_LIMIT')
         podContext['objects'] = [o.appy() for o in objs.objects]
     # Add the field-specific context if present.
     if specificContext:
         podContext.update(specificContext)
     # If a custom param comes from the request, add it to the context.
     if customParams:
         paramsDict = eval(customParams)
         podContext.update(paramsDict)
     # Define a potential global styles mapping
     if callable(self.stylesMapping):
         stylesMapping = self.callMethod(obj, self.stylesMapping)
     else:
         stylesMapping = self.stylesMapping
     rendererParams = {'template': templatePath, 'context': podContext,
                       'result': result, 'stylesMapping': stylesMapping,
                       'imageResolver': tool.o.getApp(),
                       'overwriteExisting': True}
     if tool.unoEnabledPython:
         rendererParams['pythonWithUnoPath'] = tool.unoEnabledPython
     if tool.openOfficePort:
         rendererParams['ooPort'] = tool.openOfficePort
     # Launch the renderer
     try:
         renderer = Renderer(**rendererParams)
         renderer.run()
     except PodError, pe:
         if not os.path.exists(result):
             # In some (most?) cases, when OO returns an error, the result is
             # nevertheless generated.
             obj.log(str(pe).strip(), type='error')
             return Pod.POD_ERROR
Example #22
0
 def getValue(self, obj):
     '''Gets, on_obj, the value conforming to self's type definition. For a
        Pod field, if a file is stored in the field, it means that the
        field has been frozen. Else, it means that the value must be
        retrieved by calling pod to compute the result.'''
     rq = getattr(obj, 'REQUEST', None)
     res = getattr(obj.aq_base, self.name, None)
     if res and res.size:
         # Return the frozen file.
         return sutils.FileWrapper(res)
     # If we are here, it means that we must call pod to compute the file.
     # A Pod field differs from other field types because there can be
     # several ways to produce the field value (ie: output file format can be
     # odt, pdf,...; self.action can be executed or not...). We get those
     # precisions about the way to produce the file from the request object
     # and from the tool. If we don't find the request object (or if it does
     # not exist, ie, when Zope runs in test mode), we use default values.
     obj = obj.appy()
     tool = obj.tool
     # Get POD template and available formats from the tool.
     template, availFormats = self.getToolInfo(obj)
     # Get the output format
     defaultFormat = 'pdf'
     if defaultFormat not in availFormats: defaultFormat = availFormats[0]
     outputFormat = getattr(rq, 'podFormat', defaultFormat)
     # Get or compute the specific POD context
     specificContext = None
     if callable(self.context):
         specificContext = self.callMethod(obj, self.context)
     else:
         specificContext = self.context
     # Temporary file where to generate the result
     tempFileName = '%s/%s_%f.%s' % (
         sutils.getOsTempFolder(), obj.uid, time.time(), outputFormat)
     # Define parameters to give to the appy.pod renderer
     podContext = {'tool': tool, 'user': obj.user, 'self': obj, 'field':self,
                   'now': obj.o.getProductConfig().DateTime(),
                   '_': obj.translate, 'projectFolder': tool.getDiskFolder()}
     # If the POD document is related to a query, get it from the request,
     # execute it and put the result in the context.
     isQueryRelated = rq.get('queryData', None)
     if isQueryRelated:
         # Retrieve query params from the request
         cmd = ', '.join(tool.o.queryParamNames)
         cmd += " = rq['queryData'].split(';')"
         exec cmd
         # (re-)execute the query, but without any limit on the number of
         # results; return Appy objects.
         objs = tool.o.executeQuery(obj.o.portal_type, searchName=search,
                  sortBy=sortKey, sortOrder=sortOrder, filterKey=filterKey,
                  filterValue=filterValue, maxResults='NO_LIMIT')
         podContext['objects'] = [o.appy() for o in objs['objects']]
     # Add the field-specific context if present.
     if specificContext:
         podContext.update(specificContext)
     # If a custom param comes from the request, add it to the context. A
     # custom param must have format "name:value". Custom params override any
     # other value in the request, including values from the field-specific
     # context.
     customParams = rq.get('customParams', None)
     if customParams:
         paramsDict = eval(customParams)
         podContext.update(paramsDict)
     # Define a potential global styles mapping
     if callable(self.stylesMapping):
         stylesMapping = self.callMethod(obj, self.stylesMapping)
     else:
         stylesMapping = self.stylesMapping
     rendererParams = {'template': StringIO.StringIO(template.content),
                       'context': podContext, 'result': tempFileName,
                       'stylesMapping': stylesMapping,
                       'imageResolver': tool.o.getApp()}
     if tool.unoEnabledPython:
         rendererParams['pythonWithUnoPath'] = tool.unoEnabledPython
     if tool.openOfficePort:
         rendererParams['ooPort'] = tool.openOfficePort
     # Launch the renderer
     try:
         renderer = Renderer(**rendererParams)
         renderer.run()
     except PodError, pe:
         if not os.path.exists(tempFileName):
             # In some (most?) cases, when OO returns an error, the result is
             # nevertheless generated.
             obj.log(str(pe), type='error')
             return Pod.POD_ERROR