def main(): if len(sys.argv) < 2: print 'Usage: %s [version] [--install] [--local|username password]' % sys.argv[0] print 'Where [version] is the branch you want to checkout' print 'and username and password are for your eduforge account' print 'Eg. %s 0.7 --local' % sys.argv[0] else: version = sys.argv[1] branch = 'http://exe.cfdl.auckland.ac.nz/svn/exe/branches/%s' % version origDir = Path(sys.argv[0]).abspath().dirname() tmp = TempDirPath() os.chdir(tmp) os.system('svn export %s exe' % branch) (origDir/'../../exe/webui/firefox').copytree(tmp/'exe/exe/webui/firefox') os.chdir(tmp/'exe') tarball = Path('../exe-%s-source.tgz' % version).abspath() os.system('tar czf %s *' % tarball) os.chdir(tmp) if '--local' not in sys.argv: try: from paramiko import Transport except ImportError: print 'To upload you need to install paramiko python library from:' print 'http://www.lag.net/paramiko' sys.exit(2) from socket import socket, gethostbyname s = socket() s.connect((gethostbyname('shell.eduforge.org'), 22)) t = Transport(s) t.connect() t.auth_password(sys.argv[-2], sys.argv[-1]) f = t.open_sftp_client() f.chdir('/home/pub/exe') f.put(tarball.encode('utf8'), tarball.basename().encode('utf8')) if os.getuid() == 0: tarball.copyfile('/usr/portage/distfiles/' + tarball.basename()) os.chdir(tmp/'exe/installs/gentoo') newEbuildFilename = Path('exe-%s.ebuild' % version).abspath() if not newEbuildFilename.exists(): Path('exe-0.7.ebuild').copy(newEbuildFilename) if os.getuid() == 0: ebuildDir = Path('/usr/local/portage/dev-python/exe') if ebuildDir.exists(): ebuildDir.rmtree() ebuildDir.makedirs() os.chdir(ebuildDir) newEbuildFilename.copy(ebuildDir) filesDir = ebuildDir/'files' filesDir.makedirs() Path(tmp/'exe/installs/gentoo/all-config.patch').copy(filesDir) if '--local' not in sys.argv: oldTarball = Path('/usr/portage/distfiles/')/tarball.basename() if oldTarball.exists(): oldTarball.remove() os.environ['GENTOO_MIRRORS']='' os.system('ebuild %s fetch' % newEbuildFilename.basename()) os.system('ebuild %s manifest' % newEbuildFilename.basename()) os.system('ebuild %s digest' % newEbuildFilename.basename()) if '--install' in sys.argv: os.system('ebuild %s install' % newEbuildFilename.basename())
def renderEdit(self, style): """ Returns an XHTML string with the form element for editing this block """ html = u'<div><div class="block">' html += common.textInput("title" + self.id, self.idevice.title) html += common.hiddenField("iconiDevice" + self.id, self.idevice.icon) html += u'<a class="js-show-icon-panel-button" href="javascript:showMessageBox(\'iconpanel\');">%s</a>' % _( 'Select an icon') # Get icon source (if it exists) icon = self.idevice.icon icon_exists = False if icon != '': idevice_icon = Path(G.application.config.stylesDir / style / 'icon_' + self.idevice.icon + '.gif') if idevice_icon.exists(): icon_exists = True else: idevice_icon = Path(G.application.config.stylesDir / style / "icon_" + self.idevice.icon + ".png") if idevice_icon.exists(): icon_exists = True # Icon HTML element html += u'<img class="js-idevide-icon-preview" name="iconiDevice%s" id="iconiDevice"' % ( self.id) if icon_exists: html += u' src="/style/%s/icon_%s%s"' % (style, icon, idevice_icon.ext) else: html += u' src="/images/empty.gif"' html += u'/>' # Delete button html += u'<a href="javascript:deleteIcon(%s);" id="deleteIcon%s" class="deleteIcon" title="%s"' % ( self.id, self.id, _('Delete')) # If the icon doesn't exists if not icon_exists: html += u' style="display: none;"' html += u'>' html += u'<img class="js-delete-icon" alt="%s" src="%s"/>' % ( _('Delete'), '/images/stock-delete.png') html += u'</a>' html += u'<div class="js-icon-panel-container">' html += u'<div id="iconpaneltitle">%s</div>' % _("Icons") html += u'<div id="iconpanelcontent">' html += self.__renderIcons(style) html += u'</div>' html += u'</div>' html += u"</div>" for element in self.elements: html += element.renderEdit() + u'<br />' html += self.renderEditButtons() html += u"</div>" return html
def getResourcesList(self, editMode=False, ordered=True, appendPath=True): """ Get a list of the iDevice resources """ resources = list() # Check export resources export_resources_path = Path(self.get_jsidevice_dir()) / 'export' if export_resources_path.exists(): for res in os.listdir(export_resources_path): if appendPath: resources.append( str( Path(self.get_jsidevice_dir()).basename() + '/export/' + res)) else: resources.append(str(res)) # Check edition resources edition_resources_path = Path(self.get_jsidevice_dir()) / 'edition' if (editMode) and edition_resources_path.exists(): for res in os.listdir(edition_resources_path): if appendPath: resources.append( str( Path(self.get_jsidevice_dir()).basename() + '/edition/' + res)) else: resources.append(str(res)) # Order the list if (ordered): resources.sort(key=lambda x: x.split('/')[-1]) return resources
def do_export(self, inputf, outputf): if hasattr(self, 'export_' + self.options["export"]): LOG.debug("Exporting to type %s, in: %s, out: %s, overwrite: %s" \ % (self.options["export"], inputf, outputf, str(self.options["overwrite"]))) if not outputf: if self.options["export"] in ('website', 'singlepage'): outputf = inputf.rsplit(".elp")[0] else: outputf = inputf + self.extensions[self.options["export"]] outputfp = Path(outputf) if outputfp.exists() and not self.options["overwrite"]: error = _(u'"%s" already exists.\nPlease try again \ with a different filename') % outputf raise Exception(error.encode(sys.stdout.encoding)) else: if outputfp.exists() and self.options["overwrite"]: if outputfp.isdir(): for filen in outputfp.walkfiles(): filen.remove() outputfp.rmdir() else: outputfp.remove() pkg = Package.load(inputf) LOG.debug("Package %s loaded" % (inputf)) if not pkg: error = _(u"Invalid input package") raise Exception(error.encode(sys.stdout.encoding)) self.styles_dir = self.web_dir.joinpath('style', pkg.style) LOG.debug("Styles dir: %s" % (self.styles_dir)) getattr(self, 'export_' + self.options["export"])(pkg, outputf) return outputf else: raise Exception(_(u"Export format not implemented")\ .encode(sys.stdout.encoding))
def _checkValid(self): config = Path(self._iDeviceDir) / 'config.xml' edition = Path(self._iDeviceDir) / 'edition' export = Path(self._iDeviceDir) / 'export' if config.exists() and edition.exists() and export.exists(): self._valid = True else: self._valid = False
def _checkValid(self): config = Path(self.get_jsidevice_dir()) / 'config.xml' edition = Path(self.get_jsidevice_dir()) / 'edition' if config.exists() and edition.exists(): self._valid = True else: self._valid = False
def renderEdit(self, style): """ Returns an XHTML string with the form element for editing this block """ html = u'<div>' html += '<span class="js-idevice-title-label">' html += '<label for="title'+self.id+'">'+_('Title')+':</label> ' html += common.elementInstruc(_('The title and the icon are not required. If you leave them empty the iDevice will have no emphasis.')) html += '</span>' html += common.hiddenField("iconiDevice" + self.id, self.idevice.icon) html += u'<a class="js-show-icon-panel-button" href="javascript:showMessageBox(\'iconpanel\');" title="%s"><img src="/images/stock-insert-image.png" alt="%s" width="16" height="16" /></a>' % (_('Select an icon'),_('Choose an Image')) # Get icon source (if it exists) icon = self.idevice.icon icon_exists = False if icon != '': idevice_icon = Path(G.application.config.stylesDir / style / 'icon_' + self.idevice.icon + '.gif') if idevice_icon.exists(): icon_exists = True else: idevice_icon = Path(G.application.config.stylesDir/style/"icon_" + self.idevice.icon + ".png") if idevice_icon.exists(): icon_exists = True # Icon HTML element html += u'<img class="js-idevide-icon-preview" name="iconiDevice%s" id="iconiDevice"' % (self.id) if icon_exists: html += u' src="/style/%s/icon_%s%s"' % (style, icon, idevice_icon.ext) else: html += u' src="/images/empty.gif"' html += u'/>' # Delete button html += u'<a href="javascript:deleteIcon(%s);" id="deleteIcon%s" class="deleteIcon" title="%s"' % (self.id, self.id, _('Delete')) # If the icon doesn't exists if not icon_exists: html += u' style="display: none;"' html += u'>' html += u'<img class="js-delete-icon" alt="%s" src="%s"/>' % (_('Delete'), '/images/stock-delete.png') html += u'</a>' html += common.textInput("title" + self.id, self.idevice.title) html += u'<div class="js-icon-panel-container">' html += u'<div id="iconpaneltitle">%s</div>' % _("Icons") html += u'<div id="iconpanelcontent">' html += self.__renderIcons(style) html += u'</div>' html += u"</div>" for element in self.elements: html += element.renderEdit() html += self.renderEditButtons() html += u"</div>" return html
def __renderIcons(self, style): """ Return xhtml string for dispay all icons """ iconpath = Path(G.application.config.stylesDir / style) iconfiles = iconpath.files("icon_*") html = '<div id="styleIcons"><div style="height:300px;overflow:auto">' for iconfile in iconfiles: iconname = iconfile.namebase icon = iconname.split("_", 1)[1] iconExists = False iconExtension = "gif" myIcon = Path(G.application.config.stylesDir / style / iconname + ".gif") if myIcon.exists(): iconExists = True iconValue = icon + '.' + iconExtension iconSrc = '/style/%s/icon_%s' % (style, iconValue) else: myIcon = Path(G.application.config.stylesDir / style / iconname + ".png") if myIcon.exists(): iconExists = True iconExtension = "png" iconValue = icon + '.' + iconExtension iconSrc = '/style/%s/icon_%s' % (style, iconValue) else: myIcon = Path(G.application.config.stylesDir / style / iconname + ".svg") if myIcon.exists(): iconExists = True iconExtension = "svg" iconValue = icon + '.' + iconExtension iconSrc = '/style/%s/icon_%s' % (style, iconValue) if iconExists: filename = "/style/%s/%s.%s" % (style, iconname, iconExtension) html += u'<div style="float:left; text-align:center; width:105px;\n' html += u'margin-right:10px; margin-bottom:15px" > ' html += u'<img src="%s" \n' % filename html += u"style=\"border:1px solid #E8E8E8;padding:5px;cursor:pointer;max-width:60px;height:auto\" onclick=\"window[0].selectStyleIcon('%s',this, '%s', '%s')\" title=\"%s.%s\">\n" % ( icon, iconSrc, self.id, icon, iconExtension) html += u'<br /><span style="display:inline-block;width:100px;overflow:hidden;text-overflow:ellipsis">%s.%s</span></div>\n' % ( icon, iconExtension) html += '</div></div>' return html
def __renderIcons(self): """ Return xhtml string for dispay all icons """ iconpath = self.style.get_style_dir() iconfiles = iconpath.files("icon_*") html = '<div id="styleIcons"><div style="height:300px;overflow:auto">' for iconfile in iconfiles: iconname = iconfile.namebase icon = iconname.split("_", 1)[1] iconExists = False iconExtension = "gif" myIcon = Path(G.application.config.stylesDir / self.style.get_dirname() / iconname + ".gif") if myIcon.exists(): iconExists = True else: myIcon = Path(G.application.config.stylesDir / self.style.get_dirname() / iconname + ".png") if myIcon.exists(): iconExists = True iconExtension = "png" else: myIcon = Path(G.application.config.stylesDir / self.style.get_dirname() / iconname + ".svg") if myIcon.exists(): iconExists = True iconExtension = "svg" if iconExists: filename = "/style/%s/%s.%s" % (self.style.get_dirname(), iconname, iconExtension) html += u'<div style="float:left; text-align:center; width:105px;\n' html += u'margin-right:10px; margin-bottom:15px" > ' html += u'<img src="%s" \n' % filename # html += u' alt="%s" ' % _("Submit") # window[1] because we use Ext.MessageBox instead of libot_drag.js html += u"style=\"border:1px solid #E8E8E8;padding:5px;cursor:pointer;max-width:60px;max-height:60px;height:auto\" onclick=\"window[1].selectStyleIcon('%s',this)\" title=\"%s.%s\">\n" % ( icon, icon, iconExtension) # html += u"style=\"cursor:pointer\" onclick=\"window[1].submitLink('selectIcon','%s',1)\">\n" % icon html += u'<br /><span style="display:inline-block;width:100px;overflow:hidden;text-overflow:ellipsis">%s.%s</span></div>\n' % ( icon, iconExtension) html += '</div></div>' return html
def main(): if len(sys.argv) < 2: print 'Usage: %s [version]' % sys.argv[0] print 'Where [version] is the branch you want to checkout' print 'Eg. %s 0.7' % sys.argv[0] else: version = sys.argv[1] branch = 'http://exe.cfdl.auckland.ac.nz/svn/exe/branches/%s' % version origDir = Path(sys.argv[0]).abspath().dirname() tmp = TempDirPath() os.chdir(tmp) os.system('svn export %s exe' % branch) (origDir/'../../exe/webui/firefox').copytree(tmp/'exe/exe/webui/firefox') os.chdir(tmp/'exe') tarball = Path('../exe-%s-source.tgz' % version).abspath() os.system('tar czf %s *' % tarball) os.chdir(tmp) if '--local' not in sys.argv: open('sftpbatch.tmp', 'w').write( 'cd /home/pub/exe\n' 'put %s\n' % tarball) os.system('sftp -b sftpbatch.tmp [email protected]') if os.getuid() == 0: tarball.copyfile('/usr/portage/distfiles/' + tarball.basename()) os.chdir(tmp/'exe/installs/gentoo') newEbuildFilename = Path('exe-%s.ebuild' % version).abspath() if not newEbuildFilename.exists(): Path('exe-0.7.ebuild').copy(newEbuildFilename) if os.getuid() == 0: ebuildDir = Path('/usr/local/portage/dev-python/exe') if ebuildDir.exists(): ebuildDir.rmtree() ebuildDir.makedirs() os.chdir(ebuildDir) newEbuildFilename.copy(ebuildDir) filesDir = ebuildDir/'files' filesDir.makedirs() Path(tmp/'exe/installs/gentoo/all-config.patch').copy(filesDir) if '--local' not in sys.argv: oldTarball = Path('/usr/portage/distfiles/')/tarball.basename() if oldTarball.exists(): oldTarball.remove() os.environ['GENTOO_MIRRORS']='' os.system('ebuild %s fetch' % newEbuildFilename.basename()) os.system('ebuild %s manifest' % newEbuildFilename.basename()) os.system('ebuild %s digest' % newEbuildFilename.basename()) if '--install' in sys.argv: os.system('ebuild %s install' % newEbuildFilename.basename())
def doTest(self, ExporterClass): """Exports a package with meta data""" # Load our test package package = Package.load('testPackage.elp') # Do the export outFilename = Path('scormtest.zip') exporter = ExporterClass(self.app.config, '../exe/webui/style/default', outFilename) exporter.export(package) # Check that it made a nice zip file assert outFilename.exists() # See if the manifest file was created zipped = ZipFile(outFilename) filenames = zipped.namelist() assert 'imsmanifest.xml' in filenames, filenames self._testManifest(zipped.read('imsmanifest.xml')) # Test that all the node's html files have been generated pagenodes = Set([p.node for p in exporter.pages]) othernodes = Set(self._getNodes([], package.root)) assert pagenodes == othernodes for page in exporter.pages: self._testPage(page, zipped) # Clean up zipped.close()
def makePO(applicationDirectoryPath, applicationDomain=None, verbose=1) : """Build the Portable Object Template file for the application. makePO builds the .pot file for the application stored inside a specified directory by running xgettext for all application source files. It finds the name of all files by looking for a file called 'app.fil'. If this file does not exists, makePo raises an IOError exception. By default the application domain (the application name) is the same as the directory name but it can be overridden by the 'applicationDomain' argument. makePO always creates a new file called messages.pot. If it finds files of the form app_xx.po where 'app' is the application name and 'xx' is one of the ISO 639 two-letter language codes, makePO resynchronizes those files with the latest extracted strings (now contained in messages.pot). This process updates all line location number in the language-specific .po files and may also create new entries for translation (or comment out some). The .po file is not changed, instead a new file is created with the .new extension appended to the name of the .po file. By default the function does not display what it is doing. Set the verbose argument to 1 to force it to print its commands. """ if applicationDomain is None: applicationName = fileBaseOf(applicationDirectoryPath,withPath=0) else: applicationName = applicationDomain currentDir = os.getcwd() messages_pot = Path('exe/locale/messages.pot') # Use xgettext to make the base messages.pot (with header, etc.) if messages_pot.exists(): messages_pot.remove() messages_pot.touch() cmd = 'xgettext -kx_ -s -j --no-wrap --output=exe/locale/messages.pot --from-code=utf8 exe/engine/package.py' if verbose: print cmd os.system(cmd) if not os.path.exists('app.fil'): raise IOError(2,'No module file: app.fil') # Steps: # Use xgettext to parse all application modules # The following switches are used: # # -s : sort output by string content (easier to use when we need to merge several .po files) # --files-from=app.fil : The list of files is taken from the file: app.fil # --output= : specifies the name of the output file (using a .pot extension) cmd = 'xgettext -kx_ -s -j --no-wrap --output=exe/locale/messages.pot --from-code=utf8 %s' if verbose: print cmd for fn in open('app.fil'): print 'Extracting from', fn, os.system(cmd % fn[:-1]) makeXulPO(applicationDirectoryPath, applicationDomain, verbose) # Merge new pot with .po files localeDirs = Path('exe/locale') for filename in localeDirs.walkfiles('*_*.po'): cmd = "msgmerge -U --no-wrap %s exe/locale/messages.pot" % filename if verbose: print cmd os.system(cmd)
def handleExternalResources(self, html): html_content_lower = html.lower() start_index = 0 start_index = self._findNextTagStart(html_content_lower, start_index, ['img']) while start_index != -1: res_src = self._getSrcForTag(html, start_index) if res_src is not None and res_src.startswith("http://"): new_file_basename = self.url2ascii(res_src) new_file_name = str(self.workingDir/new_file_basename) new_file_path = Path(self.workingDir/new_file_basename) if new_file_path.exists() is False: urllib.urlretrieve(res_src, new_file_name) old_length = len(html) html = html.replace(res_src, new_file_name) html_content_lower = html.lower() new_length = len(html) length_difference = old_length - new_length start_index += length_difference end_tag_index = html_content_lower.find(">", start_index); start_index = self._findNextTagStart(html_content_lower,end_tag_index , ['img']) return html
def testUpgradeAppDir(self): """ Tests that config files with 'appDataDir' are upgraded to 'configDir' """ # Write the old style config file configPath = Path(u'test.exe.conf') if configPath.exists(): configPath.remove() oldParser = ConfigParser() system = oldParser.addSection('system') system.appDataDir = 'my old app data dir' oldParser.write(configPath) del system del oldParser # Make the config instance load it Config._getConfigPathOptions = lambda self: ['test.exe.conf'] myconfig = Config() myconfig.loadSettings() # Check if it reads the old value into the new variable assert not hasattr(myconfig, 'appDataDir') self.assertEquals(myconfig.configPath, 'test.exe.conf') self.assertEquals(myconfig.configDir, 'my old app data dir') # Check if it has upgraded the file and added in some nice default values newParser = ConfigParser() newParser.read(configPath) self.assertEquals(newParser.system.configDir, 'my old app data dir')
def exportIpod(self, client, filename): """ Export 'client' to an iPod Notes folder tree 'webDir' is just read from config.webDir """ try: # filename is a directory where we will export the notes to # We assume that the user knows what they are doing # and don't check if the directory is already full or not # and we just overwrite what's already there filename = Path(filename) # Append the package name to the folder path if necessary if filename.basename() != self.package.name: filename /= self.package.name if not filename.exists(): filename.makedirs() elif not filename.isdir(): client.alert( _(u'Filename %s is a file, cannot replace it') % filename) log.error("Couldn't export web page: " + "Filename %s is a file, cannot replace it" % filename) return else: client.alert( _(u'Folder name %s already exists. ' 'Please choose another one or delete existing one then try again.' ) % filename) return # Now do the export ipodExport = IpodExport(self.config, filename) ipodExport.export(self.package) except Exception, e: client.alert(_('EXPORT FAILED!\n%s') % str(e)) raise
def makeXulPO(applicationDirectoryPath, applicationDomain=None, verbose=0): """Searches through xul files and appends to messages.pot""" if verbose: print "Importing xul templates..." path = Path(applicationDirectoryPath) messages = pot2dict('exe/locale/messages.pot') messageCommentTemplate = '\n#: %s:%s\nmsgid "' seq = len(messages) skipPaths = (applicationDirectoryPath / 'exe/webui/firefox', ) for fn in path.walkfiles(): if fn.ext.lower() == '.xul': for skipPath in skipPaths: if fn.startswith(skipPath): print 'IGNORING', fn break else: if verbose: print "template: ", fn reader = Sax2.Reader() doc = reader.fromStream(file(fn, 'rb')) xul2dict(doc, messages, seq, fn.relpath()) pot = Path('exe/locale/messages.pot') if pot.exists(): pot.remove() pot.touch() dict2pot(messages, 'exe/locale/messages.pot')
def _setupConfigFile(self, configParser): """ Override this to setup any customised config settings """ # Set up the system section system = configParser.addSection('system') system.exePath = 'exe/exe' system.exeDir = 'exe' system.webDir = 'exe/webui' system.localeDir = 'exe/locale' system.configDir = 'tmp' system.port = 8081 # Make a temporary dir where we can save packages and exports etc tmpDir = Path('tmp') if not tmpDir.exists(): tmpDir.mkdir() dataDir = tmpDir / 'data' if not dataDir.exists(): dataDir.mkdir() system.dataDir = dataDir system.browserPath = 'not really used in tests so far' # Setup the logging section logging = configParser.addSection('logging') logging.root = 'DEBUG'
def exportWebSite(self, client, filename, webDir, stylesDir): """ Export 'client' to a web site, 'webDir' is just read from config.webDir 'stylesDir' is where to copy the style sheet information from """ imagesDir = webDir.joinpath('images') scriptsDir = webDir.joinpath('scripts') templatesDir = webDir.joinpath('templates') filename = Path(filename) if filename.basename() != self.package.name: filename /= self.package.name if not filename.exists(): filename.makedirs() elif not filename.isdir(): client.alert(_(u'Filename %s is a file, cannot replace it') % filename) log.error("Couldn't export web page: "+ "Filename %s is a file, cannot replace it" % filename) return else: filename.rmtree() filename.mkdir() websiteExport = WebsiteExport(stylesDir, filename, imagesDir, scriptsDir, templatesDir) websiteExport.export(self.package) self._startFile(filename)
def launchBrowser(config, packageName): """ Launch the configured webbrowser for this platform """ url = u'%s/%s' % (G.application.exeAppUri, quote(packageName)) log.info(u"url " + url) dfbrw=mywebbrowser.get() withdefaultbrowser=True if config.browser!=None: try: config.browser = mywebbrowser.get(config.browser) if not config.browser.open(url): log.error("Unable to open defined browser: " + config.browser.name) withdefaultbrowser = True else: withdefaultbrowser = False except: browser_path = Path(config.browser) if browser_path.exists(): log.info(u"path browser " + browser_path.abspath()) mywebbrowser.register("custom-browser" , None, mywebbrowser.BackgroundBrowser(browser_path.abspath()), -1) config.browser = mywebbrowser.get("custom-browser") if not config.browser.open(url): log.error("Unable to open custom defined browser: " + browser_path.abspath()) withdefaultbrowser=True else: withdefaultbrowser=False if withdefaultbrowser: config.browser = dfbrw config.browser.open(url, new=0, autoraise=True) if hasattr(config.browser, "name"): log.info(u"Defined Browser: " + config.browser.name)
def makePO(applicationDirectoryPath, applicationDomain=None, verbose=1): """Build the Portable Object Template file for the application. makePO builds the .pot file for the application stored inside a specified directory by running xgettext for all application source files. It finds the name of all files by looking for a file called 'app.fil'. If this file does not exists, makePo raises an IOError exception. By default the application domain (the application name) is the same as the directory name but it can be overridden by the 'applicationDomain' argument. makePO always creates a new file called messages.pot. If it finds files of the form app_xx.po where 'app' is the application name and 'xx' is one of the ISO 639 two-letter language codes, makePO resynchronizes those files with the latest extracted strings (now contained in messages.pot). This process updates all line location number in the language-specific .po files and may also create new entries for translation (or comment out some). The .po file is not changed, instead a new file is created with the .new extension appended to the name of the .po file. By default the function does not display what it is doing. Set the verbose argument to 1 to force it to print its commands. """ if applicationDomain is None: applicationName = fileBaseOf(applicationDirectoryPath, withPath=0) else: applicationName = applicationDomain currentDir = os.getcwd() messages_pot = Path('exe/locale/messages.pot') # Use xgettext to make the base messages.pot (with header, etc.) if messages_pot.exists(): messages_pot.remove() messages_pot.touch() cmd = 'xgettext -kx_ -s -j --no-wrap --output=exe/locale/messages.pot --from-code=utf8 exe/engine/package.py' if verbose: print cmd os.system(cmd) if not os.path.exists('app.fil'): raise IOError(2, 'No module file: app.fil') # Steps: # Use xgettext to parse all application modules # The following switches are used: # # -s : sort output by string content (easier to use when we need to merge several .po files) # --files-from=app.fil : The list of files is taken from the file: app.fil # --output= : specifies the name of the output file (using a .pot extension) cmd = 'xgettext -kx_ -L Python -s -j --no-wrap --output=exe/locale/messages.pot --from-code=utf8 %s' if verbose: print cmd for fn in open('app.fil'): print 'Extracting from', fn, os.system(cmd % fn[:-1]) makeXulPO(applicationDirectoryPath, applicationDomain, verbose) # Merge new pot with .po files localeDirs = Path('exe/locale') for filename in localeDirs.walkfiles('*_*.po'): cmd = "msgmerge -U --no-wrap -N %s exe/locale/messages.pot" % filename if verbose: print cmd os.system(cmd)
def exportIpod(self, client, filename): """ Export 'client' to an iPod Notes folder tree 'webDir' is just read from config.webDir """ try: # filename is a directory where we will export the notes to # We assume that the user knows what they are doing # and don't check if the directory is already full or not # and we just overwrite what's already there filename = Path(filename) # Append the package name to the folder path if necessary if filename.basename() != self.package.name: filename /= self.package.name if not filename.exists(): filename.makedirs() elif not filename.isdir(): client.alert(_(u'Filename %s is a file, cannot replace it') % filename) log.error("Couldn't export web page: "+ "Filename %s is a file, cannot replace it" % filename) return else: client.alert(_(u'Folder name %s already exists. ' 'Please choose another one or delete existing one then try again.') % filename) return # Now do the export ipodExport = IpodExport(self.config, filename) ipodExport.export(self.package) except Exception, e: client.alert(_('EXPORT FAILED!\n%s') % str(e)) raise
def makeXulPO(applicationDirectoryPath, applicationDomain=None, verbose=0): """Searches through xul files and appends to messages.pot""" if verbose: print "Importing xul templates..." path = Path(applicationDirectoryPath) messages = pot2dict('exe/locale/messages.pot') messageCommentTemplate = '\n#: %s:%s\nmsgid "' seq = len(messages) skipPaths = ( applicationDirectoryPath/'exe/webui/firefox', ) for fn in path.walkfiles(): if fn.ext.lower() == '.xul': for skipPath in skipPaths: if fn.startswith(skipPath): print 'IGNORING', fn break else: if verbose: print "template: ", fn reader = Sax2.Reader() doc = reader.fromStream(file(fn, 'rb')) xul2dict(doc, messages, seq, fn.relpath()) pot = Path('exe/locale/messages.pot') if pot.exists(): pot.remove() pot.touch() dict2pot(messages, 'exe/locale/messages.pot')
def exportSinglePage(self, client, filename, webDir, stylesDir, printFlag): """ Export 'client' to a single web page, 'webDir' is just read from config.webDir 'stylesDir' is where to copy the style sheet information from 'printFlag' indicates whether or not this is for print (and whatever else that might mean) """ try: imagesDir = webDir.joinpath('images') scriptsDir = webDir.joinpath('scripts') templatesDir = webDir.joinpath('templates') filename = Path(filename) if filename.basename() != self.package.name: filename /= self.package.name if not filename.exists(): filename.makedirs() elif not filename.isdir(): client.alert(_(u'Filename %s is a file, cannot replace it') % filename) log.error("Couldn't export web page: "+ "Filename %s is a file, cannot replace it" % filename) return else: client.alert(_(u'Folder name %s already exists. ' 'Please choose another one or delete existing one then try again.') % filename) return singlePageExport = SinglePageExport(stylesDir, filename, imagesDir, scriptsDir, templatesDir) singlePageExport.export(self.package, printFlag) except Exception, e: client.alert(_('SAVE FAILED!\n%s' % str(e))) raise
def handleExport(self, client, exportType, filename): """ Called by js. Exports the current package to one of the above formats 'exportType' can be one of 'singlePage' 'webSite' 'zipFile' 'textFile' or 'scorm' 'filename' is a file for scorm pages, and a directory for websites """ webDir = Path(self.config.webDir) stylesDir = webDir.joinpath('style', self.package.style) exportDir = Path(filename).dirname() if exportDir and not exportDir.exists(): client.alert(_(u'Cannot access directory named ') + unicode(exportDir) + _(u'. Please use ASCII names.')) return if exportType == 'singlePage': self.exportSinglePage(client, filename, webDir, stylesDir) elif exportType == 'webSite': self.exportWebSite(client, filename, stylesDir) elif exportType == 'zipFile': self.exportWebZip(client, filename, stylesDir) elif exportType == 'textFile': self.exportText(client, filename) elif exportType == "scorm": self.exportScorm(client, filename, stylesDir, "scorm1.2") elif exportType == "scorm2004": self.exportScorm(client, filename, stylesDir, "scorm2004") else: self.exportIMS(client, filename, stylesDir)
def exportSinglePage(self, client, filename, webDir, stylesDir): """ Export 'client' to a single web page, 'webDir' is just read from config.webDir 'stylesDir' is where to copy the style sheet information from """ imagesDir = webDir.joinpath('images') scriptsDir = webDir.joinpath('scripts') templatesDir = webDir.joinpath('templates') filename = Path(filename) if filename.basename() != self.package.name: filename /= self.package.name if not filename.exists(): filename.makedirs() elif not filename.isdir(): client.alert(_(u'Filename %s is a file, cannot replace it') % filename) log.error("Couldn't export web page: "+ "Filename %s is a file, cannot replace it" % filename) return else: try: filename.rmtree() filename.mkdir() except Exception, e: client.alert(_('There was an error in the export:\n%s') % str(e)) return
def exportWebSite(self, client, filename, stylesDir): """ Export 'client' to a web site, 'webDir' is just read from config.webDir 'stylesDir' is where to copy the style sheet information from """ try: filename = Path(filename) if filename.basename() != self.package.name: filename /= self.package.name if not filename.exists(): filename.makedirs() elif not filename.isdir(): client.alert(_(u'Filename %s is a file, cannot replace it') % filename) log.error("Couldn't export web page: "+ "Filename %s is a file, cannot replace it" % filename) return else: client.alert(_(u'Folder name %s already exists. ' 'Please choose another one or delete existing one then try again.') % filename) return websiteExport = WebsiteExport(self.config, stylesDir, filename) websiteExport.export(self.package) except Exception, e: client.alert(_('EXPORT FAILED!\n%s') % str(e)) raise
def render_POST(self, request): """ function replaced by nevow_clientToServerEvent to avoid POST message """ log.debug("render_POST " + repr(request.args)) data = {} try: locale = request.args['locale'][0] self.config.locale = locale self.config.locales[locale].install(unicode=True) self.config.configParser.set('user', 'locale', locale) internalAnchors = request.args['internalAnchors'][0] self.config.internalAnchors = internalAnchors self.config.configParser.set('user', 'internalAnchors', internalAnchors) browser = request.args['browser'][0] if browser == "None": browser = None try: self.config.browser = mywebbrowser.get(browser) except Exception as e: browser_path = Path(browser) if browser_path.exists(): mywebbrowser.register('custom-browser' , None, mywebbrowser.BackgroundBrowser(browser_path.abspath()), -1) self.config.browser = mywebbrowser.get('custom-browser') else: raise e self.config.configParser.set('system', 'browser', browser) showWizardOnStart = request.args['showWizardOnStart'][0] self.config.showWizardOnStart = showWizardOnStart self.config.configParser.set('user', 'showWizardOnStart', showWizardOnStart) except Exception as e: log.exception(e) return json.dumps({'success': False, 'errorMessage': _("Failed to save preferences wizard")}) return json.dumps({'success': True, 'data': data})
def makeMO(applicationDirectoryPath, targetDir=None, applicationDomain=None, verbose=0, forceEnglish=0): """Compile the Portable Object files into the Machine Object stored in the right location. makeMO converts all translated language-specific PO files located inside the application directory into the binary .MO files stored inside the LC_MESSAGES sub-directory for the found locale files. makeMO searches for all files that have a name of the form 'app_xx.po' inside the application directory specified by the first argument. The 'app' is the application domain name (that can be specified by the applicationDomain argument or is taken from the directory name). The 'xx' corresponds to one of the ISO 639 two-letter language codes. makeMo stores the resulting files inside a sub-directory of `targetDir` called xx/LC_MESSAGES where 'xx' corresponds to the 2-letter language code. """ if targetDir is None: targetDir = "exe/locale" if verbose: print "Target directory for .mo files is: %s" % targetDir targetDir = Path(targetDir) if applicationDomain is None: applicationName = fileBaseOf(applicationDirectoryPath, withPath=0) else: applicationName = applicationDomain currentDir = os.getcwd() os.chdir(applicationDirectoryPath) for filename in targetDir.glob("*_*.po"): langCode = filename.split("_", 1)[1].split(".", 1)[0] mo_targetDir = Path("%s/%s/LC_MESSAGES" % (targetDir, langCode)) if not mo_targetDir.exists(): mo_targetDir.makedirs() cmd = "msgfmt --output-file=%s.mo %s" % (mo_targetDir / applicationName, filename) if verbose: print cmd os.system(cmd) os.chdir(currentDir)
def exportIpod(self, client, filename): """ Export 'client' to an iPod Notes folder tree 'webDir' is just read from config.webDir """ try: filename = Path(filename) if filename.basename() != self.package.name: filename /= self.package.name if not filename.exists(): filename.makedirs() elif not filename.isdir(): client.alert(_(u'Filename %s is a file, cannot replace it') % filename) log.error("Couldn't export web page: "+ "Filename %s is a file, cannot replace it" % filename) return else: client.alert(_(u'Folder name %s already exists. ' 'Please choose another one or delete existing one then try again.') % filename) return ipodExport = IpodExport(self.config, filename) ipodExport.export(self.package) except Exception, e: client.alert(_('EXPORT FAILED!\n%s') % str(e)) raise
def render_POST(self, request): """ function replaced by nevow_clientToServerEvent to avoid POST message """ log.debug("render_POST " + repr(request.args)) data = {} try: locale = request.args["locale"][0] self.config.locale = locale self.config.locales[locale].install(unicode=True) self.config.configParser.set("user", "locale", locale) internalAnchors = request.args["internalAnchors"][0] self.config.internalAnchors = internalAnchors self.config.configParser.set("user", "internalAnchors", internalAnchors) editormodesel = request.args["editorMode"][0] self.config.editorMode = editormodesel self.config.configParser.set("user", "editorMode", editormodesel) theme = request.args["theme"][0] self.config.theme = theme self.config.configParser.set("user", "theme", theme) doctypesel = request.args["docType"][0] self.config.docType = doctypesel self.config.configParser.set("user", "docType", doctypesel) googleApiClientID = request.args["googleApiClientID"][0] self.config.googleApiClientID = googleApiClientID self.config.configParser.set("user", "googleApiClientID", googleApiClientID) defaultLicense = request.args["defaultLicense"][0] self.config.defaultLicense = defaultLicense self.config.configParser.set("user", "defaultLicense", defaultLicense) browser = request.args["browser"][0] if browser == "None": browser = None try: self.config.browser = mywebbrowser.get(browser) except Exception as e: browser_path = Path(browser) if browser_path.exists(): mywebbrowser.register( "custom-browser", None, mywebbrowser.BackgroundBrowser(browser_path.abspath()), -1 ) self.config.browser = mywebbrowser.get("custom-browser") else: raise e self.config.configParser.set("system", "browser", browser) showPreferencesOnStart = request.args["showPreferencesOnStart"][0] self.config.showPreferencesOnStart = showPreferencesOnStart self.config.configParser.set("user", "showPreferencesOnStart", showPreferencesOnStart) except Exception as e: log.exception(e) return json.dumps({"success": False, "errorMessage": _("Failed to save preferences")}) return json.dumps({"success": True, "data": data})
def render_POST(self, request): """ function replaced by nevow_clientToServerEvent to avoid POST message """ log.debug("render_POST " + repr(request.args)) data = {} try: locale = request.args['locale'][0] self.config.locale = locale self.config.locales[locale].install(unicode=True) self.config.configParser.set('user', 'locale', locale) internalAnchors = request.args['internalAnchors'][0] self.config.internalAnchors = internalAnchors self.config.configParser.set('user', 'internalAnchors', internalAnchors) editormodesel = request.args['editorMode'][0] self.config.editorMode = editormodesel self.config.configParser.set('user', 'editorMode', editormodesel) doctypesel = request.args['docType'][0] self.config.docType = doctypesel self.config.configParser.set('user', 'docType', doctypesel) defaultLicense = request.args['defaultLicense'][0] self.config.defaultLicense = defaultLicense self.config.configParser.set('user', 'defaultLicense', defaultLicense) browser = request.args['browser'][0] if browser == "None": browser = None try: self.config.browser = mywebbrowser.get(browser) except Exception as e: browser_path = Path(browser) if browser_path.exists(): mywebbrowser.register( 'custom-browser', None, mywebbrowser.BackgroundBrowser(browser_path.abspath()), -1) self.config.browser = mywebbrowser.get('custom-browser') else: raise e self.config.configParser.set('system', 'browser', browser) showPreferencesOnStart = request.args['showPreferencesOnStart'][0] self.config.showPreferencesOnStart = showPreferencesOnStart self.config.configParser.set('user', 'showPreferencesOnStart', showPreferencesOnStart) except Exception as e: log.exception(e) return json.dumps({ 'success': False, 'errorMessage': _("Failed to save preferences") }) return json.dumps({'success': True, 'data': data})
def handleExport(self, client, exportType, filename, print_callback=''): """ Called by js. Exports the current package to one of the above formats 'exportType' can be one of 'singlePage' 'webSite' 'zipFile' 'ipod' 'textFile' or 'scorm' 'filename' is a file for scorm pages, and a directory for websites """ webDir = Path(self.config.webDir) stylesDir = webDir.joinpath('style', self.package.style) exportDir = Path(filename).dirname() if exportDir and not exportDir.exists(): client.alert(_(u'Cannot access directory named ') + unicode(exportDir) + _(u'. Please use ASCII names.')) return """ adding the print feature in using the same export functionality: """ if exportType == 'singlePage' or exportType == 'printSinglePage': printit = 0 if exportType == 'printSinglePage': printit = 1 exported_dir = self.exportSinglePage(client, filename, webDir, \ stylesDir, printit) # the above will return None if the desired exported directory # already exists (printing always goes to a new temp dir, though): if printit == 1 and not exported_dir is None: web_printdir = self.get_printdir_relative2web(exported_dir) # now that this has ben exported, go ahead and trigger # the requested printing callback: client.call(print_callback, filename, exported_dir, \ web_printdir) elif exportType == 'webSite': self.exportWebSite(client, filename, stylesDir) elif exportType == 'zipFile': filename = self.b4save(client, filename, '.zip', _(u'EXPORT FAILED!')) self.exportWebZip(client, filename, stylesDir) elif exportType == 'textFile': self.exportText(client, filename) elif exportType == 'ipod': self.exportIpod(client, filename) elif exportType == "scorm": filename = self.b4save(client, filename, '.zip', _(u'EXPORT FAILED!')) self.exportScorm(client, filename, stylesDir, "scorm1.2") elif exportType == "scorm2004": filename = self.b4save(client, filename, '.zip', _(u'EXPORT FAILED!')) self.exportScorm(client, filename, stylesDir, "scorm2004") elif exportType == "commoncartridge": filename = self.b4save(client, filename, '.zip', _(u'EXPORT FAILED!')) self.exportScorm(client, filename, stylesDir, "commoncartridge") else: filename = self.b4save(client, filename, '.zip', _(u'EXPORT FAILED!')) self.exportIMS(client, filename, stylesDir)
def checkImageVersionsExist(self, imgPath, package, exetocEl): imgResProfs = exetocEl.getAttribute("resolutions").split(",") for profileName in imgResProfs: if profileName == "": return newFileName = imgPath.namebase + "-" + profileName + imgPath.ext profileImgPath = Path(imgPath.parent/newFileName) self.assertTrue(profileImgPath.exists(), "Image ")
def exportWebZip(self, client, filename, stylesDir): filename = Path(filename) log.debug(u"exportWebsite, filename=%s" % filename) if not filename.ext.lower() == '.zip': filename += '.zip' if filename.exists(): filename.remove() websiteExport = WebsiteExport(self.config, stylesDir, filename) websiteExport.exportZip(self.package) client.alert(_(u'Exported to %s') % filename)
def exportText(self, client, filename): filename = Path(filename) log.debug(u"exportWebsite, filename=%s" % filename) if not filename.ext.lower() == '.txt': filename += '.txt' if filename.exists(): filename.remove() textExport = TextExport(filename) textExport.export(self.package) client.alert(_(u'Exported to %s') % filename)
def __loadIdevice(self): """ Load IDevice configuration from its config.xml file """ try: if self._valid: # Check if the folder has a config.xml file configFile = Path(self._iDeviceDir + '/config.xml') if configFile.exists(): # Get config data configData = open(configFile).read() try: newConfigData = configData.decode() except UnicodeDecodeError: configCharset = chardet.detect(configData) newConfigData = configData.decode( configCharset['encoding'], 'replace') # Parse the XML file xmlConfig = minidom.parseString(newConfigData) # Get main element xmlIdevice = xmlConfig.getElementsByTagName('idevice') # Initialize results variable result = dict() # If there is a main element tag if (len(xmlIdevice) > 0): # Go over all the child nodes for tag in xmlIdevice[0].childNodes: # Only process the node if it is an Element # This means only tags get processed if (isinstance(tag, minidom.Element)): # Add the tag name and value to the result dictionary result.update( {tag.tagName: tag.firstChild.nodeValue}) if 'title' in result and 'css-class' in result: return result else: raise InvalidConfigJsIdevice( Path(self._iDeviceDir).basename(), 'Mandatory fields not found.') else: raise InvalidConfigJsIdevice( Path(self._iDeviceDir).basename(), 'config.xml file doesn\'t exist.') except IOError as ioerror: # If we can't load an iDevice, we simply continue with the rest (and log it) log.debug("iDevice " + Path(self._iDeviceDir).basename() + " doesn't appear to have a valid \"config.xml\" file") raise InvalidConfigJsIdevice( Path(self._iDeviceDir).basename(), ioerror.message)
def handleTinyMCEimageChoice(self, client, tinyMCEwin, tinyMCEwin_name, \ tinyMCEfield, local_filename, preview_filename): """ Once an image is selected in the file browser that is spawned by the TinyMCE image dialog, copy this file (which is local to the user's machine) into the server space, under a preview directory (after checking if this exists, and creating it if necessary). Note that this IS a "cheat", in violation of the client-server separation, but can be done since we know that the eXe server is actually sitting on the client host. """ server_filename = "" callback_errors = "" errors = 0 webDir = Path(self.config.webDir) previewDir = webDir.joinpath('previews') if not previewDir.exists(): log.debug("image previews directory does not yet exist; " \ + "creating as %s " % previewDir) previewDir.makedirs() elif not previewDir.isdir(): client.alert( \ _(u'Preview directory %s is a file, cannot replace it') \ % previewDir) log.error("Couldn't preview tinyMCE-chosen image: "+ "Preview dir %s is a file, cannot replace it" \ % previewDir) callback_errors = "Preview dir is a file, cannot replace" errors += 1 if errors == 0: localImagePath = Path(local_filename) if not localImagePath.exists() or not localImagePath.isfile(): client.alert( \ _(u'Image file %s is not found, cannot preview it') \ % localImagePath) log.error("Couldn't find tinyMCE-chosen image: %s" \ % localImagePath) callback_errors = "Image file %s not found, cannot preview" \ % localImagePath errors += 1 try: server_filename = previewDir.joinpath(preview_filename); log.debug("handleTinyMCEimageChoice copying image from \'"\ + local_filename + "\' to \'" \ + server_filename.abspath().encode('utf-8') + "\'."); shutil.copyfile(local_filename, \ server_filename.abspath().encode('utf-8')); except Exception, e: client.alert(_('SAVE FAILED!\n%s' % str(e))) log.error("handleTinyMCEimageChoice unable to copy local image "\ +"file to server prevew, error = " + str(e)) raise
def exportScorm(self, client, filename, stylesDir, scormType): """ Exports this package to a scorm package file """ filename = Path(filename) log.debug(u"exportScorm, filename=%s" % filename) if not filename.ext.lower() == '.zip': filename += '.zip' if filename.exists(): filename.remove() scormExport = ScormExport(self.config, stylesDir, filename, scormType) scormExport.export(self.package) client.alert(_(u'Exported to %s') % filename)
def exportIMS(self, client, filename, stylesDir): """ Exports this package to a ims package file """ log.debug(u"exportIMS") if not filename.lower().endswith('.zip'): filename += '.zip' filename = Path(filename) if filename.exists(): filename.remove() imsExport = IMSExport(self.config, stylesDir, filename) imsExport.export(self.package) client.alert(_(u'Exported to %s' % filename))
def __renderIcons(self, style): """ Return xhtml string for dispay all icons """ iconpath = Path(G.application.config.stylesDir/style) iconfiles = iconpath.files("icon_*") html = '<div id="styleIcons"><div style="height:300px;overflow:auto">' for iconfile in iconfiles: iconname = iconfile.namebase icon = iconname.split("_", 1)[1] iconExists = False iconExtension = "gif" myIcon = Path(G.application.config.stylesDir/style/iconname + ".gif") if myIcon.exists(): iconExists = True iconValue = icon+'.'+iconExtension iconSrc = '/style/%s/icon_%s' % (style, iconValue) else: myIcon = Path(G.application.config.stylesDir/style/iconname + ".png") if myIcon.exists(): iconExists = True iconExtension = "png" iconValue = icon+'.'+iconExtension iconSrc = '/style/%s/icon_%s' % (style, iconValue) if iconExists: filename = "/style/%s/%s.%s" % (style, iconname, iconExtension) html += u'<div style="float:left; text-align:center; width:105px;\n' html += u'margin-right:10px; margin-bottom:15px" > ' html += u'<img src="%s" \n' % filename html += u"style=\"border:1px solid #E8E8E8;padding:5px;cursor:pointer;max-width:60px;height:auto\" onclick=\"window[0].selectStyleIcon('%s',this, '%s', '%s')\" title=\"%s.%s\">\n" % (icon, iconSrc, self.id, icon ,iconExtension) html += u'<br /><span style="display:inline-block;width:100px;overflow:hidden;text-overflow:ellipsis">%s.%s</span></div>\n' % (icon, iconExtension) html += '</div></div>' return html
def __renderIcons(self): """ Return xhtml string for dispay all icons """ iconpath = self.style.get_style_dir() iconfiles = iconpath.files("icon_*") html = '<div id="styleIcons"><div style="height:300px;overflow:auto">' for iconfile in iconfiles: iconname = iconfile.namebase icon = iconname.split("_", 1)[1] iconExists = False iconExtension = "gif" myIcon = Path(G.application.config.stylesDir/self.style.get_dirname()/iconname + ".gif") if myIcon.exists(): iconExists = True else: myIcon = Path(G.application.config.stylesDir/self.style.get_dirname()/iconname + ".png") if myIcon.exists(): iconExists = True iconExtension = "png" if iconExists: filename = "/style/%s/%s.%s" % (self.style.get_dirname(), iconname, iconExtension) html += u'<div style="float:left; text-align:center; width:105px;\n' html += u'margin-right:10px; margin-bottom:15px" > ' html += u'<img src="%s" \n' % filename # html += u' alt="%s" ' % _("Submit") # window[1] because we use Ext.MessageBox instead of libot_drag.js html += u"style=\"border:1px solid #E8E8E8;padding:5px;cursor:pointer;max-width:60px;height:auto\" onclick=\"window[1].selectStyleIcon('%s',this)\" title=\"%s.%s\">\n" % (icon, icon, iconExtension) # html += u"style=\"cursor:pointer\" onclick=\"window[1].submitLink('selectIcon','%s',1)\">\n" % icon html += u'<br /><span style="display:inline-block;width:100px;overflow:hidden;text-overflow:ellipsis">%s.%s</span></div>\n' % (icon, iconExtension) html += '</div></div>' return html
def _setupConfigFile(self, configParser): """ Setup our own config file """ utils.SuperTestCase._setupConfigFile(self, configParser) # Create an empty dir to stick the config file tmp = Path('tmp') if not tmp.exists(): tmp.mkdir() logfn = tmp / 'exe.log' if logfn.exists(): try: logfn.remove() except OSError: pass configParser.system.configDir = tmp configParser.logging.root = 'ERROR' configParser.logging.foo = 'DEBUG' configParser.logging.foo = 'DEBUG'
def exportSinglePage(self, client, filename, webDir, stylesDir, \ printFlag): """ Export 'client' to a single web page, 'webDir' is just read from config.webDir 'stylesDir' is where to copy the style sheet information from 'printFlag' indicates whether or not this is for print (and whatever else that might mean) """ try: imagesDir = webDir.joinpath('images') scriptsDir = webDir.joinpath('scripts') templatesDir = webDir.joinpath('templates') # filename is a directory where we will export the website to # We assume that the user knows what they are doing # and don't check if the directory is already full or not # and we just overwrite what's already there filename = Path(filename) # Append the package name to the folder path if necessary if filename.basename() != self.package.name: filename /= self.package.name if not filename.exists(): filename.makedirs() elif not filename.isdir(): client.alert( _(u'Filename %s is a file, cannot replace it') % filename) log.error("Couldn't export web page: " + "Filename %s is a file, cannot replace it" % filename) return else: client.alert( _(u'Folder name %s already exists. ' 'Please choose another one or delete existing one then try again.' ) % filename) return # Now do the export singlePageExport = SinglePageExport(stylesDir, filename, \ imagesDir, scriptsDir, templatesDir) singlePageExport.export(self.package, printFlag) except Exception, e: client.alert(_('SAVE FAILED!\n%s' % str(e))) raise
def testReferenceCounting(self): """ Make 3 resources with different names but same md5, ensure they are reference counted properly """ res1 = Path('my.resource1.bin') res2 = Path('my.resource2.bin') res3 = Path('my.resource3.bin') for res in (res1, res2, res3): res.write_bytes('SOME NICE DATA') res1md5 = res1.md5 res4 = Path('tmp/my.resource1.bin') if not res4.dirname().exists(): res4.dirname().makedirs() res4.write_bytes('SOME *DIFFERENT* DATA') res4md5 = res4.md5 res1, res2, res3, res4 = map(lambda f: Resource(self.package, f), (res1, res2, res3, res4)) assert res1.storageName == 'my.resource1.bin', res1.storageName assert res2.storageName == 'my.resource1.bin', res2.storageName assert res3.storageName == 'my.resource1.bin', res3.storageName assert res4.storageName == 'my.resource1.1.bin', res4.storageName assert res4.userName == 'my.resource1.bin', res4.userName assert len(self.package.resources) == 2 assert len(self.package.resources[res1.path.md5]) == 3 assert len(self.package.resources[res4.path.md5]) == 1 assert self.package.resources[res4md5][0] is res4 # Now start deleting things res4path = Path(res4.path) assert res4path.exists() res4.delete() assert not res4path.exists() assert res4md5 not in self.package.resources assert not res4path.exists() res1path = Path(res1.path) assert res1path.exists() res2.delete() assert res1path.exists() assert res2 not in self.package.resources[res1md5] res1.delete() assert res1path.exists() assert res1 not in self.package.resources[res1md5] res3.delete() assert res1md5 not in self.package.resources assert not res1path.exists()
def get_export_folder(self): export_folder = Path(self.get_jsidevice_dir()) / 'export' if export_folder.exists(): return str(Path(self.get_dirname() + '/export/'))
def handleExport(self, client, exportType, filename, print_callback=''): """ Called by js. Exports the current package to one of the above formats 'exportType' can be one of 'singlePage' 'webSite' 'zipFile' 'ipod' 'textFile' or 'scorm' 'filename' is a file for scorm pages, and a directory for websites """ webDir = Path(self.config.webDir) stylesDir = webDir.joinpath('style', self.package.style) exportDir = Path(filename).dirname() if exportDir and not exportDir.exists(): client.alert( _(u'Cannot access directory named ') + unicode(exportDir) + _(u'. Please use ASCII names.')) return """ adding the print feature in using the same export functionality: """ if exportType == 'singlePage' or exportType == 'printSinglePage': printit = 0 if exportType == 'printSinglePage': printit = 1 exported_dir = self.exportSinglePage(client, filename, webDir, \ stylesDir, printit) # the above will return None if the desired exported directory # already exists (printing always goes to a new temp dir, though): if printit == 1 and not exported_dir is None: web_printdir = self.get_printdir_relative2web(exported_dir) # now that this has ben exported, go ahead and trigger # the requested printing callback: client.call(print_callback, filename, exported_dir, \ web_printdir) elif exportType == 'webSite': self.exportWebSite(client, filename, stylesDir) elif exportType == 'zipFile': filename = self.b4save(client, filename, '.zip', _(u'EXPORT FAILED!')) self.exportWebZip(client, filename, stylesDir) elif exportType == 'textFile': self.exportText(client, filename) elif exportType == 'ipod': self.exportIpod(client, filename) elif exportType == "scorm": filename = self.b4save(client, filename, '.zip', _(u'EXPORT FAILED!')) self.exportScorm(client, filename, stylesDir, "scorm1.2") elif exportType == "scorm2004": filename = self.b4save(client, filename, '.zip', _(u'EXPORT FAILED!')) self.exportScorm(client, filename, stylesDir, "scorm2004") elif exportType == "commoncartridge": filename = self.b4save(client, filename, '.zip', _(u'EXPORT FAILED!')) self.exportScorm(client, filename, stylesDir, "commoncartridge") else: filename = self.b4save(client, filename, '.zip', _(u'EXPORT FAILED!')) self.exportIMS(client, filename, stylesDir)
def handleTinyMCEimageChoice(self, client, tinyMCEwin, tinyMCEwin_name, \ tinyMCEfield, local_filename, preview_filename): """ Once an image is selected in the file browser that is spawned by the TinyMCE image dialog, copy this file (which is local to the user's machine) into the server space, under a preview directory (after checking if this exists, and creating it if necessary). Note that this IS a "cheat", in violation of the client-server separation, but can be done since we know that the eXe server is actually sitting on the client host. """ server_filename = "" callback_errors = "" errors = 0 log.debug('handleTinyMCEimageChoice: image local = ' + local_filename + ', base=' + os.path.basename(local_filename)) webDir = Path(G.application.tempWebDir) previewDir = webDir.joinpath('previews') if not previewDir.exists(): log.debug("image previews directory does not yet exist; " \ + "creating as %s " % previewDir) previewDir.makedirs() elif not previewDir.isdir(): client.alert( \ _(u'Preview directory %s is a file, cannot replace it') \ % previewDir) log.error("Couldn't preview tinyMCE-chosen image: "+ "Preview dir %s is a file, cannot replace it" \ % previewDir) callback_errors = "Preview dir is a file, cannot replace" errors += 1 if errors == 0: log.debug('handleTinyMCEimageChoice: originally, local_filename=' + local_filename) local_filename = unicode(local_filename, 'utf-8') log.debug('handleTinyMCEimageChoice: in unicode, local_filename=' + local_filename) localImagePath = Path(local_filename) log.debug( 'handleTinyMCEimageChoice: after Path, localImagePath= ' + localImagePath) if not localImagePath.exists() or not localImagePath.isfile(): client.alert( \ _(u'Local file %s is not found, cannot preview it') \ % localImagePath) log.error("Couldn't find tinyMCE-chosen image: %s" \ % localImagePath) callback_errors = "Image file %s not found, cannot preview" \ % localImagePath errors += 1 try: # joinpath needs its join arguments to already be in Unicode: #preview_filename = toUnicode(preview_filename); # but that's okay, cuz preview_filename is now URI safe, right? log.debug('URIencoded preview filename=' + preview_filename) server_filename = previewDir.joinpath(preview_filename) log.debug("handleTinyMCEimageChoice copying image from \'"\ + local_filename + "\' to \'" \ + server_filename.abspath() + "\'.") shutil.copyfile(local_filename, \ server_filename.abspath()) # new optional description file to provide the # actual base filename, such that once it is later processed # copied into the resources directory, it can be done with # only the basename. Otherwise the resource filenames # are too long for some users, preventing them from making # backup CDs of the content, for example. # # Remember that the full path of the # file is only used here as an easy way to keep the names # unique WITHOUT requiring a roundtrip call from the Javascript # to this server, and back again, a process which does not # seem to work with tinyMCE in the mix. BUT, once tinyMCE's # part is done, and this image processed, it can be returned # to just its basename, since the resource parts have their # own unique-ification mechanisms already in place. descrip_file_path = Path(server_filename + ".exe_info") log.debug("handleTinyMCEimageChoice creating preview " \ + "description file \'" \ + descrip_file_path.abspath() + "\'.") descrip_file = open(descrip_file_path, 'wb') # safety measures against TinyMCE, otherwise it will # later take ampersands and entity-escape them into '&', # and filenames with hash signs will not be found, etc.: unspaced_filename = local_filename.replace(' ', '_') unhashed_filename = unspaced_filename.replace('#', '_num_') unamped_local_filename = unhashed_filename.replace('&', '_and_') log.debug("and setting new file basename as: " + unamped_local_filename) my_basename = os.path.basename(unamped_local_filename) descrip_file.write((u"basename=" + my_basename).encode('utf-8')) descrip_file.flush() descrip_file.close() except Exception, e: client.alert(_('SAVE FAILED!\n%s' % str(e))) log.error("handleTinyMCEimageChoice unable to copy local image "\ +"file to server prevew, error = " + str(e)) raise
def export(self, package): """ Export SCORM package """ # First do the export to a temporary directory outputDir = TempDirPath() self.metadataType = package.exportMetadataType # Copy the style files to the output dir # But not nav.css styleFiles = [self.styleDir/'..'/'popup_bg.gif'] styleFiles += self.styleDir.files("*.*") if "nav.css" in styleFiles: styleFiles.remove("nav.css") self.styleDir.copylist(styleFiles, outputDir) # copy the package's resource files for resourceFile in package.resourceDir.walkfiles(): file = package.resourceDir.relpathto(resourceFile) if ("/" in file): Dir = Path(outputDir/file[:file.rindex("/")]) if not Dir.exists(): Dir.makedirs() resourceFile.copy(outputDir/Dir) else: resourceFile.copy(outputDir) listCSSFiles=getFilesCSSToMinify('ims', self.styleDir) exportMinFileCSS(listCSSFiles, outputDir) # Export the package content self.pages = [ IMSPage("index", 1, package.root, metadataType=self.metadataType) ] self.generatePages(package.root, 2) uniquifyNames(self.pages) for page in self.pages: page.save(outputDir, self.pages) # Create the manifest file manifest = Manifest(self.config, outputDir, package, self.pages, self.metadataType) manifest.save("imsmanifest.xml") # Create lang file langGameFile = open(outputDir + '/common_i18n.js', "w") langGameFile.write(common.getJavaScriptStrings(False)) langGameFile.close() # jQuery my_style = G.application.config.styleStore.getStyle(page.node.package.style) if my_style.hasValidConfig(): if my_style.get_jquery() == True: jsFile = (self.scriptsDir/'exe_jquery.js') jsFile.copyfile(outputDir/'exe_jquery.js') else: jsFile = (self.scriptsDir/'exe_jquery.js') jsFile.copyfile(outputDir/'exe_jquery.js') dT = common.getExportDocType() if dT == "HTML5": jsFile = (self.scriptsDir/'exe_html5.js') jsFile.copyfile(outputDir/'exe_html5.js') listFiles=getFilesJSToMinify('ims', self.scriptsDir) exportMinFileJS(listFiles, outputDir) self.schemasDir.copylist(('imscp_v1p1.xsd', 'imsmd_v1p2p2.xsd', 'lom.xsd', 'lomCustom.xsd', 'ims_xml.xsd'), outputDir) # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False hasFX = False hasSH = False hasGames = False hasElpLink = False hasWikipedia = False isBreak = False hasInstructions = False hasMediaelement = False hasTooltips = False hasABCMusic = False listIdevicesFiles = [] for page in self.pages: if isBreak: break for idevice in page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasSH and hasGames and hasElpLink and hasWikipedia and hasInstructions and hasMediaelement and hasTooltips and hasABCMusic): isBreak = True break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'mojomagnify.js' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: hasGallery = common.ideviceHasGallery(idevice) if not hasFX: hasFX = common.ideviceHasFX(idevice) if not hasSH: hasSH = common.ideviceHasSH(idevice) if not hasGames: hasGames = common.ideviceHasGames(idevice) if not hasElpLink: hasElpLink = common.ideviceHasElpLink(idevice,package) if not hasWikipedia: if 'WikipediaIdevice' == idevice.klass: hasWikipedia = True if not hasInstructions: if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass: hasInstructions = True if not hasMediaelement: hasMediaelement = common.ideviceHasMediaelement(idevice) if not hasTooltips: hasTooltips = common.ideviceHasTooltips(idevice) if not hasABCMusic: hasABCMusic = common.ideviceHasABCMusic(idevice) if hasattr(idevice, "_iDeviceDir"): listIdevicesFiles.append((idevice.get_jsidevice_dir()/'export')) common.exportJavaScriptIdevicesFiles(page.node.idevices, outputDir); if hasFlowplayer: videofile = (self.templatesDir/'flowPlayer.swf') videofile.copyfile(outputDir/'flowPlayer.swf') controlsfile = (self.templatesDir/'flowplayer.controls.swf') controlsfile.copyfile(outputDir/'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir/'mojomagnify.js') videofile.copyfile(outputDir/'mojomagnify.js') if hasXspfplayer: videofile = (self.templatesDir/'xspf_player.swf') videofile.copyfile(outputDir/'xspf_player.swf') if hasGallery: exeLightbox = (self.scriptsDir/'exe_lightbox') exeLightbox.copyfiles(outputDir) if hasFX: exeEffects = (self.scriptsDir/'exe_effects') exeEffects.copyfiles(outputDir) if hasSH: exeSH = (self.scriptsDir/'exe_highlighter') exeSH.copyfiles(outputDir) if hasGames: exeGames = (self.scriptsDir/'exe_games') exeGames.copyfiles(outputDir) # Add game js string to common_i18n langGameFile = open(outputDir + '/common_i18n.js', "a") langGameFile.write(common.getGamesJavaScriptStrings(False)) langGameFile.close() if hasElpLink or package.get_exportElp(): # Export the elp file currentPackagePath = Path(package.filename) currentPackagePath.copyfile(outputDir/package.name+'.elp') if hasWikipedia: wikipediaCSS = (self.cssDir/'exe_wikipedia.css') wikipediaCSS.copyfile(outputDir/'exe_wikipedia.css') if hasInstructions: common.copyFileIfNotInStyle('panel-amusements.png', self, outputDir) common.copyFileIfNotInStyle('stock-stop.png', self, outputDir) if hasMediaelement: mediaelement = (self.scriptsDir/'mediaelement') mediaelement.copyfiles(outputDir) if dT != "HTML5": jsFile = (self.scriptsDir/'exe_html5.js') jsFile.copyfile(outputDir/'exe_html5.js') if hasTooltips: exe_tooltips = (self.scriptsDir/'exe_tooltips') exe_tooltips.copyfiles(outputDir) if hasABCMusic: pluginScripts = (self.scriptsDir/'tinymce_4/js/tinymce/plugins/abcmusic/export') pluginScripts.copyfiles(outputDir) if hasattr(package, 'exportSource') and package.exportSource: (G.application.config.webDir/'templates'/'content.xsd').copyfile(outputDir/'content.xsd') (outputDir/'content.data').write_bytes(encodeObject(package)) (outputDir/'contentv3.xml').write_bytes(encodeObjectToXML(package)) if package.license == "license GFDL": # include a copy of the GNU Free Documentation Licence (self.templatesDir/'fdl.html').copyfile(outputDir/'fdl.html') # Zip it up! self.filename.safeSave(self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir) # Clean up the temporary dir outputDir.rmtree()
def export(self, package): """ Export epub 3 package """ # First do the export to a temporary directory outputDir = TempDirPath() ''' fileDir = outputDir/"META-INF" fileDir.mkdir() fileDir = outputDir/"Content" fileDir.mkdir() ''' metainfPages = Path(outputDir.abspath() + '/META-INF') # metainfPages = outputDir/'META-INF' metainfPages.mkdir() contentPages = Path(outputDir.abspath() + '/EPUB') # contentPages = outputDir/'Content' contentPages.mkdir() # print contentPages.abspath() # print outputDir.abspath() # Export the package content self.pages = [Epub3Cover("cover", 1, package.root)] self.generatePages(package.root, 2) uniquifyNames(self.pages) cover = None for page in self.pages: page.save(contentPages, self.pages) if hasattr(page, 'cover'): cover = page.cover # Create mimetype file mimetypeFile = open(outputDir.abspath() + '/mimetype', "w") mimetypeFile.write('application/epub+zip') mimetypeFile.close() # Create common_i18n file langFile = open(contentPages + '/common_i18n.js', "w") langFile.write(common.getJavaScriptStrings(False)) langFile.close() # Copy the style files to the output dir # But not nav.css styleFiles = [self.styleDir / '..' / 'popup_bg.gif'] styleFiles += [ f for f in self.styleDir.files("*.*") if f.basename() not in ['nav.css'] ] # FIXME for now, only copy files referenced in Common Cartridge # this really should apply to all exports, but without a manifest # of the files needed by an included stylesheet it is too restrictive # Add fallback document for possible image links if Path(self.styleDir / 'fallback.xhtml').exists(): styleFiles += [self.styleDir / 'fallback.xhtml'] else: styleFiles += [self.styleDir / '..' / 'fallback.xhtml'] # copy the package's resource files for resourceFile in package.resourceDir.walkfiles(): fn = package.resourceDir.relpathto(resourceFile) if ("/" in fn): Dir = Path(contentPages / fn[:fn.rindex("/")]) if not Dir.exists(): Dir.makedirs() resourceFile.copy(contentPages / Dir) else: resourceFile.copy(contentPages) self.styleDir.copylist(styleFiles, contentPages) # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False hasFX = False hasSH = False hasGames = False hasWikipedia = False isBreak = False hasInstructions = False hasTooltips = False hasABCMusic = False for page in self.pages: if isBreak: break for idevice in page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasSH and hasGames and hasWikipedia and hasInstructions and hasTooltips and hasABCMusic): isBreak = True break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'mojomagnify.js' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: hasGallery = common.ideviceHasGallery(idevice) if not hasFX: hasFX = common.ideviceHasFX(idevice) if not hasSH: hasSH = common.ideviceHasSH(idevice) if not hasGames: hasGames = common.ideviceHasGames(idevice) if not hasWikipedia: if 'WikipediaIdevice' == idevice.klass: hasWikipedia = True if not hasInstructions: if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass: hasInstructions = True if not hasTooltips: hasTooltips = common.ideviceHasTooltips(idevice) if not hasABCMusic: hasABCMusic = common.ideviceHasABCMusic(idevice) common.exportJavaScriptIdevicesFiles(page.node.idevices, contentPages) if hasFlowplayer: videofile = (self.templatesDir / 'flowPlayer.swf') videofile.copyfile(contentPages / 'flowPlayer.swf') controlsfile = (self.templatesDir / 'flowplayer.controls.swf') controlsfile.copyfile(contentPages / 'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir / 'mojomagnify.js') videofile.copyfile(contentPages / 'mojomagnify.js') if hasXspfplayer: videofile = (self.templatesDir / 'xspf_player.swf') videofile.copyfile(contentPages / 'xspf_player.swf') if hasGallery: exeLightbox = (self.scriptsDir / 'exe_lightbox') exeLightbox.copyfiles(contentPages) if hasFX: exeEffects = (self.scriptsDir / 'exe_effects') exeEffects.copyfiles(contentPages) if hasSH: exeSH = (self.scriptsDir / 'exe_highlighter') exeSH.copyfiles(contentPages) if hasGames: exeGames = (self.scriptsDir / 'exe_games') exeGames.copyfiles(contentPages) # Add game js string to common_i18n langGameFile = open(contentPages + '/common_i18n.js', "a") langGameFile.write(common.getGamesJavaScriptStrings(False)) langGameFile.close() if hasWikipedia: wikipediaCSS = (self.cssDir / 'exe_wikipedia.css') wikipediaCSS.copyfile(contentPages / 'exe_wikipedia.css') if hasInstructions: common.copyFileIfNotInStyle('panel-amusements.png', self, contentPages) common.copyFileIfNotInStyle('stock-stop.png', self, contentPages) if hasTooltips: exe_tooltips = (self.scriptsDir / 'exe_tooltips') exe_tooltips.copyfiles(contentPages) if hasABCMusic: pluginScripts = (self.scriptsDir / 'tinymce_4/js/tinymce/plugins/abcmusic/export') pluginScripts.copyfiles(contentPages) my_style = G.application.config.styleStore.getStyle(package.style) if my_style.hasValidConfig: if my_style.get_jquery() == True: jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(contentPages / 'exe_jquery.js') else: jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(contentPages / 'exe_jquery.js') # Copy and minify CSS files css_files = getFilesCSSToMinify('epub3', self.styleDir) exportMinFileCSS(css_files, contentPages) # Copy and minify JS files js_files = getFilesJSToMinify('epub3', self.scriptsDir) exportMinFileJS(js_files, contentPages) # if hasattr(package, 'exportSource') and package.exportSource: # (G.application.config.webDir / 'templates' / 'content.xsd').copyfile(outputDir / 'content.xsd') # (outputDir / 'content.data').write_bytes(encodeObject(package)) # (outputDir / 'contentv3.xml').write_bytes(encodeObjectToXML(package)) if package.license == "license GFDL": # include a copy of the GNU Free Documentation Licence (self.templatesDir / 'fdl.html').copyfile(contentPages / 'fdl.html') # Create the nav.xhtml file container = NavEpub3(self.pages, contentPages) container.save() # Create the publication file publication = PublicationEpub3(self.config, contentPages, package, self.pages, cover) publication.save("package.opf") # Create the container file container = ContainerEpub3(metainfPages) container.save("container.xml") # Zip it up! self.filename.safeSave( self.doZip, _(u'EXPORT FAILED!\nLast succesful export is %s.'), outputDir) # Clean up the temporary dir outputDir.rmtree()
def export(self, package): """ Export SCORM package """ # First do the export to a temporary directory outputDir = TempDirPath() self.metadataType = package.exportMetadataType # copy the package's resource files for resourceFile in package.resourceDir.walkfiles(): file = package.resourceDir.relpathto(resourceFile) if ("/" in file): Dir = Path(outputDir / file[:file.rindex("/")]) if not Dir.exists(): Dir.makedirs() resourceFile.copy(outputDir / Dir) else: resourceFile.copy(outputDir) # copy the package's resource files, only non existant in outputDir # outputDirFiles = outputDir.files() # for rfile in package.resourceDir.files(): # if rfile not in outputDirFiles: # rfile.copy(outputDir) # copy the package's resource files, only indexed in package.resources # for md5 in package.resources.values(): # for resource in md5: # resource.path.copy(outputDir) # Export the package content # Import the Scorm Page class , if the secure mode is off. If the style has it's own page class # use that, else use the default one. if self.styleSecureMode == "0": if (self.styleDir / "scormpage.py").exists(): global ScormPage module = imp.load_source("ScormPage", self.styleDir / "scormpage.py") ScormPage = module.ScormPage self.pages = [ ScormPage("index", 1, package.root, scormType=self.scormType, metadataType=self.metadataType) ] self.generatePages(package.root, 2) uniquifyNames(self.pages) for page in self.pages: page.save(outputDir, self.pages) if not self.hasForum: for idevice in page.node.idevices: if hasattr(idevice, "isForum"): if idevice.forum.lms.lms == "moodle": self.hasForum = True break # Create the manifest file manifest = Manifest(self.config, outputDir, package, self.pages, self.scormType, self.metadataType) modifiedMetaData = manifest.save("imsmanifest.xml") # Create lang file langFile = open(outputDir + '/common_i18n.js', "w") langFile.write(common.getJavaScriptStrings(False)) langFile.close() if self.hasForum: manifest.save("discussionforum.xml") # Copy the style files to the output dir styleFiles = [self.styleDir / '..' / 'popup_bg.gif'] # And with all the files of the style we avoid problems: styleFiles += self.styleDir.files("*.*") if self.scormType == "commoncartridge": for sf in styleFiles[:]: if sf.basename() not in manifest.dependencies: styleFiles.remove(sf) self.styleDir.copylist(styleFiles, outputDir) listCSSFiles = getFilesCSSToMinify('scorm', self.styleDir) exportMinFileCSS(listCSSFiles, outputDir) # Copy the scripts dT = common.getExportDocType() if dT == "HTML5": #listFiles+=[self.scriptsDir/'exe_html5.js'] #listOutFiles+=[outputDir/'exe_html5.js'] jsFile = (self.scriptsDir / 'exe_html5.js') jsFile.copyfile(outputDir / 'exe_html5.js') # jQuery my_style = G.application.config.styleStore.getStyle( page.node.package.style) if my_style.hasValidConfig(): if my_style.get_jquery() == True: #listFiles+=[self.scriptsDir/'exe_jquery.js'] #listOutFiles+=[outputDir/'exe_jquery.js'] jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(outputDir / 'exe_jquery.js') else: #listFiles+=[self.scriptsDir/'exe_jquery.js'] #listOutFiles+=[outputDir/'exe_jquery.js'] jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(outputDir / 'exe_jquery.js') if self.scormType == "commoncartridge" or self.scormType == "scorm2004" or self.scormType == "scorm1.2": listFiles = getFilesJSToMinify('scorm', self.scriptsDir) exportMinFileJS(listFiles, outputDir) if self.scormType == "scorm2004" or self.scormType == "scorm1.2": self.scriptsDir.copylist( ('SCORM_API_wrapper.js', 'SCOFunctions.js'), outputDir) # about SCHEMAS: schemasDir = "" if self.scormType == "scorm1.2": schemasDir = self.schemasDir / "scorm1.2" schemasDir.copylist(('imscp_rootv1p1p2.xsd', 'imsmd_rootv1p2p1.xsd', 'adlcp_rootv1p2.xsd', 'lom.xsd', 'lomCustom.xsd', 'ims_xml.xsd'), outputDir) elif self.scormType == "scorm2004": schemasDir = self.schemasDir / "scorm2004" schemasDir.copylist( ('adlcp_v1p3.xsd', 'adlnav_v1p3.xsd', 'adlseq_v1p3.xsd', 'datatypes.dtd', 'imscp_v1p1.xsd', 'imsssp_v1p0.xsd', 'imsss_v1p0.xsd', 'imsss_v1p0auxresource.xsd', 'imsss_v1p0control.xsd', 'imsss_v1p0delivery.xsd', 'imsmd_rootv1p2p1.xsd', 'imsss_v1p0limit.xsd', 'imsss_v1p0objective.xsd', 'imsss_v1p0random.xsd', 'imsss_v1p0rollup.xsd', 'imsss_v1p0seqrule.xsd', 'imsss_v1p0util.xsd', 'ims_xml.xsd', 'lom.xsd', 'lomCustom.xsd', 'xml.xsd', 'XMLSchema.dtd'), outputDir) try: import shutil, errno shutil.copytree(schemasDir / "common", outputDir / "common") shutil.copytree(schemasDir / "extend", outputDir / "extend") shutil.copytree(schemasDir / "unique", outputDir / "unique") shutil.copytree(schemasDir / "vocab", outputDir / "vocab") except OSError as exc: if exc.errno == errno.ENOTDIR: shutil.copy(schemasDir, outputDir) else: raise # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False hasFX = False hasSH = False hasGames = False hasElpLink = False hasWikipedia = False isBreak = False hasInstructions = False hasMediaelement = False hasTooltips = False hasABCMusic = False listIdevicesFiles = [] for page in self.pages: if isBreak: break for idevice in page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasSH and hasGames and hasElpLink and hasWikipedia and hasInstructions and hasMediaelement and hasTooltips and hasABCMusic): isBreak = True break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'mojomagnify.js' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: hasGallery = common.ideviceHasGallery(idevice) if not hasFX: hasFX = common.ideviceHasFX(idevice) if not hasSH: hasSH = common.ideviceHasSH(idevice) if not hasGames: hasGames = common.ideviceHasGames(idevice) if not hasElpLink: hasElpLink = common.ideviceHasElpLink(idevice, package) if not hasWikipedia: if 'WikipediaIdevice' == idevice.klass: hasWikipedia = True if not hasInstructions: if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass: hasInstructions = True if not hasMediaelement: hasMediaelement = common.ideviceHasMediaelement(idevice) if not hasTooltips: hasTooltips = common.ideviceHasTooltips(idevice) if not hasABCMusic: hasABCMusic = common.ideviceHasABCMusic(idevice) if hasattr(idevice, "_iDeviceDir"): listIdevicesFiles.append( (idevice.get_jsidevice_dir() / 'export')) common.exportJavaScriptIdevicesFiles(page.node.idevices, outputDir) if hasFlowplayer: videofile = (self.templatesDir / 'flowPlayer.swf') videofile.copyfile(outputDir / 'flowPlayer.swf') controlsfile = (self.templatesDir / 'flowplayer.controls.swf') controlsfile.copyfile(outputDir / 'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir / 'mojomagnify.js') videofile.copyfile(outputDir / 'mojomagnify.js') if hasXspfplayer: videofile = (self.templatesDir / 'xspf_player.swf') videofile.copyfile(outputDir / 'xspf_player.swf') if hasGallery: exeLightbox = (self.scriptsDir / 'exe_lightbox') exeLightbox.copyfiles(outputDir) if hasFX: exeEffects = (self.scriptsDir / 'exe_effects') exeEffects.copyfiles(outputDir) if hasSH: exeSH = (self.scriptsDir / 'exe_highlighter') exeSH.copyfiles(outputDir) if hasGames: exeGames = (self.scriptsDir / 'exe_games') exeGames.copyfiles(outputDir) # Add game js string to common_i18n langGameFile = open(outputDir + '/common_i18n.js', "a") langGameFile.write(common.getGamesJavaScriptStrings(False)) langGameFile.close() if hasElpLink or package.get_exportElp(): # Export the elp file currentPackagePath = Path(package.filename) currentPackagePath.copyfile(outputDir / package.name + '.elp') if hasWikipedia: wikipediaCSS = (self.cssDir / 'exe_wikipedia.css') wikipediaCSS.copyfile(outputDir / 'exe_wikipedia.css') if hasInstructions: common.copyFileIfNotInStyle('panel-amusements.png', self, outputDir) common.copyFileIfNotInStyle('stock-stop.png', self, outputDir) if hasMediaelement: mediaelement = (self.scriptsDir / 'mediaelement') mediaelement.copyfiles(outputDir) if dT != "HTML5": jsFile = (self.scriptsDir / 'exe_html5.js') if hasTooltips: exe_tooltips = (self.scriptsDir / 'exe_tooltips') exe_tooltips.copyfiles(outputDir) if hasABCMusic: pluginScripts = (self.scriptsDir / 'tinymce_4/js/tinymce/plugins/abcmusic/export') pluginScripts.copyfiles(outputDir) ext = ".html" if G.application.config.cutFileName == "1": ext = ".htm" if self.scormType == "scorm1.2" or self.scormType == "scorm2004": if package.license == "license GFDL": # include a copy of the GNU Free Documentation Licence (self.templatesDir / 'fdl' + ext).copyfile(outputDir / 'fdl' + ext) if hasattr(package, 'scowsinglepage') and package.scowsinglepage: page = SinglePage("singlepage_index", 1, package.root) page.save(outputDir / "singlepage_index" + ext) # Incluide eXe's icon if the Style doesn't have one themePath = Path(G.application.config.stylesDir / package.style) themeFavicon = themePath.joinpath("favicon.ico") if not themeFavicon.exists(): faviconFile = (self.imagesDir / 'favicon.ico') faviconFile.copyfile(outputDir / 'favicon.ico') if hasattr(package, 'scowwebsite') and package.scowwebsite: website = WebsiteExport(self.config, self.styleDir, outputDir, "website_") website.export(package) (self.styleDir / 'nav.css').copyfile(outputDir / 'nav.css') # Incluide eXe's icon if the Style doesn't have one themePath = Path(G.application.config.stylesDir / package.style) themeFavicon = themePath.joinpath("favicon.ico") if not themeFavicon.exists(): faviconFile = (self.imagesDir / 'favicon.ico') faviconFile.copyfile(outputDir / 'favicon.ico') if hasattr(package, 'exportSource') and package.exportSource: (G.application.config.webDir / 'templates' / 'content.xsd').copyfile(outputDir / 'content.xsd') (outputDir / 'content.data').write_bytes(encodeObject(package)) (outputDir / 'contentv3.xml').write_bytes( encodeObjectToXML(package)) # Zip it up! self.filename.safeSave( self.doZip, _('EXPORT FAILED!\nLast succesful export is %s.'), outputDir) # Clean up the temporary dir outputDir.rmtree() return modifiedMetaData
class SinglePageExport(object): """ SinglePageExport will export a package as a website of HTML pages """ def __init__(self, stylesDir, outputDir, imagesDir, scriptsDir, cssDir, templatesDir): """ 'stylesDir' is the directory where we can copy the stylesheets from 'outputDir' is the directory that will be [over]written with the website """ self.html = "" self.style = None self.name = None self.stylesDir = Path(stylesDir) self.outputDir = Path(outputDir) self.imagesDir = Path(imagesDir) self.scriptsDir = Path(scriptsDir) self.cssDir = Path(cssDir) self.templatesDir = Path(templatesDir) self.page = None # Create the output dir if it doesn't already exist if not self.outputDir.exists(): self.outputDir.mkdir() def export(self, package, for_print=0): """ Export web site Cleans up the previous packages pages and performs the export """ self.style = package.style self.page = SinglePage("index", 1, package.root) ext = 'html' if G.application.config.cutFileName == "1": ext = 'htm' self.page.save(self.outputDir / "index" + '.' + ext, for_print) if hasattr(package, 'exportSource') and package.exportSource and not for_print: (G.application.config.webDir / 'templates' / 'content.xsd').copyfile(self.outputDir / 'content.xsd') (self.outputDir / 'content.data').write_bytes( encodeObject(package)) (self.outputDir / 'contentv3.xml').write_bytes( encodeObjectToXML(package)) self.copyFiles(package) def copyFiles(self, package): """ Copy all the files used by the website. """ # Copy the style files to the output dir # But not nav.css if os.path.isdir(self.stylesDir): styleFiles = [self.stylesDir / '..' / 'popup_bg.gif'] styleFiles += self.stylesDir.files("*.*") if "nav.css" in styleFiles: styleFiles.remove("nav.css") self.stylesDir.copylist(styleFiles, self.outputDir) # copy the package's resource files package.resourceDir.copyfiles(self.outputDir) listCSSFiles = getFilesCSSToMinify('singlepage', self.stylesDir) exportMinFileCSS(listCSSFiles, self.outputDir) # copy script files. my_style = G.application.config.styleStore.getStyle(package.style) # jQuery if my_style.hasValidConfig: if my_style.get_jquery() == True: jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(self.outputDir / 'exe_jquery.js') else: jsFile = (self.scriptsDir / 'exe_jquery.js') jsFile.copyfile(self.outputDir / 'exe_jquery.js') dT = common.getExportDocType() if dT == "HTML5": jsFile = (self.scriptsDir / 'exe_html5.js') jsFile.copyfile(self.outputDir / 'exe_html5.js') # Minify common.js file listFiles = getFilesJSToMinify('singlepage', self.scriptsDir) exportMinFileJS(listFiles, self.outputDir) # Incluide eXe's icon if the Style doesn't have one themePath = Path(G.application.config.stylesDir / package.style) themeFavicon = themePath.joinpath("favicon.ico") if not themeFavicon.exists(): faviconFile = (self.imagesDir / 'favicon.ico') faviconFile.copyfile(self.outputDir / 'favicon.ico') #JR Metemos los reproductores necesarios self.compruebaReproductores(self.page.node) if package.license == "license GFDL": # include a copy of the GNU Free Documentation Licence ext = 'html' if G.application.config.cutFileName == "1": ext = 'htm' (self.templatesDir / 'fdl' + '.' + ext).copyfile(self.outputDir / 'fdl' + '.' + ext) def compruebaReproductores(self, node): """ Comprobamos si hay que meter algun reproductor """ # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False hasGallery = False hasFX = False hasSH = False hasGames = False hasWikipedia = False hasInstructions = False hasMediaelement = False hasTooltips = False hasABCMusic = False for idevice in node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer and hasGallery and hasFX and hasSH and hasGames and hasWikipedia and hasInstructions and hasMediaelement and hasTooltips and hasABCMusic): break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'mojomagnify.js' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if not hasGallery: hasGallery = common.ideviceHasGallery(idevice) if not hasFX: hasFX = common.ideviceHasFX(idevice) if not hasSH: hasSH = common.ideviceHasSH(idevice) if not hasGames: hasGames = common.ideviceHasGames(idevice) if not hasWikipedia: if 'WikipediaIdevice' == idevice.klass: hasWikipedia = True if not hasInstructions: if 'TrueFalseIdevice' == idevice.klass or 'MultichoiceIdevice' == idevice.klass or 'VerdaderofalsofpdIdevice' == idevice.klass or 'EleccionmultiplefpdIdevice' == idevice.klass: hasInstructions = True if not hasMediaelement: hasMediaelement = common.ideviceHasMediaelement(idevice) if not hasTooltips: hasTooltips = common.ideviceHasTooltips(idevice) if not hasABCMusic: hasABCMusic = common.ideviceHasABCMusic(idevice) if hasFlowplayer: videofile = (self.templatesDir / 'flowPlayer.swf') videofile.copyfile(self.outputDir / 'flowPlayer.swf') controlsfile = (self.templatesDir / 'flowplayer.controls.swf') controlsfile.copyfile(self.outputDir / 'flowplayer.controls.swf') if hasMagnifier: videofile = (self.templatesDir / 'mojomagnify.js') videofile.copyfile(self.outputDir / 'mojomagnify.js') if hasXspfplayer: videofile = (self.templatesDir / 'xspf_player.swf') videofile.copyfile(self.outputDir / 'xspf_player.swf') if hasGallery: exeLightbox = (self.scriptsDir / 'exe_lightbox') exeLightbox.copyfiles(self.outputDir) if hasFX: exeEffects = (self.scriptsDir / 'exe_effects') exeEffects.copyfiles(self.outputDir) if hasSH: exeSH = (self.scriptsDir / 'exe_highlighter') exeSH.copyfiles(self.outputDir) if hasGames: exeGames = (self.scriptsDir / 'exe_games') exeGames.copyfiles(self.outputDir) if hasWikipedia: wikipediaCSS = (self.cssDir / 'exe_wikipedia.css') wikipediaCSS.copyfile(self.outputDir / 'exe_wikipedia.css') if hasInstructions: common.copyFileIfNotInStyle('panel-amusements.png', self, self.outputDir) common.copyFileIfNotInStyle('stock-stop.png', self, self.outputDir) if hasMediaelement: mediaelement = (self.scriptsDir / 'mediaelement') mediaelement.copyfiles(self.outputDir) dT = common.getExportDocType() if dT != "HTML5": jsFile = (self.scriptsDir / 'exe_html5.js') jsFile.copyfile(self.outputDir / 'exe_html5.js') if hasTooltips: exe_tooltips = (self.scriptsDir / 'exe_tooltips') exe_tooltips.copyfiles(self.outputDir) if hasABCMusic: pluginScripts = (self.scriptsDir / 'tinymce_4/js/tinymce/plugins/abcmusic/export') pluginScripts.copyfiles(self.outputDir) for child in node.children: self.compruebaReproductores(child) def hasUncutResources(self): """ Check if any of the resources in the exported package has an uncut filename """ for idevice in self.page.node.idevices: for resource in idevice.userResources: if type(resource) == Resource and len( resource.storageName) > 12: return True return False
class Config: """ The Config class contains the configuration information for eXe. """ # Class attributes optionNames = { 'idevices': ('someone', ), 'system': ('webDir', 'xulDir', 'port', 'dataDir', 'configDir', 'localeDir', 'browserPath'), 'user': ('locale', ), } def __init__(self): """ Initialise """ self.configPath = None self.configParser = ConfigParser(self.onWrite) # Set default values # idevices is the list of hidden idevices selected by the user self.someone = 0 # exePath is the whole path and filename of the exe executable self.exePath = Path(sys.argv[0]).abspath() # webDir is the parent directory for styles,scripts and templates self.webDir = self.exePath.dirname() # xulDir is the parent directory for styles,scripts and templates self.xulDir = self.exePath.dirname() # localeDir is the base directory where all the locales are stored self.localeDir = self.exePath.dirname() / "locale" # port is the port the exe webserver will listen on # (previous default, which earlier users might still use, was 8081) self.port = 51235 # dataDir is the default directory that is shown to the user # to save packages and exports in self.dataDir = Path(".") # configDir is the dir for storing user profiles # and user made idevices and the config file self.configDir = Path(".") # browserPath is the entire pathname to firefox self.browserPath = Path("firefox") # locale is the language of the user self.locale = chooseDefaultLocale(self.localeDir) # internalAnchors indicate which exe_tmp_anchor tags to generate for each tinyMCE field # available values = "enable_all", "disable_autotop", or "disable_all" self.internalAnchors = "enable_all" # styles is the list of style names available for loading self.styles = [] # The documents that we've recently looked at self.recentProjects = [] # canonical (English) names of iDevices not to show in the iDevice pane self.hiddeniDevices = [] # likewise, a canonical (English) names of iDevices not to show in the # iDevice pane but, contrary to the hiddens, these are ones that the # configuration can specify to turn ON: self.deprecatediDevices = [ "flash with text", "flash movie", "mp3", \ "attachment"] # by default, only allow embedding of media types for which a # browser plugin is found: self.assumeMediaPlugins = False # Let our children override our defaults depending # on the OS that we're running on self._overrideDefaultVals() # Try to make the defaults a little intelligent # Under devel trees, webui is the default webdir self.webDir = Path(self.webDir) if not (self.webDir/'scripts').isdir() \ and (self.webDir/'webui').isdir(): self.webDir /= 'webui' # Under devel trees, xului is the default xuldir self.xulDir = Path(self.xulDir) if not (self.xulDir/'scripts').isdir() \ and (self.xulDir/'xului').isdir(): self.xulDir /= 'xului' # Find where the config file will be saved self.__setConfigPath() # Fill in any undefined config options with our defaults self._writeDefaultConfigFile() # Now we are ready to serve the application self.loadSettings() self.setupLogging() self.loadStyles() self.loadLocales() def _overrideDefaultVals(self): """ Override this to override the default config values """ def _getConfigPathOptions(self): """ Override this to give a list of possible config filenames in order of preference """ return ['exe.conf'] def _writeDefaultConfigFile(self): """ [Over]writes 'self.configPath' with a default config file (auto write is on so we don't need to write the file at the end) """ for sectionName, optionNames in self.optionNames.items(): for optionName in optionNames: defaultVal = getattr(self, optionName) self.configParser.setdefault(sectionName, optionName, defaultVal) # Logging can't really be changed from inside the program at the moment... self.configParser.setdefault('logging', 'root', 'INFO') def __setConfigPath(self): """ sets self.configPath to the filename of the config file that we'll use. In descendant classes set self.configFileOptions to a list of directories where the configDir should be in order of preference. If no config files can be found in these dirs, it will force creation of the config file in the top dir """ # If there's an EXECONF environment variable, use it self.configPath = None configFileOptions = map(Path, self._getConfigPathOptions()) if "EXECONF" in os.environ: envconf = Path(os.environ["EXECONF"]) if envconf.isfile(): self.configPath = os.environ["EXECONF"] # Otherwise find the most appropriate existing file if self.configPath is None: for confPath in configFileOptions: if confPath.isfile(): self.configPath = confPath break else: # If no config files exist, create and use the # first one on the list self.configPath = configFileOptions[0] folder = self.configPath.abspath().dirname() if not folder.exists(): folder.makedirs() self.configPath.touch() # Now make our configParser self.configParser.read(self.configPath) self.configParser.autoWrite = True def upgradeFile(self): """ Called before loading the config file, removes or upgrades any old settings. """ if self.configParser.has_section('system'): system = self.configParser.system if system.has_option('appDataDir'): # Older config files had configDir stored as appDataDir self.configDir = Path(system.appDataDir) # We'll just upgrade their config file for them for now... system.configDir = self.configDir del system.appDataDir if system.has_option('greDir'): # No longer used, system should automatically support del system.greDir def loadSettings(self): """ Loads the settings from the exe.conf file. Overrides the defaults set in __init__ """ # Set up the parser so that if a certain value is not in the config # file, it will use the value from our default values def defVal(dummy, option): """If something is not in the config file, just use the default in 'self'""" return getattr(self, option) self.configParser.defaultValue = defVal self.upgradeFile() # System Section if self.configParser.has_section('system'): system = self.configParser.system self.webDir = Path(system.webDir) self.xulDir = Path(system.xulDir) self.localeDir = Path(system.localeDir) self.port = int(system.port) self.browserPath = Path(system.browserPath) self.dataDir = Path(system.dataDir) self.configDir = Path(system.configDir) self.assumeMediaPlugins = False if self.configParser.has_option('system', \ 'assumeMediaPlugins'): value = system.assumeMediaPlugins.strip().lower() if value == "1" or value == "yes" or value == "true" or \ value == "on": self.assumeMediaPlugins = True # If the dataDir points to some other dir, fix it if not self.dataDir.isdir(): self.dataDir = tempfile.gettempdir() # make the webDir absolute, to hide path joins of relative paths self.webDir = self.webDir.expand().abspath() # If the configDir doesn't exist (as it may be a default setting with a # new installation) create it if not self.configDir.exists(): self.configDir.mkdir() # Get the list of recently opened projects self.recentProjects = [] if self.configParser.has_section('recent_projects'): recentProjectsSection = self.configParser.recent_projects for key, path in recentProjectsSection.items(): self.recentProjects.append(path) # Load the list of "hidden" iDevices self.hiddeniDevices = [] if self.configParser.has_section('idevices'): idevicesSection = self.configParser.idevices for key, value in idevicesSection.items(): # emulate standard library's getboolean() value = value.strip().lower() if value == "0" or value == "no" or value == "false" or \ value == "off": self.hiddeniDevices.append(key.lower()) #self.deprecatediDevices = [ "flash with text", "flash movie", ...] # and UN-Load from the list of "deprecated" iDevices if self.configParser.has_section('deprecated'): deprecatedSection = self.configParser.deprecated for key, value in deprecatedSection.items(): # emulate standard library's getboolean() value = value.strip().lower() if value == "1" or value == "yes" or value == "true" or \ value == "on": if key.lower() in self.deprecatediDevices: self.deprecatediDevices.remove(key.lower()) # Load the "user" section if self.configParser.has_section('user'): if self.configParser.user.has_option('internalAnchors'): self.internalAnchors = self.configParser.user.internalAnchors if self.configParser.user.has_option('locale'): self.locale = self.configParser.user.locale return self.locale = chooseDefaultLocale(self.localeDir) def onWrite(self, configParser): """ Called just before the config file is written. We use it to fill out any settings that are stored here and not in the config parser itself """ # Recent projects self.configParser.delete('recent_projects') recentProjectsSection = self.configParser.addSection('recent_projects') for num, path in enumerate(self.recentProjects): recentProjectsSection[str(num)] = path def setupLogging(self): """ setup logging file """ try: hdlr = RotatingFileHandler(self.configDir / 'exe.log', 'a', 500000, 10) hdlr.doRollover() except OSError: # ignore the error we get if the log file is logged hdlr = logging.FileHandler(self.configDir / 'exe.log') format = "%(asctime)s %(name)s %(levelname)s %(message)s" log = logging.getLogger() hdlr.setFormatter(logging.Formatter(format)) log.addHandler(hdlr) loggingLevels = { "DEBUG": logging.DEBUG, "INFO": logging.INFO, "WARNING": logging.WARNING, "ERROR": logging.ERROR, "CRITICAL": logging.CRITICAL } if self.configParser.has_section('logging'): for logger, level in self.configParser._sections["logging"].items( ): if logger == "root": logging.getLogger().setLevel(loggingLevels[level]) else: logging.getLogger(logger).setLevel(loggingLevels[level]) log.info("************** eXe logging started **************") log.info("configPath = %s" % self.configPath) log.info("exePath = %s" % self.exePath) log.info("browserPath = %s" % self.browserPath) log.info("webDir = %s" % self.webDir) log.info("xulDir = %s" % self.xulDir) log.info("localeDir = %s" % self.localeDir) log.info("port = %d" % self.port) log.info("dataDir = %s" % self.dataDir) log.info("configDir = %s" % self.configDir) log.info("locale = %s" % self.locale) log.info("internalAnchors = %s" % self.internalAnchors) def loadStyles(self): """ Scans the eXe style directory and builds a list of styles """ log = logging.getLogger() self.styles = [] styleDir = self.webDir / "style" log.debug("loadStyles from %s" % styleDir) for subDir in styleDir.dirs(): styleSheet = subDir / 'content.css' log.debug(" checking %s" % styleSheet) if styleSheet.exists(): style = subDir.basename() log.debug(" loading style %s" % style) self.styles.append(style) def loadLocales(self): """ Scans the eXe locale directory and builds a list of locales """ log = logging.getLogger() log.debug("loadLocales") gettext.install('exe', self.localeDir, True) self.locales = {} for subDir in self.localeDir.dirs(): if (subDir / 'LC_MESSAGES' / 'exe.mo').exists(): self.locales[subDir.basename()] = \ gettext.translation('exe', self.localeDir, languages=[str(subDir.basename())]) if subDir.basename() == self.locale: locale = subDir.basename() log.debug(" loading locale %s" % locale) self.locales[locale].install(unicode=True) # ===========================================================================
class WinConfig(Config): """ The WinConfig overrides the Config class with Windows specific configuration """ def _overrideDefaultVals(self): """Sets the default values for windows""" self.exePath = Path(sys.argv[0]).abspath() if not self.exePath.exists(): self.exePath = Path(self.exePath + ".exe") exeDir = self.exePath.dirname() self.dataDir = Path(self.__getWinFolder(MYDOCUMENTS)) self.lastDir = Path(self.__getWinFolder(MYDOCUMENTS)) self.configDir = Path(self.__getWinFolder(APPDATA)) / 'exe' self.stylesDir = Path(self.configDir) / 'style' self.videoMediaConverter_ogv = "" self.videoMediaConverter_3gp = 'ffmpeg -i %(infile)s -s qcif -vcodec h263 -acodec libvo_aacenc -ac 1 -ar 8000 -r 25 -ab 32 -y %(outfile)s' self.videoMediaConverter_mpg = "ffmpeg -i %(infile)s -s qcif -vcodec mpeg1 -acodec wav -ac 1 -ar 8000 -r 25 -ab 32 -y %(outfile)s" self.audioMediaConverter_au = "sox %(infile)s %(outfile)s" self.audioMediaConverter_wav = "sox %(infile)s %(outfile)s" self.audioMediaConverter_mp3 = "sox %(infile)s -t wav - | lame -b 32 - %(outfile)s" self.ffmpegPath = "ffmpeg" def _getConfigPathOptions(self): """ Returns the best options for the location of the config file under windows """ # Find out where our nice config file is folders = map(self.__getWinFolder, [APPDATA, COMMON_APPDATA]) # Add unique dir names folders = [folder / 'exe' for folder in folders] folders.append(self.__getInstallDir()) folders.append('.') # Filter out non existant folders options = [folder / 'exe.conf' for folder in map(Path, folders)] return options def __getWinFolder(self, code): """ Gets one of the windows famous directorys depending on 'code' Possible values can be found at: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/enums/csidl.asp#CSIDL_WINDOWS """ from ctypes import WinDLL, create_unicode_buffer dll = WinDLL('shell32') # The '5' and the '0' from the below call come from # google: "ShellSpecialConstants site:msdn.microsoft.com" result = create_unicode_buffer(260) resource = dll.SHGetFolderPathW(None, code, None, 0, result) if resource != 0: return Path('') else: return Path(result.value) def __getInstallDir(self): """ Returns the path to where we were installed """ from _winreg import OpenKey, QueryValue, HKEY_LOCAL_MACHINE try: exeKey = None softwareKey = None try: softwareKey = OpenKey(HKEY_LOCAL_MACHINE, 'SOFTWARE') exeKey = OpenKey(softwareKey, 'exe') return Path(QueryValue(exeKey, '')) finally: if exeKey: exeKey.Close() if softwareKey: softwareKey.Close() except WindowsError: return Path('') def getLongPathName(self, path): """ Convert from Win32 short pathname to long pathname """ from ctypes import windll, create_unicode_buffer buf = create_unicode_buffer(260) r = windll.kernel32.GetLongPathNameW(unicode(path), buf, 260) if r == 0 or r > 260: return path else: return buf.value
class SinglePageExport(object): """ SinglePageExport will export a package as a website of HTML pages """ def __init__(self, stylesDir, outputDir, imagesDir, scriptsDir, templatesDir): """ 'stylesDir' is the directory where we can copy the stylesheets from 'outputDir' is the directory that will be [over]written with the website """ self.html = "" self.style = None self.name = None self.stylesDir = Path(stylesDir) self.outputDir = Path(outputDir) self.imagesDir = Path(imagesDir) self.scriptsDir = Path(scriptsDir) self.templatesDir = Path(templatesDir) self.page = None # Create the output dir if it doesn't already exist if not self.outputDir.exists(): self.outputDir.mkdir() def export(self, package, for_print=0): """ Export web site Cleans up the previous packages pages and performs the export """ self.style = package.style self.page = SinglePage("index", 1, package.root) self.page.save(self.outputDir/"index.html", for_print) self.copyFiles(package) def copyFiles(self, package): """ Copy all the files used by the website. """ # Copy the style sheet files to the output dir # But not nav.css styleFiles = [self.stylesDir/'..'/'base.css'] styleFiles += [self.stylesDir/'..'/'popup_bg.gif'] styleFiles += self.stylesDir.files("*.css") if "nav.css" in styleFiles: styleFiles.remove("nav.css") styleFiles += self.stylesDir.files("*.jpg") styleFiles += self.stylesDir.files("*.gif") styleFiles += self.stylesDir.files("*.png") styleFiles += self.stylesDir.files("*.js") styleFiles += self.stylesDir.files("*.html") self.stylesDir.copylist(styleFiles, self.outputDir) # copy the package's resource files package.resourceDir.copyfiles(self.outputDir) # copy script files. - modification by lernmodule.net self.scriptsDir.copylist(('libot_drag.js', 'common.js','lernmodule_net.js'), self.outputDir) # copy players for media idevices. hasFlowplayer = False hasMagnifier = False hasXspfplayer = False for idevice in self.page.node.idevices: if (hasFlowplayer and hasMagnifier and hasXspfplayer): break if not hasFlowplayer: if 'flowPlayer.swf' in idevice.systemResources: hasFlowplayer = True if not hasMagnifier: if 'magnifier.swf' in idevice.systemResources: hasMagnifier = True if not hasXspfplayer: if 'xspf_player.swf' in idevice.systemResources: hasXspfplayer = True if hasFlowplayer: videofile = (self.templatesDir/'flowPlayer.swf') videofile.copyfile(self.outputDir/'flowPlayer.swf') if hasMagnifier: videofile = (self.templatesDir/'magnifier.swf') videofile.copyfile(self.outputDir/'magnifier.swf') if hasXspfplayer: videofile = (self.templatesDir/'xspf_player.swf') videofile.copyfile(self.outputDir/'xspf_player.swf') if package.license == "GNU Free Documentation License": # include a copy of the GNU Free Documentation Licence (self.templatesDir/'fdl.html').copyfile(self.outputDir/'fdl.html')