示例#1
0
def buildDmg(startDir):
    fstartDir = Filename.fromOsSpecific(startDir)
    rootFilename = Filename(fstartDir, 'bundle')
    output = Filename(fstartDir, 'nppanda3d.dmg')
    output.unlink()
    cmd = 'hdiutil create -fs HFS+ -srcfolder "%(dir)s" -volname "%(volname)s" "%(output)s"' % {
        'dir': rootFilename.toOsSpecific(),
        'volname': 'nppanda3d',
        'output': output.toOsSpecific(),
    }
    os.system(cmd)
def buildDmg(startDir):
    fstartDir = Filename.fromOsSpecific(startDir)
    rootFilename = Filename(fstartDir, 'bundle')
    output = Filename(fstartDir, 'nppanda3d.dmg')
    output.unlink()
    cmd = 'hdiutil create -fs HFS+ -srcfolder "%(dir)s" -volname "%(volname)s" "%(output)s"' % {
        'dir' : rootFilename.toOsSpecific(),
        'volname' : 'nppanda3d',
        'output' : output.toOsSpecific(),
        }
    os.system(cmd)
    def onSave(self, event=None):
#        dlg = wx.FileDialog(self.frame, "Choose a location to save the source file", \
#        defaultDir= base.le.currentProj.dir.toOsSpecific(),\
#        defaultFile = 'conversation' + '.xml', wildcard="*.xml", style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
        
        dlg = wx.TextEntryDialog(self.frame, "Choose a name for this conversation", defaultValue=self.convoName)    
        
        if dlg.ShowModal() == wx.ID_OK:
            name = dlg.GetValue()
            if name in base.le.lib.conversations:
                messageDlg = wx.MessageDialog(self.frame, "\"%s\" already exists, do you want to overwrite?" %(name))
                if messageDlg.ShowModal() == wx.ID_OK:
                    #print 'overwrite it'
                    base.le.lib.removeConversation(name)
                else:
                    #print 'do not overwrite it'
                    messageDlg.Destroy()
                    return
            else:
                self.convoName = name
                
            base.le.ui.SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
            
            #== Create temporary XML file for the asset
            doc = xml.dom.minidom.Document()
            root = doc.createElement("the_root")
            doc.appendChild(root)
            root.appendChild(self.conversation.encode(doc))
            
            tempFilePath = base.le.lib.projDir.toOsSpecific() + '/' + name + '.xml'
            assetFilename = Filename(tempFilePath)
            #print 'temporary file path for asset: ' + assetFilename.toOsSpecific()
    
            f = open(assetFilename.toOsSpecific(), 'w')
            f.write(doc.toxml())
            f.close()
            
            #== Make an Asset based on the temporary source file and add it to the library
            asset = ConversationAsset(name, assetFilename)
            base.le.lib.addConversation(asset, True)
            base.le.ui.storyObjUI.update()
            
            #== Remove the temporary source file
            tempFilename = Filename(tempFilePath)
            #print 'temporary file path to now delete: ' + tempFilename.toOsSpecific()
            os.remove(tempFilename.toOsSpecific())
            
            self.changesSinceLastSave = False
            
            base.le.ui.SetCursor(wx.StockCursor(wx.CURSOR_ARROW)) 
示例#4
0
 def saveNewsCache(self):
     cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename)
     try:
         file = open(cacheIndexFilename.toOsSpecific(), "w")
     except IOError, e:
         self.notify.warning("error opening news cache file %s: %s" % (cacheIndexFilename, str(e)))
         return
示例#5
0
    def addScene(self, name=None, sceneFile=None):
        if (name == None):
            suffix = len(self.scenes)
            defaultname = "default_"

            name = defaultname + str(suffix)
            sceneFile = Filename(name + ".scene")
            f = Filename(sceneFile)
            f.setDirname(self.dir.getFullpath())
            while (os.path.exists(f.toOsSpecific())
                   or self.filenameIndexes.has_key(
                       sceneFile.getBasenameWoExtension())):
                suffix += 1
                name = defaultname + str(suffix)
                sceneFile = Filename(name + ".scene")
                f = Filename(sceneFile)
                f.setDirname(self.dir.getFullpath())
        #if there is a name but no  sceneFile given for that name
        #create a file with that name
        #TO DO: make it more error prone, for example this is not checking
        #if the file with the name already exist in the folder. This part may not be
        #be used at all but should be thought about.
        if (sceneFile == None):
            sceneFile = Filename(name + ".scene")
        self.scenes[name] = sceneFile
        self.filenameIndexes[sceneFile.getBasenameWoExtension()] = sceneFile
        if (len(self.scenes) == 1):
            #self.sceneFilename = sceneFile
            self.sceneName = name

        #f = Filename(sceneFile)
        #f.setDirname(self.dir.getFullpath())
        self.scenesOrder = sorted(self.scenes)
        return (name, sceneFile)
示例#6
0
 def addScene(self,name=None, sceneFile=None):
     if(name == None):
         suffix = len(self.scenes)
         defaultname = "default_"
         
         name = defaultname+str(suffix)
         sceneFile = Filename(name+".scene")
         f = Filename(sceneFile)
         f.setDirname(self.dir.getFullpath())
         while(os.path.exists(f.toOsSpecific())or self.filenameIndexes.has_key(sceneFile.getBasenameWoExtension())):
             suffix += 1
             name = defaultname+str(suffix)
             sceneFile = Filename(name+".scene")
             f = Filename(sceneFile)
             f.setDirname(self.dir.getFullpath())
     #if there is a name but no  sceneFile given for that name
     #create a file with that name
     #TO DO: make it more error prone, for example this is not checking
     #if the file with the name already exist in the folder. This part may not be
     #be used at all but should be thought about.
     if(sceneFile == None):
          sceneFile = Filename(name+".scene")            
     self.scenes[name] = sceneFile
     self.filenameIndexes[sceneFile.getBasenameWoExtension()] = sceneFile
     if(len(self.scenes) == 1 ):
         #self.sceneFilename = sceneFile
         self.sceneName = name
     
     #f = Filename(sceneFile)
     #f.setDirname(self.dir.getFullpath())
     self.scenesOrder = sorted(self.scenes)
     return (name,sceneFile)
示例#7
0
    def saveNewsCache(self):
        """ Saves self.newsCache to cache_index.txt """
        cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename)

        file = open(cacheIndexFilename.toOsSpecific(), 'w')
        for filename, (size, date) in self.newsCache.items():
            print >> file, '%s\t%s\t%s' % (filename, size, date)
    def downloadDescFileGenerator(self, http):
        """ A generator function that implements downloadDescFile()
        one piece at a time.  It yields one of stepComplete,
        stepFailed, or stepContinue. """

        assert self.descFile

        if self.hasDescFile:
            # We've already got one.
            yield self.stepComplete
            return

        if self.host.appRunner and self.host.appRunner.verifyContents != self.host.appRunner.P3DVCNever:
            # We're allowed to download it.
            self.http = http

            func = lambda step, self=self: self.__downloadFile(
                None, self.descFile, urlbase=self.descFile.filename, filename=self.descFileBasename
            )
            step = self.InstallStep(func, self.descFile.size, self.downloadFactor, "downloadDesc")

            for token in step.func():
                if token == self.stepContinue:
                    yield token
                else:
                    break

            while token == self.restartDownload:
                # Try again.
                func = lambda step, self=self: self.__downloadFile(
                    None, self.descFile, urlbase=self.descFile.filename, filename=self.descFileBasename
                )
                step = self.InstallStep(func, self.descFile.size, self.downloadFactor, "downloadDesc")
                for token in step.func():
                    if token == self.stepContinue:
                        yield token
                    else:
                        break

            if token == self.stepFailed:
                # Couldn't download the desc file.
                yield self.stepFailed
                return

            assert token == self.stepComplete

            filename = Filename(self.getPackageDir(), self.descFileBasename)
            # Now that we've written the desc file, make it read-only.
            os.chmod(filename.toOsSpecific(), 0444)

        if not self.__readDescFile():
            # Weird, it passed the hash check, but we still can't read
            # it.
            filename = Filename(self.getPackageDir(), self.descFileBasename)
            self.notify.warning("Failure reading %s" % (filename))
            yield self.stepFailed
            return

        yield self.stepComplete
        return
示例#9
0
 def saveNewsCache(self):
     cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename)
     try:
         file = open(cacheIndexFilename.toOsSpecific(), 'w')
     except IOError, e:
         self.notify.warning('error opening news cache file %s: %s' % (cacheIndexFilename, str(e)))
         return
示例#10
0
    def __uncompressArchive(self, step):
        """ Turns the compressed archive into the uncompressed
        archive.  Yields one of stepComplete, stepFailed, 
        restartDownload, or stepContinue. """

        if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever:
            # We're not allowed to!
            yield self.stepFailed
            return

        self.updated = True

        sourcePathname = Filename(self.getPackageDir(),
                                  self.compressedArchive.filename)
        targetPathname = Filename(self.getPackageDir(),
                                  self.uncompressedArchive.filename)
        targetPathname.unlink()
        self.notify.info("Uncompressing %s to %s" %
                         (sourcePathname, targetPathname))
        decompressor = Decompressor()
        decompressor.initiate(sourcePathname, targetPathname)
        totalBytes = self.uncompressedArchive.size
        result = decompressor.run()
        while result == EUOk:
            step.bytesDone = int(totalBytes * decompressor.getProgress())
            self.__updateStepProgress(step)
            result = decompressor.run()
            if taskMgr.destroyed:
                # If the task manager has been destroyed, we must
                # be shutting down.  Get out of here.
                self.notify.warning(
                    "Task Manager destroyed, aborting decompresss %s" %
                    (sourcePathname))
                yield self.stepFailed
                return

            yield self.stepContinue

        if result != EUSuccess:
            yield self.stepFailed
            return

        step.bytesDone = totalBytes
        self.__updateStepProgress(step)

        if not self.uncompressedArchive.quickVerify(self.getPackageDir(),
                                                    notify=self.notify):
            self.notify.warning("after uncompressing, %s still incorrect" %
                                (self.uncompressedArchive.filename))
            yield self.stepFailed
            return

        # Now that we've verified the archive, make it read-only.
        os.chmod(targetPathname.toOsSpecific(), 0444)

        # Now we can safely remove the compressed archive.
        sourcePathname.unlink()
        yield self.stepComplete
        return
示例#11
0
def loadConversations(sceneFile, libraryFile): # Anton added 2/24
    sceneFilename = Filename(sceneFile)
    libraryFilename = Filename.fromOsSpecific(os.getcwd()) + '/' + libraryFile
    lib = Library(Filename(libraryFilename.getDirname()))
    assetIndex = AssetIndex(lib)
    
    conversationAssets = assetIndex.conversations
    conversationObjects = {}
    
    for key, filename in conversationAssets.items():
        xmlFilename = Filename(filename)
        doc = xml.dom.minidom.parse(xmlFilename.toOsSpecific())
        Debug.debug(__name__,'loading '+str(xmlFilename.toOsSpecific())+'...')
        convo = Conversation.decode(doc)
        conversationObjects[key] = convo
    
    return conversationObjects
示例#12
0
    def __init__(self, pathname, ignoreUsageXml=False):
        self.pathname = pathname
        self.filenames = []
        self.fileSize = 0
        self.nested = []
        self.nestedSize = 0

        xusage = None
        if not ignoreUsageXml:
            # Look for a usage.xml file in this directory.  If we find
            # one, we read it for the file size and then stop here, as
            # an optimization.
            usageFilename = Filename(pathname, 'usage.xml')
            doc = TiXmlDocument(usageFilename.toOsSpecific())
            if doc.LoadFile():
                xusage = doc.FirstChildElement('usage')
                if xusage:
                    diskSpace = xusage.Attribute('disk_space')
                    try:
                        diskSpace = int(diskSpace or '')
                    except ValueError:
                        diskSpace = None
                    if diskSpace is not None:
                        self.fileSize = diskSpace
                        return

        files = vfs.scanDirectory(self.pathname)
        if files is None:
            files = []
        for vfile in files:
            if hasattr(vfile, 'getMount'):
                if not isinstance(vfile.getMount(), VirtualFileMountSystem):
                    # Not a real file; ignore it.
                    continue

            if vfile.isDirectory():
                # A nested directory.
                subdir = ScanDirectoryNode(vfile.getFilename(),
                                           ignoreUsageXml=ignoreUsageXml)
                self.nested.append(subdir)
                self.nestedSize += subdir.getTotalSize()

            elif vfile.isRegularFile():
                # A nested file.
                self.filenames.append(vfile.getFilename())
                self.fileSize += vfile.getFileSize()

            else:
                # Some other wacky file thing.
                self.filenames.append(vfile.getFilename())

        if xusage:
            # Now update the usage.xml file with the newly-determined
            # disk space.
            xusage.SetAttribute('disk_space', str(self.getTotalSize()))
            tfile = Filename.temporary(pathname.cStr(), '.xml')
            if doc.SaveFile(tfile.toOsSpecific()):
                tfile.renameTo(usageFilename)
示例#13
0
    def exportScripts(self, file):
        outputLines = []
        tab = "    "
        outputLines.append("SCRIPTS_LIST = []\n\n")
        #whole file
        for script, asset in self.editor.lib.scripts.iteritems():

            #writing a script file to the whole file
            filename = self.editor.lib.scripts[script].getFullFilename()
            scriptFile = open(filename.toOsSpecific())

            lines = scriptFile.readlines()

            mainArguments = self.getArgumentsFromScriptFile(lines)
            scriptFunctionName = script
            if (len(mainArguments) == 0):
                prefix = "world"
            else:
                prefix = "world, "
            functionHeader = "\ndef " + scriptFunctionName + "(" + prefix + ",".join(
                mainArguments) + "):\n"
            mainFunc = "main(" + prefix + ",".join(mainArguments) + ")"
            mainFuncHeader = "def " + mainFunc + ":\n"
            outputLines.append(functionHeader)
            isReturn = False
            for line in lines:
                #print line
                if line.strip().startswith("#"):
                    continue
                if line.strip().startswith("def main"):
                    newline = mainFuncHeader
                elif line.find("Interface") != -1:
                    newline = line.replace('Interface',
                                           "world.scriptInterface")
                else:
                    newline = line
                if line.strip().startswith("return"):
                    isReturn = True
                outputLines.append(tab + newline)

            if (isReturn):
                outputLines.append("\n" + tab + "return " + mainFunc)
            else:
                outputLines.append("\n" + tab + mainFunc)
            outputLines.append("\nSCRIPTS_LIST.append(" + scriptFunctionName +
                               ")\n")
            scriptFile.close()
        scriptsFilename = Filename(
            Filename.fromOsSpecific(file).getDirname() + '/Scripts.py')

        try:
            scriptsFile = open(scriptsFilename.toOsSpecific(), 'w')
        except IOError:
            print "ERROR: Couldn't open the script file for writing"

        scriptsFile.writelines(outputLines)
        scriptsFile.close()
        return scriptsFilename
 def exportScripts(self, file):
     outputLines = []
     tab = "    "
     outputLines.append("SCRIPTS_LIST = []\n\n")
     #whole file
     for script, asset in self.editor.lib.scripts.iteritems():
         
         #writing a script file to the whole file
         filename = self.editor.lib.scripts[script].getFullFilename()
         scriptFile = open(filename.toOsSpecific())
         
         lines = scriptFile.readlines()
         
         mainArguments = self.getArgumentsFromScriptFile(lines)
         scriptFunctionName = script
         if(len(mainArguments) == 0):
             prefix = "world"
         else:
             prefix = "world, "
         functionHeader = "\ndef "+scriptFunctionName+"("+prefix+",".join(mainArguments)+"):\n"
         mainFunc = "main("+prefix+",".join(mainArguments)+")"
         mainFuncHeader = "def "+mainFunc+":\n"
         outputLines.append(functionHeader)
         isReturn = False
         for line in lines:
             #print line
             if line.strip().startswith("#"):
                 continue
             if line.strip().startswith("def main"):
                 newline = mainFuncHeader
             elif line.find("Interface")!=-1:
                 newline = line.replace('Interface', "world.scriptInterface")
             else:
                 newline = line
             if line.strip().startswith("return"):
                 isReturn = True
             outputLines.append(tab+newline)
         
         if(isReturn):   
             outputLines.append("\n"+tab+"return "+mainFunc)
         else:
             outputLines.append("\n"+tab+mainFunc)
         outputLines.append("\nSCRIPTS_LIST.append("+scriptFunctionName+")\n")
         scriptFile.close()
     scriptsFilename = Filename(Filename.fromOsSpecific(file).getDirname()+'/Scripts.py')
     
     
     
     
                                  
     try:
         scriptsFile = open(scriptsFilename.toOsSpecific(), 'w')
     except IOError:
         print "ERROR: Couldn't open the script file for writing"
     
     scriptsFile.writelines(outputLines)
     scriptsFile.close()
     return scriptsFilename
示例#15
0
def loadConversations(sceneFile, libraryFile):  # Anton added 2/24
    sceneFilename = Filename(sceneFile)
    libraryFilename = Filename.fromOsSpecific(os.getcwd()) + '/' + libraryFile
    lib = Library(Filename(libraryFilename.getDirname()))
    assetIndex = AssetIndex(lib)

    conversationAssets = assetIndex.conversations
    conversationObjects = {}

    for key, filename in conversationAssets.items():
        xmlFilename = Filename(filename)
        doc = xml.dom.minidom.parse(xmlFilename.toOsSpecific())
        Debug.debug(__name__,
                    'loading ' + str(xmlFilename.toOsSpecific()) + '...')
        convo = Conversation.decode(doc)
        conversationObjects[key] = convo

    return conversationObjects
    def __init__(self, pathname, ignoreUsageXml = False):
        self.pathname = pathname
        self.filenames = []
        self.fileSize = 0
        self.nested = []
        self.nestedSize = 0

        xusage = None
        if not ignoreUsageXml:
            # Look for a usage.xml file in this directory.  If we find
            # one, we read it for the file size and then stop here, as
            # an optimization.
            usageFilename = Filename(pathname, 'usage.xml')
            doc = TiXmlDocument(usageFilename.toOsSpecific())
            if doc.LoadFile():
                xusage = doc.FirstChildElement('usage')
                if xusage:
                    diskSpace = xusage.Attribute('disk_space')
                    try:
                        diskSpace = int(diskSpace or '')
                    except ValueError:
                        diskSpace = None
                    if diskSpace is not None:
                        self.fileSize = diskSpace
                        return

        files = vfs.scanDirectory(self.pathname)
        if files is None:
            files = []
        for vfile in files:
            if hasattr(vfile, 'getMount'):
                if not isinstance(vfile.getMount(), VirtualFileMountSystem):
                    # Not a real file; ignore it.
                    continue

            if vfile.isDirectory():
                # A nested directory.
                subdir = ScanDirectoryNode(vfile.getFilename(), ignoreUsageXml = ignoreUsageXml)
                self.nested.append(subdir)
                self.nestedSize += subdir.getTotalSize()

            elif vfile.isRegularFile():
                # A nested file.
                self.filenames.append(vfile.getFilename())
                self.fileSize += vfile.getFileSize()

            else:
                # Some other wacky file thing.
                self.filenames.append(vfile.getFilename())

        if xusage:
            # Now update the usage.xml file with the newly-determined
            # disk space.
            xusage.SetAttribute('disk_space', str(self.getTotalSize()))
            tfile = Filename.temporary(pathname.cStr(), '.xml')
            if doc.SaveFile(tfile.toOsSpecific()):
                tfile.renameTo(usageFilename)
示例#17
0
    def saveAs(self, newDir, newName, keepOld=False):
        if keepOld:
            shutil.copytree(self.dir.toOsSpecific(), newDir.toOsSpecific())
        else:
            if not os.path.exists(newDir.toOsSpecific()):
                os.makedirs(newDir.toOsSpecific())
            for x in os.listdir(self.dir.toOsSpecific()):
                shutil.move((self.dir + '/' + x).toOsSpecific(),
                            (newDir + '/' + x).toOsSpecific())

        #make sure everything in the new directory is not marked read only
        for root, dirs, files in os.walk(newDir.toOsSpecific()):
            for name in files:
                os.chmod(os.path.join(root, name), stat.S_IWRITE)

        newFilename = newDir + '/' + newName + '.proj'
        newSceneFilename = Filename(newName + '.scene')
        newJournalFilename = Filename(newName + '.journal')
        newInventoryMapFilename = Filename(newName + '.inventory')

        f = Filename(self.filename)
        f.setDirname(newDir.getFullpath())

        f2 = Filename(self.scenes[self.sceneName])  #self.sceneFilename)
        f2.setDirname(newDir.getFullpath())

        f3 = Filename(self.journalFilename)
        f3.setDirname(newDir.getFullpath())

        f4 = Filename(self.inventoryMapFilename)
        f4.setDirname(newDir.getFullpath())

        #make sure we don't end up with a project or scene file with the old name
        #in the new directory
        if os.path.exists(f.toOsSpecific()):
            os.remove(f.toOsSpecific())
        if os.path.exists(f2.toOsSpecific()):
            os.remove(f2.toOsSpecific())
        if os.path.exists(f3.toOsSpecific()):
            os.remove(f3.toOsSpecific())
        if os.path.exists(f4.toOsSpecific()):
            os.remove(f4.toOsSpecific())

        self.name = newName
        self.dir = newDir
        self.filename = newFilename
        #self.scenes["default"] = newSceneFilename
        #self.sceneFilename = newSceneFilename
        self.journalFilename = newJournalFilename
        self.inventoryMapFilename = newInventoryMapFilename

        self.lib.moveTo(newDir)

        self.saveToFile()
示例#18
0
 def saveAs(self, newDir, newName, keepOld=False):
     if keepOld:
         shutil.copytree(self.dir.toOsSpecific(), newDir.toOsSpecific())
     else:
         if not os.path.exists(newDir.toOsSpecific()):
             os.makedirs(newDir.toOsSpecific())
         for x in os.listdir(self.dir.toOsSpecific()):
             shutil.move((self.dir + '/' + x).toOsSpecific(), (newDir + '/' + x).toOsSpecific())
     
     #make sure everything in the new directory is not marked read only
     for root, dirs, files in os.walk(newDir.toOsSpecific()):
         for name in files:
             os.chmod(os.path.join(root, name), stat.S_IWRITE)
     
     newFilename = newDir + '/' +newName + '.proj'
     newSceneFilename = Filename(newName + '.scene')
     newJournalFilename = Filename(newName + '.journal')
     newInventoryMapFilename = Filename(newName + '.inventory')
     
     f = Filename(self.filename)
     f.setDirname(newDir.getFullpath())
     
     f2 = Filename(self.scenes[self.sceneName])#self.sceneFilename)
     f2.setDirname(newDir.getFullpath())
     
     f3 = Filename(self.journalFilename)
     f3.setDirname(newDir.getFullpath())
     
     f4 = Filename(self.inventoryMapFilename)
     f4.setDirname(newDir.getFullpath())
     
     #make sure we don't end up with a project or scene file with the old name
     #in the new directory
     if os.path.exists(f.toOsSpecific()):
         os.remove(f.toOsSpecific())
     if os.path.exists(f2.toOsSpecific()):
         os.remove(f2.toOsSpecific())
     if os.path.exists(f3.toOsSpecific()):
         os.remove(f3.toOsSpecific())
     if os.path.exists(f4.toOsSpecific()):
         os.remove(f4.toOsSpecific())
     
     self.name = newName   
     self.dir = newDir        
     self.filename = newFilename
     #self.scenes["default"] = newSceneFilename      
     #self.sceneFilename = newSceneFilename
     self.journalFilename = newJournalFilename
     self.inventoryMapFilename = newInventoryMapFilename
     
     self.lib.moveTo(newDir)
     
     self.saveToFile()
def makeBundle(startDir):
    fstartDir = Filename.fromOsSpecific(startDir)

    # Search for panda3d_mac along $PATH.
    path = DSearchPath()
    if 'PATH' in os.environ:
        path.appendPath(os.environ['PATH'])
    path.appendPath(os.defpath)
    panda3d_mac = path.findFile('panda3d_mac')
    if not panda3d_mac:
        raise StandardError, "Couldn't find panda3d_mac on path."

    # Construct a search path to look for the images.
    search = DSearchPath()

    # First on the path: an explicit $PLUGIN_IMAGES env var.
    if ExecutionEnvironment.hasEnvironmentVariable('PLUGIN_IMAGES'):
        search.appendDirectory(Filename.expandFrom('$PLUGIN_IMAGES'))

    # Next on the path: the models/plugin_images directory within the
    # current directory.
    search.appendDirectory('models/plugin_images')

    # Finally on the path: models/plugin_images within the model
    # search path.
    for dir in getModelPath().getDirectories():
        search.appendDirectory(Filename(dir, 'plugin_images'))

    # Now find the icon file on the above search path.
    icons = search.findFile('panda3d.icns')
    if not icons:
        raise StandardError, "Couldn't find panda3d.icns on model-path."

    # Generate the bundle directory structure
    rootFilename = Filename(fstartDir)
    bundleFilename = Filename(rootFilename, 'Panda3D.app')
    if os.path.exists(bundleFilename.toOsSpecific()):
        shutil.rmtree(bundleFilename.toOsSpecific())

    plistFilename = Filename(bundleFilename, 'Contents/Info.plist')
    plistFilename.makeDir()
    exeFilename = Filename(bundleFilename, 'Contents/MacOS/panda3d_mac')
    exeFilename.makeDir()
    iconFilename = Filename(bundleFilename, 'Contents/Resources/panda3d.icns')
    iconFilename.makeDir()

    # Copy in Info.plist, the icon file, and the compiled executable.
    shutil.copyfile(
        Filename(fstartDir, "panda3d_mac.plist").toOsSpecific(),
        plistFilename.toOsSpecific())
    shutil.copyfile(icons.toOsSpecific(), iconFilename.toOsSpecific())
    print panda3d_mac, exeFilename
    shutil.copyfile(panda3d_mac.toOsSpecific(), exeFilename.toOsSpecific())
    os.chmod(exeFilename.toOsSpecific(), 0755)

    # All done!
    bundleFilename.touch()
    print bundleFilename.toOsSpecific()
    def saveNewsCache(self):
        cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename)
        try:
            file = open(cacheIndexFilename.toOsSpecific(), 'w')
        except IOError as e:
            self.notify.warning('error opening news cache file %s: %s' % (cacheIndexFilename, str(e)))
            return

        for filename, (size, date) in self.newsCache.items():
            print >> file, '%s\t%s\t%s' % (filename, size, date)
示例#21
0
    def saveNewsCache(self):
        cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename)
        try:
            file = open(cacheIndexFilename.toOsSpecific(), 'w')
        except IOError as e:
            self.notify.warning('error opening news cache file %s: %s' % (cacheIndexFilename, str(e)))
            return

        for filename, (size, date) in self.newsCache.items():
            print >> file, '%s\t%s\t%s' % (filename, size, date)
    def buildArch(self, output, platform):
        """ Builds an ArchLinux package and stores it in the path
        indicated by the 'output' argument. It will be built for the
        architecture specified by the 'arch' argument.
        If 'output' is a directory, the deb file will be stored in it. """

        arch = platform.rsplit("_", 1)[-1]
        assert arch in ("i386", "amd64")
        arch = {"i386": "i686", "amd64": "x86_64"}[arch]
        pkgver = self.version + "-1"

        output = Filename(output)
        if output.isDirectory():
            output = Filename(
                output,
                "%s-%s-%s.pkg.tar.gz" % (self.shortname.lower(), pkgver, arch))
        Installer.notify.info("Creating %s..." % output)
        modtime = int(time.time())

        # Create a temporary directory and write the launcher and dependencies to it.
        tempdir, totsize = self.__buildTempLinux(platform)

        # Create a pkginfo file in memory.
        pkginfo = StringIO()
        print >> pkginfo, "# Generated using pdeploy"
        print >> pkginfo, "# %s" % time.ctime(modtime)
        print >> pkginfo, "pkgname = %s" % self.shortname.lower()
        print >> pkginfo, "pkgver = %s" % pkgver
        print >> pkginfo, "pkgdesc = %s" % self.fullname
        print >> pkginfo, "builddate = %s" % modtime
        print >> pkginfo, "packager = %s <%s>" % (self.authorname,
                                                  self.authoremail)
        print >> pkginfo, "size = %d" % totsize
        print >> pkginfo, "arch = %s" % arch
        if self.licensename != "":
            print >> pkginfo, "license = %s" % self.licensename
        pkginfoinfo = TarInfoRoot(".PKGINFO")
        pkginfoinfo.mtime = modtime
        pkginfoinfo.size = pkginfo.tell()
        pkginfo.seek(0)

        # Create the actual package now.
        pkgfile = tarfile.open(output.toOsSpecific(),
                               "w:gz",
                               tarinfo=TarInfoRoot)
        pkgfile.addfile(pkginfoinfo, pkginfo)
        pkgfile.add(tempdir.toOsSpecific(), "/")
        if not self.licensefile.empty():
            pkgfile.add(
                self.licensefile.toOsSpecific(),
                "/usr/share/licenses/%s/LICENSE" % self.shortname.lower())
        pkgfile.close()

        return output
def makeBundle(startDir):
    fstartDir = Filename.fromOsSpecific(startDir)

    # Search for panda3d_mac along $PATH.
    path = DSearchPath()
    if 'PATH' in os.environ:
        path.appendPath(os.environ['PATH'])
    path.appendPath(os.defpath)
    panda3d_mac = path.findFile('panda3d_mac')
    if not panda3d_mac:
        raise StandardError, "Couldn't find panda3d_mac on path."

    # Construct a search path to look for the images.
    search = DSearchPath()

    # First on the path: an explicit $PLUGIN_IMAGES env var.
    if ExecutionEnvironment.hasEnvironmentVariable('PLUGIN_IMAGES'):
        search.appendDirectory(Filename.expandFrom('$PLUGIN_IMAGES'))

    # Next on the path: the models/plugin_images directory within the
    # current directory.
    search.appendDirectory('models/plugin_images')

    # Finally on the path: models/plugin_images within the model
    # search path.
    for dir in getModelPath().getDirectories():
        search.appendDirectory(Filename(dir, 'plugin_images'))

    # Now find the icon file on the above search path.
    icons = search.findFile('panda3d.icns')
    if not icons:
        raise StandardError, "Couldn't find panda3d.icns on model-path."

    # Generate the bundle directory structure
    rootFilename = Filename(fstartDir)
    bundleFilename = Filename(rootFilename, 'Panda3D.app')
    if os.path.exists(bundleFilename.toOsSpecific()):
        shutil.rmtree(bundleFilename.toOsSpecific())

    plistFilename = Filename(bundleFilename, 'Contents/Info.plist')
    plistFilename.makeDir()
    exeFilename = Filename(bundleFilename, 'Contents/MacOS/panda3d_mac')
    exeFilename.makeDir()
    iconFilename = Filename(bundleFilename, 'Contents/Resources/panda3d.icns')
    iconFilename.makeDir()

    # Copy in Info.plist, the icon file, and the compiled executable.
    shutil.copyfile(Filename(fstartDir, "panda3d_mac.plist").toOsSpecific(), plistFilename.toOsSpecific())
    shutil.copyfile(icons.toOsSpecific(), iconFilename.toOsSpecific())
    print panda3d_mac, exeFilename
    shutil.copyfile(panda3d_mac.toOsSpecific(), exeFilename.toOsSpecific())
    os.chmod(exeFilename.toOsSpecific(), 0755)

    # All done!
    bundleFilename.touch()
    print bundleFilename.toOsSpecific()
示例#24
0
    def quickVerify(self, packageDir = None, pathname = None,
                    notify = None):
        """ Performs a quick test to ensure the file has not been
        modified.  This test is vulnerable to people maliciously
        attempting to fool the program (by setting datestamps etc.).

        Returns true if it is intact, false if it needs to be
        redownloaded. """

        if not pathname:
            pathname = Filename(packageDir, self.filename)
        try:
            st = os.stat(pathname.toOsSpecific())
        except OSError:
            # If the file is missing, the file fails.
            if notify:
                notify.debug("file not found: %s" % (pathname))
            return False

        if st.st_size != self.size:
            # If the size is wrong, the file fails.
            if notify:
                notify.debug("size wrong: %s" % (pathname))
            return False

        if st.st_mtime == self.timestamp:
            # If the size is right and the timestamp is right, the
            # file passes.
            if notify:
                notify.debug("file ok: %s" % (pathname))
            return True

        if notify:
            notify.debug("modification time wrong: %s" % (pathname))

        # If the size is right but the timestamp is wrong, the file
        # soft-fails.  We follow this up with a hash check.
        if not self.checkHash(packageDir, pathname, st):
            # Hard fail, the hash is wrong.
            if notify:
                notify.debug("hash check wrong: %s" % (pathname))
                notify.debug("  found %s, expected %s" % (self.actualFile.hash, self.hash))
            return False

        if notify:
            notify.info("hash check ok: %s" % (pathname))

        # The hash is OK after all.  Change the file's timestamp back
        # to what we expect it to be, so we can quick-verify it
        # successfully next time.
        self.__updateTimestamp(pathname, st)

        return True
    def quickVerify(self, packageDir=None, pathname=None, notify=None):
        """ Performs a quick test to ensure the file has not been
        modified.  This test is vulnerable to people maliciously
        attempting to fool the program (by setting datestamps etc.).

        Returns true if it is intact, false if it needs to be
        redownloaded. """

        if not pathname:
            pathname = Filename(packageDir, self.filename)
        try:
            st = os.stat(pathname.toOsSpecific())
        except OSError:
            # If the file is missing, the file fails.
            if notify:
                notify.debug("file not found: %s" % (pathname))
            return False

        if st.st_size != self.size:
            # If the size is wrong, the file fails.
            if notify:
                notify.debug("size wrong: %s" % (pathname))
            return False

        if st.st_mtime == self.timestamp:
            # If the size is right and the timestamp is right, the
            # file passes.
            if notify:
                notify.debug("file ok: %s" % (pathname))
            return True

        if notify:
            notify.debug("modification time wrong: %s" % (pathname))

        # If the size is right but the timestamp is wrong, the file
        # soft-fails.  We follow this up with a hash check.
        if not self.checkHash(packageDir, pathname, st):
            # Hard fail, the hash is wrong.
            if notify:
                notify.debug("hash check wrong: %s" % (pathname))
                notify.debug("  found %s, expected %s" %
                             (self.actualFile.hash, self.hash))
            return False

        if notify:
            notify.info("hash check ok: %s" % (pathname))

        # The hash is OK after all.  Change the file's timestamp back
        # to what we expect it to be, so we can quick-verify it
        # successfully next time.
        self.__updateTimestamp(pathname, st)

        return True
示例#26
0
    def __uncompressArchive(self, step):
        """ Turns the compressed archive into the uncompressed
        archive.  Yields one of stepComplete, stepFailed, 
        restartDownload, or stepContinue. """

        if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever:
            # We're not allowed to!
            yield self.stepFailed
            return

        self.updated = True

        sourcePathname = Filename(self.getPackageDir(), self.compressedArchive.filename)
        targetPathname = Filename(self.getPackageDir(), self.uncompressedArchive.filename)
        targetPathname.unlink()
        self.notify.info("Uncompressing %s to %s" % (sourcePathname, targetPathname))
        decompressor = Decompressor()
        decompressor.initiate(sourcePathname, targetPathname)
        totalBytes = self.uncompressedArchive.size
        result = decompressor.run()
        while result == EUOk:
            step.bytesDone = int(totalBytes * decompressor.getProgress())
            self.__updateStepProgress(step)
            result = decompressor.run()
            if taskMgr.destroyed:
                # If the task manager has been destroyed, we must
                # be shutting down.  Get out of here.
                self.notify.warning("Task Manager destroyed, aborting decompresss %s" % (sourcePathname))
                yield self.stepFailed
                return

            yield self.stepContinue

        if result != EUSuccess:
            yield self.stepFailed
            return

        step.bytesDone = totalBytes
        self.__updateStepProgress(step)

        if not self.uncompressedArchive.quickVerify(self.getPackageDir(), notify=self.notify):
            self.notify.warning("after uncompressing, %s still incorrect" % (self.uncompressedArchive.filename))
            yield self.stepFailed
            return

        # Now that we've verified the archive, make it read-only.
        os.chmod(targetPathname.toOsSpecific(), 0444)

        # Now we can safely remove the compressed archive.
        sourcePathname.unlink()
        yield self.stepComplete
        return
示例#27
0
 def onOpenConvoEditor(self, x, item):
     convoKey = self.treeStoryObj.GetItemText(item)
     #print "treeStoryObj type: %s" %(type(self.treeStoryObj))
     #print 'convo key: %s' %(convoKey)
     if convoKey in self.lib.conversations:
         convoFilename = Filename(self.editor.lib.conversations[convoKey].getFullFilename())
         f = open(convoFilename.toOsSpecific())
         doc = xml.dom.minidom.parse(f)
         root = doc.documentElement
         convo = Conversation.decode(doc)
         f.close()
     else:
         convo = None
     editor = ConversationEditor(self, self.editor, convo, convoKey)
示例#28
0
 def onOpenConvoEditor(self, x, item):
     convoKey = self.treeStoryObj.GetItemText(item)
     #print "treeStoryObj type: %s" %(type(self.treeStoryObj))
     #print 'convo key: %s' %(convoKey)
     if convoKey in self.lib.conversations:
         convoFilename = Filename(
             self.editor.lib.conversations[convoKey].getFullFilename())
         f = open(convoFilename.toOsSpecific())
         doc = xml.dom.minidom.parse(f)
         root = doc.documentElement
         convo = Conversation.decode(doc)
         f.close()
     else:
         convo = None
     editor = ConversationEditor(self, self.editor, convo, convoKey)
    def buildArch(self, output, platform):
        """ Builds an ArchLinux package and stores it in the path
        indicated by the 'output' argument. It will be built for the
        architecture specified by the 'arch' argument.
        If 'output' is a directory, the deb file will be stored in it. """

        arch = platform.rsplit("_", 1)[-1]
        assert arch in ("i386", "amd64")
        arch = {"i386": "i686", "amd64": "x86_64"}[arch]
        pkgver = self.version + "-1"

        output = Filename(output)
        if output.isDirectory():
            output = Filename(output, "%s-%s-%s.pkg.tar.gz" % (self.shortname.lower(), pkgver, arch))
        Installer.notify.info("Creating %s..." % output)
        modtime = int(time.time())

        # Create a temporary directory and write the launcher and dependencies to it.
        tempdir, totsize = self.__buildTempLinux(platform)

        # Create a pkginfo file in memory.
        pkginfo = StringIO()
        print >> pkginfo, "# Generated using pdeploy"
        print >> pkginfo, "# %s" % time.ctime(modtime)
        print >> pkginfo, "pkgname = %s" % self.shortname.lower()
        print >> pkginfo, "pkgver = %s" % pkgver
        print >> pkginfo, "pkgdesc = %s" % self.fullname
        print >> pkginfo, "builddate = %s" % modtime
        print >> pkginfo, "packager = %s <%s>" % (self.authorname, self.authoremail)
        print >> pkginfo, "size = %d" % totsize
        print >> pkginfo, "arch = %s" % arch
        if self.licensename != "":
            print >> pkginfo, "license = %s" % self.licensename
        pkginfoinfo = TarInfoRoot(".PKGINFO")
        pkginfoinfo.mtime = modtime
        pkginfoinfo.size = pkginfo.tell()
        pkginfo.seek(0)

        # Create the actual package now.
        pkgfile = tarfile.open(output.toOsSpecific(), "w:gz", tarinfo=TarInfoRoot)
        pkgfile.addfile(pkginfoinfo, pkginfo)
        pkgfile.add(tempdir.toOsSpecific(), "/")
        if not self.licensefile.empty():
            pkgfile.add(self.licensefile.toOsSpecific(), "/usr/share/licenses/%s/LICENSE" % self.shortname.lower())
        pkgfile.close()

        return output
示例#30
0
    def getUsage(self):
        """ Returns the xusage element that is read from the usage.xml
        file, or None if there is no usage.xml file. """

        if not hasattr(PandaModules, 'TiXmlDocument'):
            return None

        filename = Filename(self.getPackageDir(), self.UsageBasename)
        doc = TiXmlDocument(filename.toOsSpecific())
        if not doc.LoadFile():
            return None
            
        xusage = doc.FirstChildElement('usage')
        if not xusage:
            return None

        return copy.copy(xusage)
示例#31
0
    def getUsage(self):
        """ Returns the xusage element that is read from the usage.xml
        file, or None if there is no usage.xml file. """

        if not hasattr(PandaModules, 'TiXmlDocument'):
            return None

        filename = Filename(self.getPackageDir(), self.UsageBasename)
        doc = TiXmlDocument(filename.toOsSpecific())
        if not doc.LoadFile():
            return None

        xusage = doc.FirstChildElement('usage')
        if not xusage:
            return None

        return copy.copy(xusage)
示例#32
0
 def removeScene(self, sceneName, delFile = False):
     if(len(self.scenes)==1):
         raise SceneDeleteError() 
     else:
         #delete the file in the folder too.
         if delFile:
             toDel = Filename(self.dir.getFullpath() + '/' + self.scenes[sceneName].getFullpath())
             try:
                 os.remove(toDel.toOsSpecific())
             except OSError as e:
                 pass
         if(self.sceneName == sceneName):
             self.sceneName = self.scenesOrder[0]
             #self.sceneFilename = self.scenes[self.sceneName]
         del self.filenameIndexes[self.scenes[sceneName].getBasenameWoExtension()]
         del self.scenes[sceneName]
         self.scenesOrder = sorted(self.scenes)
示例#33
0
    def readNewsCache(self):
        cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename)
        self.newsCache = {}
        if cacheIndexFilename.isRegularFile():
            file = open(cacheIndexFilename.toOsSpecific(), 'r')
            for line in file.readlines():
                line = line.strip()
                keywords = line.split('\t')
                if len(keywords) == 3:
                    filename, size, date = keywords
                    if filename in self.newsFiles:
                        try:
                            size = int(size)
                        except ValueError:
                            size = 0

                        self.newsCache[filename] = (size, date)
示例#34
0
    def readNewsCache(self):
        cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename)
        self.newsCache = {}
        if cacheIndexFilename.isRegularFile():
            file = open(cacheIndexFilename.toOsSpecific(), "r")
            for line in file.readlines():
                line = line.strip()
                keywords = line.split("\t")
                if len(keywords) == 3:
                    filename, size, date = keywords
                    if filename in self.newsFiles:
                        try:
                            size = int(size)
                        except ValueError:
                            size = 0

                        self.newsCache[filename] = (size, date)
示例#35
0
 def removeScene(self, sceneName, delFile=False):
     if (len(self.scenes) == 1):
         raise SceneDeleteError()
     else:
         #delete the file in the folder too.
         if delFile:
             toDel = Filename(self.dir.getFullpath() + '/' +
                              self.scenes[sceneName].getFullpath())
             try:
                 os.remove(toDel.toOsSpecific())
             except OSError as e:
                 pass
         if (self.sceneName == sceneName):
             self.sceneName = self.scenesOrder[0]
             #self.sceneFilename = self.scenes[self.sceneName]
         del self.filenameIndexes[
             self.scenes[sceneName].getBasenameWoExtension()]
         del self.scenes[sceneName]
         self.scenesOrder = sorted(self.scenes)
示例#36
0
    def fromFile(self, packageDir, filename, pathname=None, st=None):
        """ Reads the file information from the indicated file.  If st
        is supplied, it is the result of os.stat on the filename. """

        vfs = VirtualFileSystem.getGlobalPtr()

        filename = Filename(filename)
        if pathname is None:
            pathname = Filename(packageDir, filename)

        self.filename = filename.cStr()
        self.basename = filename.getBasename()

        if st is None:
            st = os.stat(pathname.toOsSpecific())
        self.size = st.st_size
        self.timestamp = st.st_mtime

        self.readHash(pathname)
示例#37
0
    def fromFile(self, packageDir, filename, pathname = None, st = None):
        """ Reads the file information from the indicated file.  If st
        is supplied, it is the result of os.stat on the filename. """
        
        vfs = VirtualFileSystem.getGlobalPtr()

        filename = Filename(filename)
        if pathname is None:
            pathname = Filename(packageDir, filename)
        
        self.filename = filename.cStr()
        self.basename = filename.getBasename()

        if st is None:
            st = os.stat(pathname.toOsSpecific())
        self.size = st.st_size
        self.timestamp = st.st_mtime

        self.readHash(pathname)
示例#38
0
    def fullVerify(self, packageDir=None, pathname=None, notify=None):
        """ Performs a more thorough test to ensure the file has not
        been modified.  This test is less vulnerable to malicious
        attacks, since it reads and verifies the entire file.

        Returns true if it is intact, false if it needs to be
        redownloaded. """

        if not pathname:
            pathname = Filename(packageDir, self.filename)
        try:
            st = os.stat(pathname.toOsSpecific())
        except OSError:
            # If the file is missing, the file fails.
            if notify:
                notify.debug("file not found: %s" % (pathname))
            return False

        if st.st_size != self.size:
            # If the size is wrong, the file fails;
            if notify:
                notify.debug("size wrong: %s" % (pathname))
            return False

        if not self.checkHash(packageDir, pathname, st):
            # Hard fail, the hash is wrong.
            if notify:
                notify.debug("hash check wrong: %s" % (pathname))
                notify.debug("  found %s, expected %s" %
                             (self.actualFile.hash, self.hash))
            return False

        if notify:
            notify.debug("hash check ok: %s" % (pathname))

        # The hash is OK.  If the timestamp is wrong, change it back
        # to what we expect it to be, so we can quick-verify it
        # successfully next time.
        if st.st_mtime != self.timestamp:
            self.__updateTimestamp(pathname, st)

        return True
    def __buildTempLinux(self, platform):
        """ Builds a filesystem for Linux.  Used so that buildDEB,
        buildRPM and buildArch can share the same temp directory. """

        if self.__linuxRoot is not None:
            return self.__linuxRoot

        tempdir = Filename(self.tempDir, platform)
        tempdir.makeDir()

        Filename(tempdir, "usr/bin/").makeDir()
        if self.includeRequires:
            extraTokens = {"host_dir": "/usr/lib/" + self.shortname.lower()}
        else:
            extraTokens = {}
        self.standalone.build(
            Filename(tempdir, "usr/bin/" + self.shortname.lower()), platform,
            extraTokens)
        if not self.licensefile.empty():
            Filename(tempdir,
                     "usr/share/doc/%s/" % self.shortname.lower()).makeDir()
            shutil.copyfile(
                self.licensefile.toOsSpecific(),
                Filename(tempdir, "usr/share/doc/%s/copyright" %
                         self.shortname.lower()).toOsSpecific())
            shutil.copyfile(
                self.licensefile.toOsSpecific(),
                Filename(tempdir, "usr/share/doc/%s/LICENSE" %
                         self.shortname.lower()).toOsSpecific())

        if self.includeRequires:
            hostDir = Filename(tempdir, "usr/lib/" + self.shortname.lower())
            hostDir.makeDir()
            self.installPackagesInto(hostDir, platform)

        totsize = 0
        for root, dirs, files in self.os_walk(tempdir.toOsSpecific()):
            for name in files:
                totsize += os.path.getsize(os.path.join(root, name))

        self.__linuxRoot = (tempdir, totsize)
        return self.__linuxRoot
    def readConfigXml(self):
        """ Reads the config.xml file that may be present in the root
        directory. """

        if not hasattr(PandaModules, 'TiXmlDocument'):
            return
        from pandac.PandaModules import TiXmlDocument

        filename = Filename(self.rootDir, self.ConfigBasename)
        doc = TiXmlDocument(filename.toOsSpecific())
        if not doc.LoadFile():
            return

        xconfig = doc.FirstChildElement('config')
        if xconfig:
            maxDiskUsage = xconfig.Attribute('max_disk_usage')
            try:
                self.maxDiskUsage = int(maxDiskUsage or '')
            except ValueError:
                pass
示例#41
0
    def readConfigXml(self):
        """ Reads the config.xml file that may be present in the root
        directory. """

        if not hasattr(PandaModules, 'TiXmlDocument'):
            return
        from pandac.PandaModules import TiXmlDocument

        filename = Filename(self.rootDir, self.ConfigBasename)
        doc = TiXmlDocument(filename.toOsSpecific())
        if not doc.LoadFile():
            return

        xconfig = doc.FirstChildElement('config')
        if xconfig:
            maxDiskUsage = xconfig.Attribute('max_disk_usage')
            try:
                self.maxDiskUsage = int(maxDiskUsage or '')
            except ValueError:
                pass
示例#42
0
    def fullVerify(self, packageDir = None, pathname = None, notify = None):
        """ Performs a more thorough test to ensure the file has not
        been modified.  This test is less vulnerable to malicious
        attacks, since it reads and verifies the entire file.

        Returns true if it is intact, false if it needs to be
        redownloaded. """

        if not pathname:
            pathname = Filename(packageDir, self.filename)
        try:
            st = os.stat(pathname.toOsSpecific())
        except OSError:
            # If the file is missing, the file fails.
            if notify:
                notify.debug("file not found: %s" % (pathname))
            return False

        if st.st_size != self.size:
            # If the size is wrong, the file fails;
            if notify:
                notify.debug("size wrong: %s" % (pathname))
            return False

        if not self.checkHash(packageDir, pathname, st):
            # Hard fail, the hash is wrong.
            if notify:
                notify.debug("hash check wrong: %s" % (pathname))
                notify.debug("  found %s, expected %s" % (self.actualFile.hash, self.hash))
            return False

        if notify:
            notify.info("hash check ok: %s" % (pathname))

        # The hash is OK.  If the timestamp is wrong, change it back
        # to what we expect it to be, so we can quick-verify it
        # successfully next time.
        if st.st_mtime != self.timestamp:
            self.__updateTimestamp(pathname, st)

        return True
    def __buildTempLinux(self, platform):
        """ Builds a filesystem for Linux.  Used so that buildDEB,
        buildRPM and buildArch can share the same temp directory. """

        if self.__linuxRoot is not None:
            return self.__linuxRoot

        tempdir = Filename(self.tempDir, platform)
        tempdir.makeDir()

        Filename(tempdir, "usr/bin/").makeDir()
        if self.includeRequires:
            extraTokens = {"host_dir": "/usr/lib/" + self.shortname.lower()}
        else:
            extraTokens = {}
        self.standalone.build(Filename(tempdir, "usr/bin/" + self.shortname.lower()), platform, extraTokens)
        if not self.licensefile.empty():
            Filename(tempdir, "usr/share/doc/%s/" % self.shortname.lower()).makeDir()
            shutil.copyfile(
                self.licensefile.toOsSpecific(),
                Filename(tempdir, "usr/share/doc/%s/copyright" % self.shortname.lower()).toOsSpecific(),
            )
            shutil.copyfile(
                self.licensefile.toOsSpecific(),
                Filename(tempdir, "usr/share/doc/%s/LICENSE" % self.shortname.lower()).toOsSpecific(),
            )

        if self.includeRequires:
            hostDir = Filename(tempdir, "usr/lib/" + self.shortname.lower())
            hostDir.makeDir()
            self.installPackagesInto(hostDir, platform)

        totsize = 0
        for root, dirs, files in self.os_walk(tempdir.toOsSpecific()):
            for name in files:
                totsize += os.path.getsize(os.path.join(root, name))

        self.__linuxRoot = (tempdir, totsize)
        return self.__linuxRoot
示例#44
0
    def writeConfigXml(self):
        """ Rewrites the config.xml to the root directory.  This isn't
        called automatically; an application may call this after
        adjusting some parameters (such as self.maxDiskUsage). """

        from pandac.PandaModules import TiXmlDocument, TiXmlDeclaration, TiXmlElement

        filename = Filename(self.rootDir, self.ConfigBasename)
        doc = TiXmlDocument(filename.toOsSpecific())
        decl = TiXmlDeclaration("1.0", "utf-8", "")
        doc.InsertEndChild(decl)

        xconfig = TiXmlElement('config')
        xconfig.SetAttribute('max_disk_usage', str(self.maxDiskUsage))
        doc.InsertEndChild(xconfig)

        # Write the file to a temporary filename, then atomically move
        # it to its actual filename, to avoid race conditions when
        # updating this file.
        tfile = Filename.temporary(self.rootDir.cStr(), '.xml')
        if doc.SaveFile(tfile.toOsSpecific()):
            tfile.renameTo(filename)
    def writeConfigXml(self):
        """ Rewrites the config.xml to the root directory.  This isn't
        called automatically; an application may call this after
        adjusting some parameters (such as self.maxDiskUsage). """

        from pandac.PandaModules import TiXmlDocument, TiXmlDeclaration, TiXmlElement

        filename = Filename(self.rootDir, self.ConfigBasename)
        doc = TiXmlDocument(filename.toOsSpecific())
        decl = TiXmlDeclaration("1.0", "utf-8", "")
        doc.InsertEndChild(decl)

        xconfig = TiXmlElement('config')
        xconfig.SetAttribute('max_disk_usage', str(self.maxDiskUsage))
        doc.InsertEndChild(xconfig)

        # Write the file to a temporary filename, then atomically move
        # it to its actual filename, to avoid race conditions when
        # updating this file.
        tfile = Filename.temporary(self.rootDir.cStr(), '.xml')
        if doc.SaveFile(tfile.toOsSpecific()):
            tfile.renameTo(filename)
示例#46
0
def makeBundle(startDir):
    fstartDir = Filename.fromOsSpecific(startDir)

    # Search for nppandad along $DYLD_LIBRARY_PATH.
    path = DSearchPath()
    if 'LD_LIBRARY_PATH' in os.environ:
        path.appendPath(os.environ['LD_LIBRARY_PATH'])
    if 'DYLD_LIBRARY_PATH' in os.environ:
        path.appendPath(os.environ['DYLD_LIBRARY_PATH'])
    nppanda3d = path.findFile('nppanda3d')
    if not nppanda3d:
        raise StandardError, "Couldn't find nppanda3d on path."

    # Generate the bundle directory structure
    rootFilename = Filename(fstartDir, 'bundle')

    if os.path.exists(rootFilename.toOsSpecific()):
        shutil.rmtree(rootFilename.toOsSpecific())

    bundleFilename = Filename(rootFilename, 'nppanda3d.plugin')
    plistFilename = Filename(bundleFilename, 'Contents/Info.plist')
    plistFilename.makeDir()
    exeFilename = Filename(bundleFilename, 'Contents/MacOS/nppanda3d')
    exeFilename.makeDir()
    resourceFilename = Filename(bundleFilename,
                                'Contents/Resources/nppanda3d.rsrc')
    resourceFilename.makeDir()

    # Compile the .r file to an .rsrc file.
    os.system('/Developer/Tools/Rez -useDF -o %s %s' %
              (resourceFilename.toOsSpecific(),
               Filename(fstartDir, "nppanda3d.r").toOsSpecific()))

    if not resourceFilename.exists():
        raise IOError, 'Unable to run Rez'

    # Copy in Info.plist and the compiled executable.
    shutil.copyfile(
        Filename(fstartDir, "nppanda3d.plist").toOsSpecific(),
        plistFilename.toOsSpecific())
    shutil.copyfile(nppanda3d.toOsSpecific(), exeFilename.toOsSpecific())

    # All done!
    bundleFilename.touch()
    print bundleFilename.toOsSpecific()
def makeBundle(startDir):
    fstartDir = Filename.fromOsSpecific(startDir)

    # Search for nppandad along $DYLD_LIBRARY_PATH.
    path = DSearchPath()
    if 'LD_LIBRARY_PATH' in os.environ:
        path.appendPath(os.environ['LD_LIBRARY_PATH'])
    if 'DYLD_LIBRARY_PATH' in os.environ:
        path.appendPath(os.environ['DYLD_LIBRARY_PATH'])
    nppanda3d = path.findFile('nppanda3d')
    if not nppanda3d:
        raise StandardError, "Couldn't find nppanda3d on path."

    # Generate the bundle directory structure
    rootFilename = Filename(fstartDir, 'bundle')

    if os.path.exists(rootFilename.toOsSpecific()):
        shutil.rmtree(rootFilename.toOsSpecific())

    bundleFilename = Filename(rootFilename, 'nppanda3d.plugin')
    plistFilename = Filename(bundleFilename, 'Contents/Info.plist')
    plistFilename.makeDir()
    exeFilename = Filename(bundleFilename, 'Contents/MacOS/nppanda3d')
    exeFilename.makeDir()
    resourceFilename = Filename(bundleFilename, 'Contents/Resources/nppanda3d.rsrc')
    resourceFilename.makeDir()
    
    # Compile the .r file to an .rsrc file.
    os.system('/Developer/Tools/Rez -useDF -o %s %s' % (
        resourceFilename.toOsSpecific(), Filename(fstartDir, "nppanda3d.r").toOsSpecific()))

    if not resourceFilename.exists():
        raise IOError, 'Unable to run Rez'

    # Copy in Info.plist and the compiled executable.
    shutil.copyfile(Filename(fstartDir, "nppanda3d.plist").toOsSpecific(), plistFilename.toOsSpecific())
    shutil.copyfile(nppanda3d.toOsSpecific(), exeFilename.toOsSpecific())

    # All done!
    bundleFilename.touch()
    print bundleFilename.toOsSpecific()
示例#48
0
    def quickVerify(self, packageDir = None, pathname = None,
                    notify = None, correctSelf = False):
        """ Performs a quick test to ensure the file has not been
        modified.  This test is vulnerable to people maliciously
        attempting to fool the program (by setting datestamps etc.).

        if correctSelf is True, then any discrepency is corrected by
        updating the appropriate fields internally, making the
        assumption that the file on disk is the authoritative version.

        Returns true if it is intact, false if it is incorrect.  If
        correctSelf is true, raises OSError if the self-update is
        impossible (for instance, because the file does not exist)."""

        if not pathname:
            pathname = Filename(packageDir, self.filename)
        try:
            st = os.stat(pathname.toOsSpecific())
        except OSError:
            # If the file is missing, the file fails.
            if notify:
                notify.debug("file not found: %s" % (pathname))
                if correctSelf:
                    raise
            return False

        if st.st_size != self.size:
            # If the size is wrong, the file fails.
            if notify:
                notify.debug("size wrong: %s" % (pathname))
            if correctSelf:
                self.__correctHash(packageDir, pathname, st, notify)
            return False

        if st.st_mtime == self.timestamp:
            # If the size is right and the timestamp is right, the
            # file passes.
            if notify:
                notify.debug("file ok: %s" % (pathname))
            return True

        if notify:
            notify.debug("modification time wrong: %s" % (pathname))

        # If the size is right but the timestamp is wrong, the file
        # soft-fails.  We follow this up with a hash check.
        if not self.checkHash(packageDir, pathname, st):
            # Hard fail, the hash is wrong.
            if notify:
                notify.debug("hash check wrong: %s" % (pathname))
                notify.debug("  found %s, expected %s" % (self.actualFile.hash, self.hash))
            if correctSelf:
                self.__correctHash(packageDir, pathname, st, notify)
            return False

        if notify:
            notify.info("hash check ok: %s" % (pathname))

        # The hash is OK after all.  Change the file's timestamp back
        # to what we expect it to be, so we can quick-verify it
        # successfully next time.
        if correctSelf:
            # Or update our own timestamp.
            self.__correctTimestamp(pathname, st, notify)
            return False
        else:
            self.__updateTimestamp(pathname, st)

        return True
示例#49
0
    def downloadDescFileGenerator(self, http):
        """ A generator function that implements downloadDescFile()
        one piece at a time.  It yields one of stepComplete,
        stepFailed, or stepContinue. """

        assert self.descFile

        if self.hasDescFile:
            # We've already got one.
            yield self.stepComplete
            return

        if self.host.appRunner and self.host.appRunner.verifyContents != self.host.appRunner.P3DVCNever:
            # We're allowed to download it.
            self.http = http

            func = lambda step, self=self: self.__downloadFile(
                None,
                self.descFile,
                urlbase=self.descFile.filename,
                filename=self.descFileBasename)
            step = self.InstallStep(func, self.descFile.size,
                                    self.downloadFactor, 'downloadDesc')

            for token in step.func():
                if token == self.stepContinue:
                    yield token
                else:
                    break

            while token == self.restartDownload:
                # Try again.
                func = lambda step, self=self: self.__downloadFile(
                    None,
                    self.descFile,
                    urlbase=self.descFile.filename,
                    filename=self.descFileBasename)
                step = self.InstallStep(func, self.descFile.size,
                                        self.downloadFactor, 'downloadDesc')
                for token in step.func():
                    if token == self.stepContinue:
                        yield token
                    else:
                        break

            if token == self.stepFailed:
                # Couldn't download the desc file.
                yield self.stepFailed
                return

            assert token == self.stepComplete

            filename = Filename(self.getPackageDir(), self.descFileBasename)
            # Now that we've written the desc file, make it read-only.
            os.chmod(filename.toOsSpecific(), 0444)

        if not self.__readDescFile():
            # Weird, it passed the hash check, but we still can't read
            # it.
            filename = Filename(self.getPackageDir(), self.descFileBasename)
            self.notify.warning("Failure reading %s" % (filename))
            yield self.stepFailed
            return

        yield self.stepComplete
        return
示例#50
0
class DirectNewsFrame(DirectObject.DirectObject):

    TaskName = 'HtmlViewUpdateTask'
    TaskChainName = "RedownladTaskChain"
    RedownloadTaskName = "RedownloadNewsTask"
    NewsBaseDir = config.GetString("news-base-dir", "/httpNews")
    NewsStageDir = config.GetString("news-stage-dir", "news")
    # taken from In Game NewsFrame
    FrameDimensions = (-1.30666637421, 1.30666637421, -0.751666665077,
                       0.751666665077)
    notify = DirectNotifyGlobal.directNotify.newCategory("DirectNewsFrame")
    NewsIndexFilename = config.GetString("news-index-filename",
                                         "http_news_index.txt")
    NewsOverHttp = config.GetBool("news-over-http", True)
    CacheIndexFilename = 'cache_index.txt'

    # home page is considered one section, must always be first
    # home, news, events, talk of the town, ask toontown, toon resistance
    SectionIdents = ['hom', 'new', 'evt', 'tot', 'att', 'tnr']

    def __init__(self, parent=aspect2d):
        DirectObject.DirectObject.__init__(self)
        self.accept("newsSnapshot", self.doSnapshot)
        self.active = False
        self.parent = parent
        self.issues = []
        self.accept("newsChangeWeek", self.changeWeek)
        self.curIssueIndex = 0
        self.strFilenames = None
        self.redownloadingNews = False
        self.startRedownload = datetime.datetime.now()  # just used for timing
        self.endRedownload = datetime.datetime.now()  # just used for timing
        self.load()
        self.percentDownloaded = 0.0
        self.numIssuesExpected = 0
        self.needsParseNews = True
        if self.NewsOverHttp:
            self.redownloadNews()

        self.accept("newIssueOut", self.handleNewIssueOut)
        self.accept("clientCleanup", self.handleClientCleanup)

    def parseNewsContent(self):
        """Open up the directory, read all the files, and figure out the structure."""
        if not self.needsParseNews:
            return
        assert not self.redownloadingNews
        self.needsParseNews = False

        result = False
        newsDir = self.findNewsDir()
        if newsDir:
            allHomeFiles = self.getAllHomeFilenames(newsDir)
            self.notify.debug("len allHomeFiles = %s" % len(allHomeFiles))
            self.numIssuesExpected = len(allHomeFiles)
            if allHomeFiles:
                for myIssueIndex, oneHomeFile in enumerate(allHomeFiles):
                    if type(oneHomeFile) == type(""):
                        justFilename = oneHomeFile
                    else:
                        justFilename = oneHomeFile.getFilename().getBasename()
                    self.notify.debug("parseNewContent %s" % justFilename)
                    parts = justFilename.split('_')
                    dateStr = parts[3]
                    oneIssue = IssueFrame.IssueFrame(self.backFrame, newsDir,
                                                     dateStr, myIssueIndex,
                                                     len(allHomeFiles),
                                                     self.strFilenames)
                    oneIssue.hide()
                    self.issues.append(oneIssue)
                if self.issues:
                    self.issues[-1].show()
                    self.curIssueIndex = len(self.issues) - 1
                    result = True

        if hasattr(base.cr, 'inGameNewsMgr') and base.cr.inGameNewsMgr:
            # we should get here only when a new issue comes out mid game
            self.createdTime = base.cr.inGameNewsMgr.getLatestIssue()
            self.notify.debug("setting created time to latest issue %s" %
                              self.createdTime)
        else:
            # this is sucky that at this point (initial load) we don't have in game news mgr
            self.createdTime = base.cr.toontownTimeManager.getCurServerDateTime(
            )
            self.notify.debug("setting created time cur server time %s" %
                              self.createdTime)
        return result

    def getAllHomeFilenames(self, newsDir):
        """Find all the issues that are available."""

        self.notify.debug("getAllHomeFilenames")
        newsDirAsFile = vfs.getFile(Filename(newsDir))
        fileList = newsDirAsFile.scanDirectory()
        fileNames = fileList.getFiles()
        self.notify.debug("filenames=%s" % fileNames)
        # scan through and find hom1. thats got to be a home page
        homeFileNames = set([])
        for name in fileNames:
            self.notify.debug("processing %s" % name)
            baseName = name.getFilename().getBasename()
            self.notify.debug("baseName=%s" % baseName)
            if "hom1." in baseName:
                homeFileNames.add(name)
            else:
                self.notify.debug("hom1. not in baseName")

        if not homeFileNames:
            #self.notify.error("couldnt find hom1. in %s" % fileNames)
            self.notify.warning("couldnt find hom1. in %s" % fileNames)
            self.setErrorMessage(TTLocalizer.NewsPageNoIssues)
            return []

        def fileCmp(fileA, fileB):
            return fileA.getFilename().compareTo(fileB.getFilename())

        homeFileNames = list(homeFileNames)
        homeFileNames.sort(cmp=fileCmp)
        self.notify.debug("returned homeFileNames=%s" % homeFileNames)

        return homeFileNames

    def findNewsDir(self):
        """Returns the directory string for news content.

        Returns None if it cant find the directory
        """

        if self.NewsOverHttp:
            # If we're running news-over-http, we dump the news into a
            # staging directory.
            return self.NewsStageDir

        searchPath = DSearchPath()
        if AppRunnerGlobal.appRunner:
            # In the web-publish runtime, it will always be here:
            searchPath.appendDirectory(
                Filename.expandFrom('$TT_3_5_ROOT/phase_3.5/models/news'))
        else:
            # In the launcher or dev environment, look here:
            basePath = os.path.expandvars('$TTMODELS') or './ttmodels'
            searchPath.appendDirectory(
                Filename.fromOsSpecific(basePath + '/built/' +
                                        self.NewsBaseDir))
            searchPath.appendDirectory(Filename(self.NewsBaseDir))

        pfile = Filename(self.NewsIndexFilename)
        found = vfs.resolveFilename(pfile, searchPath)
        if not found:
            self.notify.warning('findNewsDir - no path: %s' %
                                self.NewsIndexFilename)
            self.setErrorMessage(TTLocalizer.NewsPageErrorDownloadingFile %
                                 self.NewsIndexFilename)
            return None
        self.notify.debug("found index file %s" % pfile)
        realDir = pfile.getDirname()
        return realDir

    def load(self):
        """Create the gui objects we need."""
        self.loadBackground()
        #self.loadMainPage()

    def loadBackground(self):
        """Create a plain white background image, that covers over the shtickerbook"""
        # HtmlView: webFrame  = -1.30666637421 1.30666637421 -0.751666665077 0.751666665077
        upsellBackground = loader.loadModel(
            "phase_3.5/models/gui/tt_m_gui_ign_newsStatusBackground")
        imageScaleX = self.FrameDimensions[1] - self.FrameDimensions[0]
        imageScaleY = self.FrameDimensions[3] - self.FrameDimensions[2]
        self.backFrame = DirectFrame(
            parent=self.parent,
            image=upsellBackground,
            image_scale=(imageScaleX, 1, imageScaleY),
            frameColor=(1, 1, 1, 0),
            frameSize=self.FrameDimensions,
            pos=(0, 0, 0),
            relief=DGG.FLAT,
            text=TTLocalizer.NewsPageDownloadingNews1,
            text_scale=0.06,
            text_pos=(0, -0.4),
        )

    def addDownloadingTextTask(self):
        """Add a simple little task to show in game news is downloading stuff."""
        self.removeDownloadingTextTask()
        task = taskMgr.doMethodLater(1, self.loadingTextTask,
                                     "DirectNewsFrameDownloadingTextTask")
        task.startTime = globalClock.getFrameTime()
        self.loadingTextTask(task)

    def removeDownloadingTextTask(self):
        """Add a simple little task to show in game news is downloading stuff."""
        taskMgr.remove("DirectNewsFrameDownloadingTextTask")

    def loadMainPage(self):
        """Create the other gui for this."""
        self.mainFrame = DirectFrame(
            parent=self.backFrame,
            frameSize=self.FrameDimensions,
            frameColor=(1, 0, 0, 1),
        )

    def activate(self):
        """
        Check if we have a new issue, and prompt the user if we have one.
        """
        if hasattr(self,"createdTime") and \
           self.createdTime < base.cr.inGameNewsMgr.getLatestIssue() and \
           self.NewsOverHttp and \
           not self.redownloadingNews:
            # we have a new issue, ask the user if he wants to download it
            # let's assume he clicked yes
            self.redownloadNews()
            pass

        else:
            self.addDownloadingTextTask()

        # Load up the news content the first time the user asks to see
        # it.
        if self.needsParseNews and not self.redownloadingNews:
            self.parseNewsContent()

        self.active = True

    def deactivate(self):
        """
        self.quad.hide()
        taskMgr.remove(self.TaskName)
        """
        self.removeDownloadingTextTask()
        self.active = False

    def unload(self):
        """
        self.deactivate()
        HtmlView.HtmlView.unload(self)
        """
        self.removeDownloadingTextTask()
        result = taskMgr.remove(self.RedownloadTaskName)
        self.ignore("newsSnapshot")
        self.ignore("newsChangeWeek")
        self.ignore("newIssueOut")
        self.ignore("clientCleanup")

    def handleClientCleanup(self):
        """User killing toontown, detach the backframe."""
        pass

    def doSnapshot(self):
        "Save the current browser contents to a png file." ""
        pass

    def changeWeek(self, issueIndex):
        """Change the issue we are displaying."""
        if 0 <= issueIndex and issueIndex < len(self.issues):
            self.issues[self.curIssueIndex].hide()
            self.issues[issueIndex].show()
            self.curIssueIndex = issueIndex

    def loadingTextTask(self, task):
        """Change a visual element to indicate we're still downloading."""
        timeIndex = int(globalClock.getFrameTime() - task.startTime) % 3
        timeStrs = (TTLocalizer.NewsPageDownloadingNews0,
                    TTLocalizer.NewsPageDownloadingNews1,
                    TTLocalizer.NewsPageDownloadingNews2)
        textToDisplay = timeStrs[timeIndex] % (int(
            self.percentDownloaded * 100))

        if self.backFrame["text"] != textToDisplay:
            if TTLocalizer.NewsPageDownloadingNewsSubstr in self.backFrame[
                    "text"]:
                # don't change the text if we're displaying an error message
                self.backFrame["text"] = textToDisplay

        return task.again

    def setErrorMessage(self, errText):
        """Tell the user something has gone wrong."""
        self.backFrame["text"] = errText

    def redownloadNews(self):
        """Get the new issue that came out while he was playing."""
        if self.redownloadingNews:
            self.notify.warning(
                "averting potential crash redownloadNews called twice, just returning"
            )
            return
        # I know it's info, it's important enough I feel to appear in the logs
        self.percentDownloaded = 0.0
        self.notify.info("starting redownloadNews")
        self.startRedownload = datetime.datetime.now()

        self.redownloadingNews = True
        self.addDownloadingTextTask()

        # Clean up the old issues and start new stuff downloading.
        for issue in self.issues:
            issue.destroy()
        self.issues = []
        self.curIssueIndex = 0
        self.strFilenames = None
        self.needsParseNews = True

        # Start by downloading the index file.
        self.newsUrl = self.getInGameNewsUrl()
        self.newsDir = Filename(self.findNewsDir())

        # Ensure self.newsDir exists and is a directory.
        Filename(self.newsDir + '/.').makeDir()

        http = HTTPClient.getGlobalPtr()
        self.url = self.newsUrl + self.NewsIndexFilename
        self.ch = http.makeChannel(True)
        self.ch.beginGetDocument(self.url)
        self.rf = Ramfile()
        self.ch.downloadToRam(self.rf)

        taskMgr.remove(self.RedownloadTaskName)
        taskMgr.add(self.downloadIndexTask, self.RedownloadTaskName)

    def downloadIndexTask(self, task):
        """ Get the initial index file from the HTTP server. """
        if self.ch.run():
            return task.cont

        if not self.ch.isValid():
            self.notify.warning("Unable to download %s" % (self.url))
            self.redownloadingNews = False
            return task.done

        # OK, now we've got the list of files hosted by the server.
        # Parse the list.
        self.newsFiles = []
        filename = self.rf.readline()
        while filename:
            filename = filename.strip()
            if filename:
                self.newsFiles.append(filename)
            filename = self.rf.readline()
        del self.rf

        self.newsFiles.sort()
        self.notify.info("Server lists %s news files" % (len(self.newsFiles)))

        # Now see if we already have copies of these files we
        # downloaded previously.
        self.readNewsCache()

        # Clean up any unexpected files in this directory--they might
        # be old news files, or partial failed downloads from before.
        for basename in os.listdir(self.newsDir.toOsSpecific()):
            if basename != self.CacheIndexFilename and basename not in self.newsCache:
                junk = Filename(self.newsDir, basename)
                self.notify.info("Removing %s" % (junk))
                junk.unlink()

        # And start downloading the files.
        self.nextNewsFile = 0
        return self.downloadNextFile(task)

    def downloadNextFile(self, task):
        """ Starts the next news file downloading from the HTTP
        server. """

        if self.nextNewsFile >= len(self.newsFiles):
            # Hey, we're done!
            self.notify.info("Done downloading news.")
            self.percentDownloaded = 1

            del self.newsFiles
            del self.nextNewsFile
            del self.newsUrl
            del self.newsDir
            del self.ch
            del self.url
            if hasattr(self, 'filename'):
                del self.filename
            self.redownloadingNews = False

            if self.active:
                # If we're looking at the page now, go ahead and load it.
                self.parseNewsContent()

            return task.done

        self.percentDownloaded = float(self.nextNewsFile) / float(
            len(self.newsFiles))

        # Get the next file on the list.
        self.filename = self.newsFiles[self.nextNewsFile]
        self.nextNewsFile += 1
        self.url = self.newsUrl + self.filename

        localFilename = Filename(self.newsDir, self.filename)
        doc = DocumentSpec(self.url)
        if self.filename in self.newsCache:
            # We have already downloaded this file.  Ask the
            # server to give us another copy only if the server's
            # copy is newer.
            size, date = self.newsCache[self.filename]
            if date and localFilename.exists() and (
                    size == 0 or localFilename.getFileSize() == size):
                doc.setDate(date)
                doc.setRequestMode(doc.RMNewer)

        self.ch.beginGetDocument(doc)
        self.ch.downloadToFile(localFilename)

        taskMgr.remove(self.RedownloadTaskName)
        taskMgr.add(self.downloadCurrentFileTask, self.RedownloadTaskName)

    def downloadCurrentFileTask(self, task):
        """ Continues downloading the URL in self.url and self.filename. """

        if self.ch.run():
            return task.cont

        if self.ch.getStatusCode() == 304:
            # This file is still cached from before.  We don't need to
            # download it again.  Move on to the next file.
            self.notify.info("already cached: %s" % (self.filename))
            return self.downloadNextFile(task)

        localFilename = Filename(self.newsDir, self.filename)

        if not self.ch.isValid():
            self.notify.warning("Unable to download %s" % (self.url))
            localFilename.unlink()

            if self.filename in self.newsCache:
                del self.newsCache[self.filename]
                self.saveNewsCache()

            # Might as well see if we can get the next file.
            return self.downloadNextFile(task)

        # Successfully downloaded.
        self.notify.info("downloaded %s" % (self.filename))

        # The HTTP "Entity Tag" appears to be useless with our CDN:
        # different CDN servers will serve up different etag values
        # for the same file.  We rely on file size and date instead.

        size = self.ch.getFileSize()
        doc = self.ch.getDocumentSpec()
        date = ''
        if doc.hasDate():
            date = doc.getDate().getString()

        self.newsCache[self.filename] = (size, date)
        self.saveNewsCache()

        # Continue downloading files.
        return self.downloadNextFile(task)

    def readNewsCache(self):
        """ Reads cache_index.txt into self.newsCache. """

        cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename)
        self.newsCache = {}
        if cacheIndexFilename.isRegularFile():
            file = open(cacheIndexFilename.toOsSpecific(), 'r')
            for line in file.readlines():
                line = line.strip()
                keywords = line.split('\t')
                if len(keywords) == 3:
                    filename, size, date = keywords
                    if filename in self.newsFiles:
                        try:
                            size = int(size)
                        except ValueError:
                            size = 0
                        self.newsCache[filename] = (size, date)

    def saveNewsCache(self):
        """ Saves self.newsCache to cache_index.txt """
        cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename)

        file = open(cacheIndexFilename.toOsSpecific(), 'w')
        for filename, (size, date) in self.newsCache.items():
            print >> file, '%s\t%s\t%s' % (filename, size, date)

    def handleNewIssueOut(self):
        """Handle getting this newIssueOut message."""
        # we will get this immediately after DistributedInGameNewsManager gets created
        # we will get this again when a new issue comes out while we are playing
        if hasattr(self,"createdTime") and \
           base.cr.inGameNewsMgr.getLatestIssue()  < self.createdTime:
            self.createdTime = base.cr.inGameNewsMgr.getLatestIssue()
        else:
            # we got a new issue while playing the game
            if self.NewsOverHttp and not self.redownloadingNews:
                # let's not abruptly yank the page if he's reading the news
                if not self.active:
                    self.redownloadNews()
            pass

    def getInGameNewsUrl(self):
        """Get the appropriate URL to use if we are in test, qa, or live."""
        # First if all else fails, we hard code the live news url
        result = base.config.GetString(
            "fallback-news-url",
            "http://cdn.toontown.disney.go.com/toontown/en/gamenews/")
        # next check if we have an override, say they want to url to point to a file in their harddisk
        override = base.config.GetString("in-game-news-url", "")
        if override:
            self.notify.info(
                "got an override url,  using %s for in game news" % override)
            result = override
        else:
            try:
                launcherUrl = base.launcher.getValue("GAME_IN_GAME_NEWS_URL",
                                                     "")
                if launcherUrl:
                    result = launcherUrl
                    self.notify.info(
                        "got GAME_IN_GAME_NEWS_URL from launcher using %s" %
                        result)
                else:
                    self.notify.info(
                        "blank GAME_IN_GAME_NEWS_URL from launcher, using %s" %
                        result)

            except:
                self.notify.warning(
                    "got exception getting GAME_IN_GAME_NEWS_URL from launcher, using %s"
                    % result)
        return result

    def calcIssueVersion(self, dateStr):
        majorVer = 1
        minorVer = 0
        for entry in self.newsIndexEntries:
            if 'aaver' in entry and dateStr in entry:
                parts = entry.split('_')
                if len(parts) > 5:
                    try:
                        majorVer = int(parts[5])
                    except:
                        self.notify.warning('could not int %s' % parts[5])

                else:
                    self.notify.warning('expected more than 5 parts in %s' %
                                        entry)
                if len(parts) > 6:
                    try:
                        minorVer = int(parts[6])
                    except:
                        self.notify.warning('could not int %s' % parts[6])

                else:
                    self.notify.warning('expected more than 6 parts in %s' %
                                        entry)
                break

        return (majorVer, minorVer)
示例#51
0
    def __downloadFile(self, step, fileSpec, urlbase = None, filename = None,
                       allowPartial = False):
        """ Downloads the indicated file from the host into
        packageDir.  Yields one of stepComplete, stepFailed, 
        restartDownload, or stepContinue. """

        if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever:
            # We're not allowed to download anything.
            yield self.stepFailed; return

        self.updated = True

        if not urlbase:
            urlbase = self.descFileDirname + '/' + fileSpec.filename

        # Build up a list of URL's to try downloading from.  Unlike
        # the C++ implementation in P3DPackage.cxx, here we build the
        # URL's in forward order.
        tryUrls = []

        if self.host.appRunner and self.host.appRunner.superMirrorUrl:
            # We start with the "super mirror", if it's defined.
            url = self.host.appRunner.superMirrorUrl + urlbase
            tryUrls.append((url, False))

        if self.host.mirrors:
            # Choose two mirrors at random.
            mirrors = self.host.mirrors[:]
            for i in range(2):
                mirror = random.choice(mirrors)
                mirrors.remove(mirror)
                url = mirror + urlbase
                tryUrls.append((url, False))
                if not mirrors:
                    break

        # After trying two mirrors and failing (or if there are no
        # mirrors), go get it from the original host.
        url = self.host.downloadUrlPrefix + urlbase
        tryUrls.append((url, False))

        # And finally, if the original host also fails, try again with
        # a cache-buster.
        tryUrls.append((url, True))

        for url, cacheBust in tryUrls:
            request = DocumentSpec(url)

            if cacheBust:
                # On the last attempt to download a particular file,
                # we bust through the cache: append a query string to
                # do this.
                url += '?' + str(int(time.time()))
                request = DocumentSpec(url)
                request.setCacheControl(DocumentSpec.CCNoCache)
             
            self.notify.info("%s downloading %s" % (self.packageName, url))

            if not filename:
                filename = fileSpec.filename
            targetPathname = Filename(self.getPackageDir(), filename)
            targetPathname.setBinary()

            channel = self.http.makeChannel(False)

            # If there's a previous partial download, attempt to resume it.
            bytesStarted = 0
            if allowPartial and not cacheBust and targetPathname.exists():
                bytesStarted = targetPathname.getFileSize()

            if bytesStarted < 1024*1024:
                # Not enough bytes downloaded to be worth the risk of
                # a partial download.
                bytesStarted = 0
            elif bytesStarted >= fileSpec.size:
                # Couldn't possibly be our file.
                bytesStarted = 0

            if bytesStarted:
                self.notify.info("Resuming %s after %s bytes already downloaded" % (url, bytesStarted))
                # Make sure the file is writable.
                os.chmod(targetPathname.toOsSpecific(), 0644)
                channel.beginGetSubdocument(request, bytesStarted, 0)
            else:
                # No partial download possible; get the whole file.
                targetPathname.makeDir()
                targetPathname.unlink()
                channel.beginGetDocument(request)
                
            channel.downloadToFile(targetPathname)
            while channel.run():
                if step:
                    step.bytesDone = channel.getBytesDownloaded() + channel.getFirstByteDelivered()
                    if step.bytesDone > step.bytesNeeded:
                        # Oops, too much data.  Might as well abort;
                        # it's the wrong file.
                        self.notify.warning("Got more data than expected for download %s" % (url))
                        break
                    
                    self.__updateStepProgress(step)

                if taskMgr.destroyed:
                    # If the task manager has been destroyed, we must
                    # be shutting down.  Get out of here.
                    self.notify.warning("Task Manager destroyed, aborting %s" % (url))
                    yield self.stepFailed; return
                    
                yield self.stepContinue
                
            if step:
                step.bytesDone = channel.getBytesDownloaded() + channel.getFirstByteDelivered()
                self.__updateStepProgress(step)

            if not channel.isValid():
                self.notify.warning("Failed to download %s" % (url))

            elif not fileSpec.fullVerify(self.getPackageDir(), pathname = targetPathname, notify = self.notify):
                self.notify.warning("After downloading, %s incorrect" % (Filename(fileSpec.filename).getBasename()))

                # This attempt failed.  Maybe the original contents.xml
                # file is stale.  Try re-downloading it now, just to be
                # sure.
                if self.host.redownloadContentsFile(self.http):
                    # Yes!  Go back and start over from the beginning.
                    yield self.restartDownload; return

            else:
                # Success!
                yield self.stepComplete; return

            # Maybe the mirror is bad.  Go back and try the next
            # mirror.

        # All attempts failed.  Maybe the original contents.xml file
        # is stale.  Try re-downloading it now, just to be sure.
        if self.host.redownloadContentsFile(self.http):
            # Yes!  Go back and start over from the beginning.
            yield self.restartDownload; return

        # All mirrors failed; the server (or the internet connection)
        # must be just fubar.
        yield self.stepFailed; return
示例#52
0
class DirectNewsFrame(DirectObject.DirectObject):
    TaskName = 'HtmlViewUpdateTask'
    TaskChainName = 'RedownladTaskChain'
    RedownloadTaskName = 'RedownloadNewsTask'
    NewsBaseDir = config.GetString('news-base-dir', '/httpNews')
    NewsStageDir = config.GetString('news-stage-dir', 'news')
    FrameDimensions = (-1.30666637421, 1.30666637421, -0.75166666507699997, 0.75166666507699997)
    notify = DirectNotifyGlobal.directNotify.newCategory('DirectNewsFrame')
    NewsIndexFilename = config.GetString('news-index-filename', 'http_news_index.txt')
    NewsOverHttp = config.GetBool('news-over-http', True)
    CacheIndexFilename = 'cache_index.txt'
    SectionIdents = [
        'hom',
        'new',
        'evt',
        'tot',
        'att',
        'tnr']
    
    def __init__(self, parent = aspect2d):
        DirectObject.DirectObject.__init__(self)
        self.accept('newsSnapshot', self.doSnapshot)
        self.active = False
        self.parent = parent
        self.issues = []
        self.accept('newsChangeWeek', self.changeWeek)
        self.curIssueIndex = 0
        self.strFilenames = None
        self.redownloadingNews = False
        self.startRedownload = datetime.datetime.now()
        self.endRedownload = datetime.datetime.now()
        self.load()
        self.percentDownloaded = 0.0
        self.numIssuesExpected = 0
        self.needsParseNews = True
        self.newsIndexEntries = []
        if self.NewsOverHttp:
            self.redownloadNews()
        
        self.accept('newIssueOut', self.handleNewIssueOut)
        self.accept('clientCleanup', self.handleClientCleanup)

    
    def parseNewsContent(self):
        if not self.needsParseNews:
            return None
        
        self.needsParseNews = False
        result = False
        newsDir = self.findNewsDir()
        if newsDir:
            allHomeFiles = self.getAllHomeFilenames(newsDir)
            self.notify.debug('len allHomeFiles = %s' % len(allHomeFiles))
            self.numIssuesExpected = len(allHomeFiles)
            if allHomeFiles:
                for (myIssueIndex, oneHomeFile) in enumerate(allHomeFiles):
                    if type(oneHomeFile) == type(''):
                        justFilename = oneHomeFile
                    else:
                        justFilename = oneHomeFile.getFilename().getBasename()
                    self.notify.debug('parseNewContent %s' % justFilename)
                    parts = justFilename.split('_')
                    dateStr = parts[3]
                    (majorVer, minorVer) = self.calcIssueVersion(dateStr)
                    if majorVer == 1:
                        oneIssue = IssueFrame.IssueFrame(self.backFrame, newsDir, dateStr, myIssueIndex, len(allHomeFiles), self.strFilenames)
                    elif majorVer == 2:
                        oneIssue = IssueFrameV2.IssueFrameV2(self.backFrame, newsDir, dateStr, myIssueIndex, len(allHomeFiles), self.strFilenames, self.newsIndexEntries)
                    else:
                        self.notify.warning('Dont know how to handle version %s, asuming v2' % majorVer)
                        oneIssue = IssueFrameV2.IssueFrameV2(self.backFrame, newsDir, dateStr, myIssueIndex, len(allHomeFiles), self.strFilenames, self.newsIndexEntries)
                    oneIssue.hide()
                    self.issues.append(oneIssue)
                
                if self.issues:
                    self.issues[-1].show()
                    self.curIssueIndex = len(self.issues) - 1
                    result = True
                
            
        
        if hasattr(base.cr, 'inGameNewsMgr') and base.cr.inGameNewsMgr:
            self.createdTime = base.cr.inGameNewsMgr.getLatestIssue()
            self.notify.debug('setting created time to latest issue %s' % self.createdTime)
        else:
            self.createdTime = base.cr.toontownTimeManager.getCurServerDateTime()
            self.notify.debug('setting created time cur server time %s' % self.createdTime)
        return result

    
    def getAllHomeFilenames(self, newsDir):
        self.notify.debug('getAllHomeFilenames')
        newsDirAsFile = vfs.getFile(Filename(newsDir))
        fileList = newsDirAsFile.scanDirectory()
        fileNames = fileList.getFiles()
        self.notify.debug('filenames=%s' % fileNames)
        homeFileNames = set([])
        for name in fileNames:
            self.notify.debug('processing %s' % name)
            baseName = name.getFilename().getBasename()
            self.notify.debug('baseName=%s' % baseName)
            if 'hom1.' in baseName:
                homeFileNames.add(name)
                continue
            self.notify.debug('hom1. not in baseName')
        
        if not homeFileNames:
            self.notify.warning('couldnt find hom1. in %s' % fileNames)
            self.setErrorMessage(TTLocalizer.NewsPageNoIssues)
            return []
        
        
        def fileCmp(fileA, fileB):
            return fileA.getFilename().compareTo(fileB.getFilename())

        homeFileNames = list(homeFileNames)
        homeFileNames.sort(cmp = fileCmp)
        self.notify.debug('returned homeFileNames=%s' % homeFileNames)
        return homeFileNames

    
    def findNewsDir(self):
        if self.NewsOverHttp:
            return self.NewsStageDir
        
        searchPath = DSearchPath()
        if AppRunnerGlobal.appRunner:
            searchPath.appendDirectory(Filename.expandFrom('$TT_3_5_ROOT/phase_3.5/models/news'))
        elif not os.path.expandvars('$TTMODELS'):
            pass
        basePath = './ttmodels'
        searchPath.appendDirectory(Filename.fromOsSpecific(basePath + '/built/' + self.NewsBaseDir))
        searchPath.appendDirectory(Filename(self.NewsBaseDir))
        pfile = Filename(self.NewsIndexFilename)
        found = vfs.resolveFilename(pfile, searchPath)
        if not found:
            self.notify.warning('findNewsDir - no path: %s' % self.NewsIndexFilename)
            self.setErrorMessage(TTLocalizer.NewsPageErrorDownloadingFile % self.NewsIndexFilename)
            return None
        
        self.notify.debug('found index file %s' % pfile)
        realDir = pfile.getDirname()
        return realDir

    
    def load(self):
        self.loadBackground()

    
    def loadBackground(self):
        upsellBackground = loader.loadModel('phase_3.5/models/gui/tt_m_gui_ign_newsStatusBackground')
        imageScaleX = self.FrameDimensions[1] - self.FrameDimensions[0]
        imageScaleY = self.FrameDimensions[3] - self.FrameDimensions[2]
        self.backFrame = DirectFrame(parent = self.parent, image = upsellBackground, image_scale = (imageScaleX, 1, imageScaleY), frameColor = (1, 1, 1, 0), frameSize = self.FrameDimensions, pos = (0, 0, 0), relief = DGG.FLAT, text = TTLocalizer.NewsPageDownloadingNews1, text_scale = 0.059999999999999998, text_pos = (0, -0.40000000000000002))

    
    def addDownloadingTextTask(self):
        self.removeDownloadingTextTask()
        task = taskMgr.doMethodLater(1, self.loadingTextTask, 'DirectNewsFrameDownloadingTextTask')
        task.startTime = globalClock.getFrameTime()
        self.loadingTextTask(task)

    
    def removeDownloadingTextTask(self):
        taskMgr.remove('DirectNewsFrameDownloadingTextTask')

    
    def loadMainPage(self):
        self.mainFrame = DirectFrame(parent = self.backFrame, frameSize = self.FrameDimensions, frameColor = (1, 0, 0, 1))

    
    def activate(self):
        if hasattr(self, 'createdTime') and self.createdTime < base.cr.inGameNewsMgr.getLatestIssue() and self.NewsOverHttp and not (self.redownloadingNews):
            self.redownloadNews()
        else:
            self.addDownloadingTextTask()
        if self.needsParseNews and not (self.redownloadingNews):
            self.parseNewsContent()
        
        self.active = True

    
    def deactivate(self):
        self.removeDownloadingTextTask()
        self.active = False

    
    def unload(self):
        self.removeDownloadingTextTask()
        result = taskMgr.remove(self.RedownloadTaskName)
        self.ignore('newsSnapshot')
        self.ignore('newsChangeWeek')
        self.ignore('newIssueOut')
        self.ignore('clientCleanup')

    
    def handleClientCleanup(self):
        pass

    
    def doSnapshot(self):
        pass

    
    def changeWeek(self, issueIndex):
        if 0 <= issueIndex and issueIndex < len(self.issues):
            self.issues[self.curIssueIndex].hide()
            self.issues[issueIndex].show()
            self.curIssueIndex = issueIndex
        

    
    def loadingTextTask(self, task):
        timeIndex = int(globalClock.getFrameTime() - task.startTime) % 3
        timeStrs = (TTLocalizer.NewsPageDownloadingNews0, TTLocalizer.NewsPageDownloadingNews1, TTLocalizer.NewsPageDownloadingNews2)
        textToDisplay = timeStrs[timeIndex] % int(self.percentDownloaded * 100)
        if self.backFrame['text'] != textToDisplay:
            if TTLocalizer.NewsPageDownloadingNewsSubstr in self.backFrame['text']:
                self.backFrame['text'] = textToDisplay
            
        
        return task.again

    
    def setErrorMessage(self, errText):
        self.backFrame['text'] = errText

    
    def redownloadNews(self):
        if self.redownloadingNews:
            self.notify.warning('averting potential crash redownloadNews called twice, just returning')
            return None
        
        self.percentDownloaded = 0.0
        self.notify.info('starting redownloadNews')
        self.startRedownload = datetime.datetime.now()
        self.redownloadingNews = True
        self.addDownloadingTextTask()
        for issue in self.issues:
            issue.destroy()
        
        self.issues = []
        self.curIssueIndex = 0
        self.strFilenames = None
        self.needsParseNews = True
        self.newsUrl = self.getInGameNewsUrl()
        self.newsDir = Filename(self.findNewsDir())
        Filename(self.newsDir + '/.').makeDir()
        http = HTTPClient.getGlobalPtr()
        self.url = self.newsUrl + self.NewsIndexFilename
        self.ch = http.makeChannel(True)
        self.ch.beginGetDocument(self.url)
        self.rf = Ramfile()
        self.ch.downloadToRam(self.rf)
        taskMgr.remove(self.RedownloadTaskName)
        taskMgr.add(self.downloadIndexTask, self.RedownloadTaskName)

    
    def downloadIndexTask(self, task):
        if self.ch.run():
            return task.cont
        
        if not self.ch.isValid():
            self.notify.warning('Unable to download %s' % self.url)
            self.redownloadingNews = False
            return task.done
        
        self.newsFiles = []
        filename = self.rf.readline()
        while filename:
            filename = filename.strip()
            if filename:
                self.newsFiles.append(filename)
            
            filename = self.rf.readline()
        del self.rf
        self.newsFiles.sort()
        self.newsIndexEntries = list(self.newsFiles)
        self.notify.info('Server lists %s news files' % len(self.newsFiles))
        self.notify.debug('self.newsIndexEntries=%s' % self.newsIndexEntries)
        self.readNewsCache()
        for basename in os.listdir(self.newsDir.toOsSpecific()):
            if basename != self.CacheIndexFilename and basename not in self.newsCache:
                junk = Filename(self.newsDir, basename)
                self.notify.info('Removing %s' % junk)
                junk.unlink()
                continue
        
        self.nextNewsFile = 0
        return self.downloadNextFile(task)

    
    def downloadNextFile(self, task):
        while self.nextNewsFile < len(self.newsFiles) and 'aaver' in self.newsFiles[self.nextNewsFile]:
            self.nextNewsFile += 1
        if self.nextNewsFile >= len(self.newsFiles):
            self.notify.info('Done downloading news.')
            self.percentDownloaded = 1
            del self.newsFiles
            del self.nextNewsFile
            del self.newsUrl
            del self.newsDir
            del self.ch
            del self.url
            if hasattr(self, 'filename'):
                del self.filename
            
            self.redownloadingNews = False
            if self.active:
                self.parseNewsContent()
            
            return task.done
        
        self.percentDownloaded = float(self.nextNewsFile) / float(len(self.newsFiles))
        self.filename = self.newsFiles[self.nextNewsFile]
        self.nextNewsFile += 1
        self.url = self.newsUrl + self.filename
        localFilename = Filename(self.newsDir, self.filename)
        self.notify.info('testing for %s' % localFilename.getFullpath())
        doc = DocumentSpec(self.url)
        if self.filename in self.newsCache:
            (size, date) = self.newsCache[self.filename]
            if date and localFilename.exists():
                if size == 0 or localFilename.getFileSize() == size:
                    doc.setDate(date)
                    doc.setRequestMode(doc.RMNewer)
                
            localFilename.getFileSize() == size
        
        self.ch.beginGetDocument(doc)
        self.ch.downloadToFile(localFilename)
        taskMgr.remove(self.RedownloadTaskName)
        taskMgr.add(self.downloadCurrentFileTask, self.RedownloadTaskName)

    
    def downloadCurrentFileTask(self, task):
        if self.ch.run():
            return task.cont
        
        if self.ch.getStatusCode() == 304:
            self.notify.info('already cached: %s' % self.filename)
            return self.downloadNextFile(task)
        
        localFilename = Filename(self.newsDir, self.filename)
        if not self.ch.isValid():
            self.notify.warning('Unable to download %s' % self.url)
            localFilename.unlink()
            if self.filename in self.newsCache:
                del self.newsCache[self.filename]
                self.saveNewsCache()
            
            return self.downloadNextFile(task)
        
        self.notify.info('downloaded %s' % self.filename)
        size = self.ch.getFileSize()
        doc = self.ch.getDocumentSpec()
        date = ''
        if doc.hasDate():
            date = doc.getDate().getString()
        
        self.newsCache[self.filename] = (size, date)
        self.saveNewsCache()
        return self.downloadNextFile(task)

    
    def readNewsCache(self):
        cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename)
        self.newsCache = { }
        if cacheIndexFilename.isRegularFile():
            file = open(cacheIndexFilename.toOsSpecific(), 'r')
            for line in file.readlines():
                line = line.strip()
                keywords = line.split('\t')
                if len(keywords) == 3:
                    (filename, size, date) = keywords
                    if filename in self.newsFiles:
                        
                        try:
                            size = int(size)
                        except ValueError:
                            size = 0

                        self.newsCache[filename] = (size, date)
                    
                filename in self.newsFiles
            
        

    
    def saveNewsCache(self):
        cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename)
        
        try:
            file = open(cacheIndexFilename.toOsSpecific(), 'w')
        except IOError:
            e = None
            self.notify.warning('error opening news cache file %s: %s' % (cacheIndexFilename, str(e)))
            return None

        for (size, date) in self.newsCache.items():
            print >>file, '%s\t%s\t%s' % (filename, size, date)
        

    
    def handleNewIssueOut(self):
        if hasattr(self, 'createdTime') and base.cr.inGameNewsMgr.getLatestIssue() < self.createdTime:
            self.createdTime = base.cr.inGameNewsMgr.getLatestIssue()
        elif self.NewsOverHttp and not (self.redownloadingNews):
            if not self.active:
                self.redownloadNews()
            
        

    
    def getInGameNewsUrl(self):
        result = base.config.GetString('fallback-news-url', 'http://cdn.toontown.disney.go.com/toontown/en/gamenews/')
        override = base.config.GetString('in-game-news-url', '')
        if override:
            self.notify.info('got an override url,  using %s for in game news' % override)
            result = override
        else:
            
            try:
                launcherUrl = base.launcher.getValue('GAME_IN_GAME_NEWS_URL', '')
                if launcherUrl:
                    result = launcherUrl
                    self.notify.info('got GAME_IN_GAME_NEWS_URL from launcher using %s' % result)
                else:
                    self.notify.info('blank GAME_IN_GAME_NEWS_URL from launcher, using %s' % result)
            except:
                self.notify.warning('got exception getting GAME_IN_GAME_NEWS_URL from launcher, using %s' % result)

        return result

    
    def calcIssueVersion(self, dateStr):
        majorVer = 1
        minorVer = 0
        for entry in self.newsIndexEntries:
            if 'aaver' in entry and dateStr in entry:
                parts = entry.split('_')
                if len(parts) > 5:
                    
                    try:
                        majorVer = int(parts[5])
                    self.notify.warning('could not int %s' % parts[5])

                else:
                    self.notify.warning('expected more than 5 parts in %s' % entry)
                if len(parts) > 6:
                    
                    try:
                        minorVer = int(parts[6])
                    self.notify.warning('could not int %s' % parts[6])

                else:
                    self.notify.warning('expected more than 6 parts in %s' % entry)
                break
                continue
        
        return (majorVer, minorVer)
示例#53
0
class DirectNewsFrame(DirectObject.DirectObject):
    TaskName = "HtmlViewUpdateTask"
    TaskChainName = "RedownladTaskChain"
    RedownloadTaskName = "RedownloadNewsTask"
    NewsBaseDir = config.GetString("news-base-dir", "/httpNews")
    NewsStageDir = config.GetString("news-stage-dir", "news")
    FrameDimensions = (-1.30666637421, 1.30666637421, -0.751666665077, 0.751666665077)
    notify = DirectNotifyGlobal.directNotify.newCategory("DirectNewsFrame")
    NewsIndexFilename = config.GetString("news-index-filename", "http_news_index.txt")
    NewsOverHttp = config.GetBool("news-over-http", True)
    CacheIndexFilename = "cache_index.txt"
    SectionIdents = ["hom", "new", "evt", "tot", "att", "tnr"]

    def __init__(self, parent=aspect2d):
        DirectObject.DirectObject.__init__(self)
        self.accept("newsSnapshot", self.doSnapshot)
        self.active = False
        self.parent = parent
        self.issues = []
        self.accept("newsChangeWeek", self.changeWeek)
        self.curIssueIndex = 0
        self.strFilenames = None
        self.redownloadingNews = False
        self.startRedownload = datetime.datetime.now()
        self.endRedownload = datetime.datetime.now()
        self.load()
        self.percentDownloaded = 0.0
        self.numIssuesExpected = 0
        self.needsParseNews = True
        self.newsIndexEntries = []
        if self.NewsOverHttp:
            self.redownloadNews()
        self.accept("newIssueOut", self.handleNewIssueOut)
        self.accept("clientCleanup", self.handleClientCleanup)
        return

    def parseNewsContent(self):
        if not self.needsParseNews:
            return
        self.needsParseNews = False
        result = False
        newsDir = self.findNewsDir()
        if newsDir:
            allHomeFiles = self.getAllHomeFilenames(newsDir)
            self.notify.debug("len allHomeFiles = %s" % len(allHomeFiles))
            self.numIssuesExpected = len(allHomeFiles)
            if allHomeFiles:
                for myIssueIndex, oneHomeFile in enumerate(allHomeFiles):
                    if type(oneHomeFile) == type(""):
                        justFilename = oneHomeFile
                    else:
                        justFilename = oneHomeFile.getFilename().getBasename()
                    self.notify.debug("parseNewContent %s" % justFilename)
                    parts = justFilename.split("_")
                    dateStr = parts[3]
                    majorVer, minorVer = self.calcIssueVersion(dateStr)
                    if majorVer == 1:
                        oneIssue = IssueFrame.IssueFrame(
                            self.backFrame, newsDir, dateStr, myIssueIndex, len(allHomeFiles), self.strFilenames
                        )
                    elif majorVer == 2:
                        oneIssue = IssueFrameV2.IssueFrameV2(
                            self.backFrame,
                            newsDir,
                            dateStr,
                            myIssueIndex,
                            len(allHomeFiles),
                            self.strFilenames,
                            self.newsIndexEntries,
                        )
                    else:
                        self.notify.warning("Dont know how to handle version %s, asuming v2" % majorVer)
                        oneIssue = IssueFrameV2.IssueFrameV2(
                            self.backFrame,
                            newsDir,
                            dateStr,
                            myIssueIndex,
                            len(allHomeFiles),
                            self.strFilenames,
                            self.newsIndexEntries,
                        )
                    oneIssue.hide()
                    self.issues.append(oneIssue)

                if self.issues:
                    self.issues[-1].show()
                    self.curIssueIndex = len(self.issues) - 1
                    result = True
        if hasattr(base.cr, "inGameNewsMgr") and base.cr.inGameNewsMgr:
            self.createdTime = base.cr.inGameNewsMgr.getLatestIssue()
            self.notify.debug("setting created time to latest issue %s" % self.createdTime)
        else:
            self.createdTime = base.cr.toontownTimeManager.getCurServerDateTime()
            self.notify.debug("setting created time cur server time %s" % self.createdTime)
        return result

    def getAllHomeFilenames(self, newsDir):
        self.notify.debug("getAllHomeFilenames")
        newsDirAsFile = vfs.getFile(Filename(newsDir))
        fileList = newsDirAsFile.scanDirectory()
        fileNames = fileList.getFiles()
        self.notify.debug("filenames=%s" % fileNames)
        homeFileNames = set([])
        for name in fileNames:
            self.notify.debug("processing %s" % name)
            baseName = name.getFilename().getBasename()
            self.notify.debug("baseName=%s" % baseName)
            if "hom1." in baseName:
                homeFileNames.add(name)
            else:
                self.notify.debug("hom1. not in baseName")

        if not homeFileNames:
            self.notify.warning("couldnt find hom1. in %s" % fileNames)
            self.setErrorMessage(TTLocalizer.NewsPageNoIssues)
            return []

        def fileCmp(fileA, fileB):
            return fileA.getFilename().compareTo(fileB.getFilename())

        homeFileNames = list(homeFileNames)
        homeFileNames.sort(cmp=fileCmp)
        self.notify.debug("returned homeFileNames=%s" % homeFileNames)
        return homeFileNames

    def findNewsDir(self):
        if self.NewsOverHttp:
            return self.NewsStageDir
        searchPath = DSearchPath()
        if AppRunnerGlobal.appRunner:
            searchPath.appendDirectory(Filename.expandFrom("$TT_3_5_ROOT/phase_3.5/models/news"))
        else:
            basePath = os.path.expandvars("$TTMODELS") or "./ttmodels"
            searchPath.appendDirectory(Filename.fromOsSpecific(basePath + "/built/" + self.NewsBaseDir))
            searchPath.appendDirectory(Filename(self.NewsBaseDir))
        pfile = Filename(self.NewsIndexFilename)
        found = vfs.resolveFilename(pfile, searchPath)
        if not found:
            self.notify.warning("findNewsDir - no path: %s" % self.NewsIndexFilename)
            self.setErrorMessage(TTLocalizer.NewsPageErrorDownloadingFile % self.NewsIndexFilename)
            return None
        self.notify.debug("found index file %s" % pfile)
        realDir = pfile.getDirname()
        return realDir

    def load(self):
        self.loadBackground()

    def loadBackground(self):
        upsellBackground = loader.loadModel("phase_3.5/models/gui/tt_m_gui_ign_newsStatusBackground")
        imageScaleX = self.FrameDimensions[1] - self.FrameDimensions[0]
        imageScaleY = self.FrameDimensions[3] - self.FrameDimensions[2]
        self.backFrame = DirectFrame(
            parent=self.parent,
            image=upsellBackground,
            image_scale=(imageScaleX, 1, imageScaleY),
            frameColor=(1, 1, 1, 0),
            frameSize=self.FrameDimensions,
            pos=(0, 0, 0),
            relief=DGG.FLAT,
            text=TTLocalizer.NewsPageDownloadingNews1,
            text_scale=0.06,
            text_pos=(0, -0.4),
        )

    def addDownloadingTextTask(self):
        self.removeDownloadingTextTask()
        task = taskMgr.doMethodLater(1, self.loadingTextTask, "DirectNewsFrameDownloadingTextTask")
        task.startTime = globalClock.getFrameTime()
        self.loadingTextTask(task)

    def removeDownloadingTextTask(self):
        taskMgr.remove("DirectNewsFrameDownloadingTextTask")

    def loadMainPage(self):
        self.mainFrame = DirectFrame(parent=self.backFrame, frameSize=self.FrameDimensions, frameColor=(1, 0, 0, 1))

    def activate(self):
        if (
            hasattr(self, "createdTime")
            and self.createdTime < base.cr.inGameNewsMgr.getLatestIssue()
            and self.NewsOverHttp
            and not self.redownloadingNews
        ):
            self.redownloadNews()
        else:
            self.addDownloadingTextTask()
        if self.needsParseNews and not self.redownloadingNews:
            self.parseNewsContent()
        self.active = True

    def deactivate(self):
        self.removeDownloadingTextTask()
        self.active = False

    def unload(self):
        self.removeDownloadingTextTask()
        result = taskMgr.remove(self.RedownloadTaskName)
        self.ignore("newsSnapshot")
        self.ignore("newsChangeWeek")
        self.ignore("newIssueOut")
        self.ignore("clientCleanup")

    def handleClientCleanup(self):
        pass

    def doSnapshot(self):
        pass

    def changeWeek(self, issueIndex):
        if 0 <= issueIndex and issueIndex < len(self.issues):
            self.issues[self.curIssueIndex].hide()
            self.issues[issueIndex].show()
            self.curIssueIndex = issueIndex

    def loadingTextTask(self, task):
        timeIndex = int(globalClock.getFrameTime() - task.startTime) % 3
        timeStrs = (
            TTLocalizer.NewsPageDownloadingNews0,
            TTLocalizer.NewsPageDownloadingNews1,
            TTLocalizer.NewsPageDownloadingNews2,
        )
        textToDisplay = timeStrs[timeIndex] % int(self.percentDownloaded * 100)
        if self.backFrame["text"] != textToDisplay:
            if TTLocalizer.NewsPageDownloadingNewsSubstr in self.backFrame["text"]:
                self.backFrame["text"] = textToDisplay
        return task.again

    def setErrorMessage(self, errText):
        self.backFrame["text"] = errText

    def redownloadNews(self):
        if self.redownloadingNews:
            self.notify.warning("averting potential crash redownloadNews called twice, just returning")
            return
        self.percentDownloaded = 0.0
        self.notify.info("starting redownloadNews")
        self.startRedownload = datetime.datetime.now()
        self.redownloadingNews = True
        self.addDownloadingTextTask()
        for issue in self.issues:
            issue.destroy()

        self.issues = []
        self.curIssueIndex = 0
        self.strFilenames = None
        self.needsParseNews = True
        self.newsUrl = self.getInGameNewsUrl()
        self.newsDir = Filename(self.findNewsDir())
        Filename(self.newsDir + "/.").makeDir()
        http = HTTPClient.getGlobalPtr()
        self.url = self.newsUrl + self.NewsIndexFilename
        self.ch = http.makeChannel(True)
        self.ch.beginGetDocument(self.url)
        self.rf = Ramfile()
        self.ch.downloadToRam(self.rf)
        taskMgr.remove(self.RedownloadTaskName)
        taskMgr.add(self.downloadIndexTask, self.RedownloadTaskName)
        return

    def downloadIndexTask(self, task):
        if self.ch.run():
            return task.cont
        if not self.ch.isValid():
            self.notify.warning("Unable to download %s" % self.url)
            self.redownloadingNews = False
            return task.done
        self.newsFiles = []
        filename = self.rf.readline()
        while filename:
            filename = filename.strip()
            if filename:
                self.newsFiles.append(filename)
            filename = self.rf.readline()

        del self.rf
        self.newsFiles.sort()
        self.newsIndexEntries = list(self.newsFiles)
        self.notify.info("Server lists %s news files" % len(self.newsFiles))
        self.notify.debug("self.newsIndexEntries=%s" % self.newsIndexEntries)
        self.readNewsCache()
        for basename in os.listdir(self.newsDir.toOsSpecific()):
            if basename != self.CacheIndexFilename and basename not in self.newsCache:
                junk = Filename(self.newsDir, basename)
                self.notify.info("Removing %s" % junk)
                junk.unlink()

        self.nextNewsFile = 0
        return self.downloadNextFile(task)

    def downloadNextFile(self, task):
        while self.nextNewsFile < len(self.newsFiles) and "aaver" in self.newsFiles[self.nextNewsFile]:
            self.nextNewsFile += 1

        if self.nextNewsFile >= len(self.newsFiles):
            self.notify.info("Done downloading news.")
            self.percentDownloaded = 1
            del self.newsFiles
            del self.nextNewsFile
            del self.newsUrl
            del self.newsDir
            del self.ch
            del self.url
            if hasattr(self, "filename"):
                del self.filename
            self.redownloadingNews = False
            if self.active:
                self.parseNewsContent()
            return task.done
        self.percentDownloaded = float(self.nextNewsFile) / float(len(self.newsFiles))
        self.filename = self.newsFiles[self.nextNewsFile]
        self.nextNewsFile += 1
        self.url = self.newsUrl + self.filename
        localFilename = Filename(self.newsDir, self.filename)
        self.notify.info("testing for %s" % localFilename.getFullpath())
        doc = DocumentSpec(self.url)
        if self.filename in self.newsCache:
            size, date = self.newsCache[self.filename]
            if date and localFilename.exists() and (size == 0 or localFilename.getFileSize() == size):
                doc.setDate(date)
                doc.setRequestMode(doc.RMNewer)
        self.ch.beginGetDocument(doc)
        self.ch.downloadToFile(localFilename)
        taskMgr.remove(self.RedownloadTaskName)
        taskMgr.add(self.downloadCurrentFileTask, self.RedownloadTaskName)

    def downloadCurrentFileTask(self, task):
        if self.ch.run():
            return task.cont
        if self.ch.getStatusCode() == 304:
            self.notify.info("already cached: %s" % self.filename)
            return self.downloadNextFile(task)
        localFilename = Filename(self.newsDir, self.filename)
        if not self.ch.isValid():
            self.notify.warning("Unable to download %s" % self.url)
            localFilename.unlink()
            if self.filename in self.newsCache:
                del self.newsCache[self.filename]
                self.saveNewsCache()
            return self.downloadNextFile(task)
        self.notify.info("downloaded %s" % self.filename)
        size = self.ch.getFileSize()
        doc = self.ch.getDocumentSpec()
        date = ""
        if doc.hasDate():
            date = doc.getDate().getString()
        self.newsCache[self.filename] = (size, date)
        self.saveNewsCache()
        return self.downloadNextFile(task)

    def readNewsCache(self):
        cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename)
        self.newsCache = {}
        if cacheIndexFilename.isRegularFile():
            file = open(cacheIndexFilename.toOsSpecific(), "r")
            for line in file.readlines():
                line = line.strip()
                keywords = line.split("\t")
                if len(keywords) == 3:
                    filename, size, date = keywords
                    if filename in self.newsFiles:
                        try:
                            size = int(size)
                        except ValueError:
                            size = 0

                        self.newsCache[filename] = (size, date)

    def saveNewsCache(self):
        cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename)
        try:
            file = open(cacheIndexFilename.toOsSpecific(), "w")
        except IOError, e:
            self.notify.warning("error opening news cache file %s: %s" % (cacheIndexFilename, str(e)))
            return

        for filename, (size, date) in self.newsCache.items():
            print >> file, "%s\t%s\t%s" % (filename, size, date)
示例#54
0
#from ShowBaseGlobal import *
#import ToontownClientRepository

#cr = ToontownClientRepository.ToontownClientRepository("D:\\Cygwin\\home\\jnschell\\player\\toontown\\src\\configfiles\\toon.dc")

#import FSMInspector
#ins = FSMInspector.FSMInspector(ClassicFSM=cr.fsm)

#cr.fsm.request("connect", ["206.18.93.17", 6667])

from ToonBaseGlobal import *
from toontown.distributed import ToontownClientRepository
import os
from pandac.PandaModules import Filename

# Start up the client repository
fname = Filename(os.getenv("TOONTOWN") + "/src/configfiles/toon.dc")
cr = ToontownClientRepository.ToontownClientRepository(fname.toOsSpecific())

# Start the show
base.startShow(cr)
run()
示例#55
0
    def __downloadFile(self,
                       step,
                       fileSpec,
                       urlbase=None,
                       filename=None,
                       allowPartial=False):
        """ Downloads the indicated file from the host into
        packageDir.  Yields one of stepComplete, stepFailed, 
        restartDownload, or stepContinue. """

        if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever:
            # We're not allowed to download anything.
            yield self.stepFailed
            return

        self.updated = True

        if not urlbase:
            urlbase = self.descFileDirname + '/' + fileSpec.filename

        # Build up a list of URL's to try downloading from.  Unlike
        # the C++ implementation in P3DPackage.cxx, here we build the
        # URL's in forward order.
        tryUrls = []

        if self.host.appRunner and self.host.appRunner.superMirrorUrl:
            # We start with the "super mirror", if it's defined.
            url = self.host.appRunner.superMirrorUrl + urlbase
            tryUrls.append((url, False))

        if self.host.mirrors:
            # Choose two mirrors at random.
            mirrors = self.host.mirrors[:]
            for i in range(2):
                mirror = random.choice(mirrors)
                mirrors.remove(mirror)
                url = mirror + urlbase
                tryUrls.append((url, False))
                if not mirrors:
                    break

        # After trying two mirrors and failing (or if there are no
        # mirrors), go get it from the original host.
        url = self.host.downloadUrlPrefix + urlbase
        tryUrls.append((url, False))

        # And finally, if the original host also fails, try again with
        # a cache-buster.
        tryUrls.append((url, True))

        for url, cacheBust in tryUrls:
            request = DocumentSpec(url)

            if cacheBust:
                # On the last attempt to download a particular file,
                # we bust through the cache: append a query string to
                # do this.
                url += '?' + str(int(time.time()))
                request = DocumentSpec(url)
                request.setCacheControl(DocumentSpec.CCNoCache)

            self.notify.info("%s downloading %s" % (self.packageName, url))

            if not filename:
                filename = fileSpec.filename
            targetPathname = Filename(self.getPackageDir(), filename)
            targetPathname.setBinary()

            channel = self.http.makeChannel(False)

            # If there's a previous partial download, attempt to resume it.
            bytesStarted = 0
            if allowPartial and not cacheBust and targetPathname.exists():
                bytesStarted = targetPathname.getFileSize()

            if bytesStarted < 1024 * 1024:
                # Not enough bytes downloaded to be worth the risk of
                # a partial download.
                bytesStarted = 0
            elif bytesStarted >= fileSpec.size:
                # Couldn't possibly be our file.
                bytesStarted = 0

            if bytesStarted:
                self.notify.info(
                    "Resuming %s after %s bytes already downloaded" %
                    (url, bytesStarted))
                # Make sure the file is writable.
                os.chmod(targetPathname.toOsSpecific(), 0644)
                channel.beginGetSubdocument(request, bytesStarted, 0)
            else:
                # No partial download possible; get the whole file.
                targetPathname.makeDir()
                targetPathname.unlink()
                channel.beginGetDocument(request)

            channel.downloadToFile(targetPathname)
            while channel.run():
                if step:
                    step.bytesDone = channel.getBytesDownloaded(
                    ) + channel.getFirstByteDelivered()
                    if step.bytesDone > step.bytesNeeded:
                        # Oops, too much data.  Might as well abort;
                        # it's the wrong file.
                        self.notify.warning(
                            "Got more data than expected for download %s" %
                            (url))
                        break

                    self.__updateStepProgress(step)

                if taskMgr.destroyed:
                    # If the task manager has been destroyed, we must
                    # be shutting down.  Get out of here.
                    self.notify.warning("Task Manager destroyed, aborting %s" %
                                        (url))
                    yield self.stepFailed
                    return

                yield self.stepContinue

            if step:
                step.bytesDone = channel.getBytesDownloaded(
                ) + channel.getFirstByteDelivered()
                self.__updateStepProgress(step)

            if not channel.isValid():
                self.notify.warning("Failed to download %s" % (url))

            elif not fileSpec.fullVerify(self.getPackageDir(),
                                         pathname=targetPathname,
                                         notify=self.notify):
                self.notify.warning(
                    "After downloading, %s incorrect" %
                    (Filename(fileSpec.filename).getBasename()))

                # This attempt failed.  Maybe the original contents.xml
                # file is stale.  Try re-downloading it now, just to be
                # sure.
                if self.host.redownloadContentsFile(self.http):
                    # Yes!  Go back and start over from the beginning.
                    yield self.restartDownload
                    return

            else:
                # Success!
                yield self.stepComplete
                return

            # Maybe the mirror is bad.  Go back and try the next
            # mirror.

        # All attempts failed.  Maybe the original contents.xml file
        # is stale.  Try re-downloading it now, just to be sure.
        if self.host.redownloadContentsFile(self.http):
            # Yes!  Go back and start over from the beginning.
            yield self.restartDownload
            return

        # All mirrors failed; the server (or the internet connection)
        # must be just fubar.
        yield self.stepFailed
        return
示例#56
0
class DirectNewsFrame(DirectObject.DirectObject):
    TaskName = 'HtmlViewUpdateTask'
    TaskChainName = 'RedownladTaskChain'
    RedownloadTaskName = 'RedownloadNewsTask'
    NewsBaseDir = config.GetString('news-base-dir', '/httpNews')
    NewsStageDir = config.GetString('news-stage-dir', 'news')
    FrameDimensions = (-1.30666637421, 1.30666637421, -0.751666665077,
                       0.751666665077)
    notify = DirectNotifyGlobal.directNotify.newCategory('DirectNewsFrame')
    NewsIndexFilename = config.GetString('news-index-filename',
                                         'http_news_index.txt')
    NewsOverHttp = config.GetBool('news-over-http', True)
    CacheIndexFilename = 'cache_index.txt'
    SectionIdents = ['hom', 'new', 'evt', 'tot', 'att', 'tnr']

    def __init__(self, parent=aspect2d):
        DirectObject.DirectObject.__init__(self)
        self.accept('newsSnapshot', self.doSnapshot)
        self.active = False
        self.parent = parent
        self.issues = []
        self.accept('newsChangeWeek', self.changeWeek)
        self.curIssueIndex = 0
        self.strFilenames = None
        self.redownloadingNews = False
        self.startRedownload = datetime.datetime.now()
        self.endRedownload = datetime.datetime.now()
        self.load()
        self.percentDownloaded = 0.0
        self.numIssuesExpected = 0
        self.needsParseNews = True
        self.newsIndexEntries = []
        if self.NewsOverHttp:
            self.redownloadNews()
        self.accept('newIssueOut', self.handleNewIssueOut)
        self.accept('clientCleanup', self.handleClientCleanup)
        return

    def parseNewsContent(self):
        if not self.needsParseNews:
            return
        self.needsParseNews = False
        result = False
        newsDir = self.findNewsDir()
        if newsDir:
            allHomeFiles = self.getAllHomeFilenames(newsDir)
            self.notify.debug('len allHomeFiles = %s' % len(allHomeFiles))
            self.numIssuesExpected = len(allHomeFiles)
            if allHomeFiles:
                for myIssueIndex, oneHomeFile in enumerate(allHomeFiles):
                    if type(oneHomeFile) == type(''):
                        justFilename = oneHomeFile
                    else:
                        justFilename = oneHomeFile.getFilename().getBasename()
                    self.notify.debug('parseNewContent %s' % justFilename)
                    parts = justFilename.split('_')
                    dateStr = parts[3]
                    majorVer, minorVer = self.calcIssueVersion(dateStr)
                    if majorVer == 1:
                        oneIssue = IssueFrame.IssueFrame(
                            self.backFrame, newsDir, dateStr, myIssueIndex,
                            len(allHomeFiles), self.strFilenames)
                    elif majorVer == 2:
                        oneIssue = IssueFrameV2.IssueFrameV2(
                            self.backFrame, newsDir, dateStr, myIssueIndex,
                            len(allHomeFiles), self.strFilenames,
                            self.newsIndexEntries)
                    else:
                        self.notify.warning(
                            'Dont know how to handle version %s, asuming v2' %
                            majorVer)
                        oneIssue = IssueFrameV2.IssueFrameV2(
                            self.backFrame, newsDir, dateStr, myIssueIndex,
                            len(allHomeFiles), self.strFilenames,
                            self.newsIndexEntries)
                    oneIssue.hide()
                    self.issues.append(oneIssue)

                if self.issues:
                    self.issues[-1].show()
                    self.curIssueIndex = len(self.issues) - 1
                    result = True
        if hasattr(base.cr, 'inGameNewsMgr') and base.cr.inGameNewsMgr:
            self.createdTime = base.cr.inGameNewsMgr.getLatestIssue()
            self.notify.debug('setting created time to latest issue %s' %
                              self.createdTime)
        else:
            self.createdTime = base.cr.toontownTimeManager.getCurServerDateTime(
            )
            self.notify.debug('setting created time cur server time %s' %
                              self.createdTime)
        return result

    def getAllHomeFilenames(self, newsDir):
        self.notify.debug('getAllHomeFilenames')
        newsDirAsFile = vfs.getFile(Filename(newsDir))
        fileList = newsDirAsFile.scanDirectory()
        fileNames = fileList.getFiles()
        self.notify.debug('filenames=%s' % fileNames)
        homeFileNames = set([])
        for name in fileNames:
            self.notify.debug('processing %s' % name)
            baseName = name.getFilename().getBasename()
            self.notify.debug('baseName=%s' % baseName)
            if 'hom1.' in baseName:
                homeFileNames.add(name)
            else:
                self.notify.debug('hom1. not in baseName')

        if not homeFileNames:
            self.notify.warning('couldnt find hom1. in %s' % fileNames)
            self.setErrorMessage(TTLocalizer.NewsPageNoIssues)
            return []

        def fileCmp(fileA, fileB):
            return fileA.getFilename().compareTo(fileB.getFilename())

        homeFileNames = list(homeFileNames)
        homeFileNames.sort(cmp=fileCmp)
        self.notify.debug('returned homeFileNames=%s' % homeFileNames)
        return homeFileNames

    def findNewsDir(self):
        if self.NewsOverHttp:
            return self.NewsStageDir
        searchPath = DSearchPath()
        if AppRunnerGlobal.appRunner:
            searchPath.appendDirectory(
                Filename.expandFrom('$TT_3_5_ROOT/phase_3.5/models/news'))
        else:
            basePath = os.path.expandvars('$TTMODELS') or './ttmodels'
            searchPath.appendDirectory(
                Filename.fromOsSpecific(basePath + '/built/' +
                                        self.NewsBaseDir))
            searchPath.appendDirectory(Filename(self.NewsBaseDir))
        pfile = Filename(self.NewsIndexFilename)
        found = vfs.resolveFilename(pfile, searchPath)
        if not found:
            self.notify.warning('findNewsDir - no path: %s' %
                                self.NewsIndexFilename)
            self.setErrorMessage(TTLocalizer.NewsPageErrorDownloadingFile %
                                 self.NewsIndexFilename)
            return None
        self.notify.debug('found index file %s' % pfile)
        realDir = pfile.getDirname()
        return realDir

    def load(self):
        self.loadBackground()

    def loadBackground(self):
        upsellBackground = loader.loadModel(
            'phase_3.5/models/gui/tt_m_gui_ign_newsStatusBackground')
        imageScaleX = self.FrameDimensions[1] - self.FrameDimensions[0]
        imageScaleY = self.FrameDimensions[3] - self.FrameDimensions[2]
        self.backFrame = DirectFrame(parent=self.parent,
                                     image=upsellBackground,
                                     image_scale=(imageScaleX, 1, imageScaleY),
                                     frameColor=(1, 1, 1, 0),
                                     frameSize=self.FrameDimensions,
                                     pos=(0, 0, 0),
                                     relief=DGG.FLAT,
                                     text=TTLocalizer.NewsPageDownloadingNews1,
                                     text_scale=0.06,
                                     text_pos=(0, -0.4))

    def addDownloadingTextTask(self):
        self.removeDownloadingTextTask()
        task = taskMgr.doMethodLater(1, self.loadingTextTask,
                                     'DirectNewsFrameDownloadingTextTask')
        task.startTime = globalClock.getFrameTime()
        self.loadingTextTask(task)

    def removeDownloadingTextTask(self):
        taskMgr.remove('DirectNewsFrameDownloadingTextTask')

    def loadMainPage(self):
        self.mainFrame = DirectFrame(parent=self.backFrame,
                                     frameSize=self.FrameDimensions,
                                     frameColor=(1, 0, 0, 1))

    def activate(self):
        if hasattr(
                self, 'createdTime'
        ) and self.createdTime < base.cr.inGameNewsMgr.getLatestIssue(
        ) and self.NewsOverHttp and not self.redownloadingNews:
            self.redownloadNews()
        else:
            self.addDownloadingTextTask()
        if self.needsParseNews and not self.redownloadingNews:
            self.parseNewsContent()
        self.active = True

    def deactivate(self):
        self.removeDownloadingTextTask()
        self.active = False

    def unload(self):
        self.removeDownloadingTextTask()
        result = taskMgr.remove(self.RedownloadTaskName)
        self.ignore('newsSnapshot')
        self.ignore('newsChangeWeek')
        self.ignore('newIssueOut')
        self.ignore('clientCleanup')

    def handleClientCleanup(self):
        pass

    def doSnapshot(self):
        pass

    def changeWeek(self, issueIndex):
        if 0 <= issueIndex and issueIndex < len(self.issues):
            self.issues[self.curIssueIndex].hide()
            self.issues[issueIndex].show()
            self.curIssueIndex = issueIndex

    def loadingTextTask(self, task):
        timeIndex = int(globalClock.getFrameTime() - task.startTime) % 3
        timeStrs = (TTLocalizer.NewsPageDownloadingNews0,
                    TTLocalizer.NewsPageDownloadingNews1,
                    TTLocalizer.NewsPageDownloadingNews2)
        textToDisplay = timeStrs[timeIndex] % int(self.percentDownloaded * 100)
        if self.backFrame['text'] != textToDisplay:
            if TTLocalizer.NewsPageDownloadingNewsSubstr in self.backFrame[
                    'text']:
                self.backFrame['text'] = textToDisplay
        return task.again

    def setErrorMessage(self, errText):
        self.backFrame['text'] = errText

    def redownloadNews(self):
        if self.redownloadingNews:
            self.notify.warning(
                'averting potential crash redownloadNews called twice, just returning'
            )
            return
        self.percentDownloaded = 0.0
        self.notify.info('starting redownloadNews')
        self.startRedownload = datetime.datetime.now()
        self.redownloadingNews = True
        self.addDownloadingTextTask()
        for issue in self.issues:
            issue.destroy()

        self.issues = []
        self.curIssueIndex = 0
        self.strFilenames = None
        self.needsParseNews = True
        self.newsUrl = self.getInGameNewsUrl()
        self.newsDir = Filename(self.findNewsDir())
        Filename(self.newsDir + '/.').makeDir()
        http = HTTPClient.getGlobalPtr()
        self.url = self.newsUrl + self.NewsIndexFilename
        self.ch = http.makeChannel(True)
        self.ch.beginGetDocument(self.url)
        self.rf = Ramfile()
        self.ch.downloadToRam(self.rf)
        taskMgr.remove(self.RedownloadTaskName)
        taskMgr.add(self.downloadIndexTask, self.RedownloadTaskName)
        return

    def downloadIndexTask(self, task):
        if self.ch.run():
            return task.cont
        if not self.ch.isValid():
            self.notify.warning('Unable to download %s' % self.url)
            self.redownloadingNews = False
            return task.done
        self.newsFiles = []
        filename = self.rf.readline()
        while filename:
            filename = filename.strip()
            if filename:
                self.newsFiles.append(filename)
            filename = self.rf.readline()

        del self.rf
        self.newsFiles.sort()
        self.newsIndexEntries = list(self.newsFiles)
        self.notify.info('Server lists %s news files' % len(self.newsFiles))
        self.notify.debug('self.newsIndexEntries=%s' % self.newsIndexEntries)
        self.readNewsCache()
        for basename in os.listdir(self.newsDir.toOsSpecific()):
            if basename != self.CacheIndexFilename and basename not in self.newsCache:
                junk = Filename(self.newsDir, basename)
                self.notify.info('Removing %s' % junk)
                junk.unlink()

        self.nextNewsFile = 0
        return self.downloadNextFile(task)

    def downloadNextFile(self, task):
        while self.nextNewsFile < len(
                self.newsFiles) and 'aaver' in self.newsFiles[
                    self.nextNewsFile]:
            self.nextNewsFile += 1

        if self.nextNewsFile >= len(self.newsFiles):
            self.notify.info('Done downloading news.')
            self.percentDownloaded = 1
            del self.newsFiles
            del self.nextNewsFile
            del self.newsUrl
            del self.newsDir
            del self.ch
            del self.url
            if hasattr(self, 'filename'):
                del self.filename
            self.redownloadingNews = False
            if self.active:
                self.parseNewsContent()
            return task.done
        self.percentDownloaded = float(self.nextNewsFile) / float(
            len(self.newsFiles))
        self.filename = self.newsFiles[self.nextNewsFile]
        self.nextNewsFile += 1
        self.url = self.newsUrl + self.filename
        localFilename = Filename(self.newsDir, self.filename)
        self.notify.info('testing for %s' % localFilename.getFullpath())
        doc = DocumentSpec(self.url)
        if self.filename in self.newsCache:
            size, date = self.newsCache[self.filename]
            if date and localFilename.exists() and (
                    size == 0 or localFilename.getFileSize() == size):
                doc.setDate(date)
                doc.setRequestMode(doc.RMNewer)
        self.ch.beginGetDocument(doc)
        self.ch.downloadToFile(localFilename)
        taskMgr.remove(self.RedownloadTaskName)
        taskMgr.add(self.downloadCurrentFileTask, self.RedownloadTaskName)

    def downloadCurrentFileTask(self, task):
        if self.ch.run():
            return task.cont
        if self.ch.getStatusCode() == 304:
            self.notify.info('already cached: %s' % self.filename)
            return self.downloadNextFile(task)
        localFilename = Filename(self.newsDir, self.filename)
        if not self.ch.isValid():
            self.notify.warning('Unable to download %s' % self.url)
            localFilename.unlink()
            if self.filename in self.newsCache:
                del self.newsCache[self.filename]
                self.saveNewsCache()
            return self.downloadNextFile(task)
        self.notify.info('downloaded %s' % self.filename)
        size = self.ch.getFileSize()
        doc = self.ch.getDocumentSpec()
        date = ''
        if doc.hasDate():
            date = doc.getDate().getString()
        self.newsCache[self.filename] = (size, date)
        self.saveNewsCache()
        return self.downloadNextFile(task)

    def readNewsCache(self):
        cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename)
        self.newsCache = {}
        if cacheIndexFilename.isRegularFile():
            file = open(cacheIndexFilename.toOsSpecific(), 'r')
            for line in file.readlines():
                line = line.strip()
                keywords = line.split('\t')
                if len(keywords) == 3:
                    filename, size, date = keywords
                    if filename in self.newsFiles:
                        try:
                            size = int(size)
                        except ValueError:
                            size = 0

                        self.newsCache[filename] = (size, date)

    def saveNewsCache(self):
        cacheIndexFilename = Filename(self.newsDir, self.CacheIndexFilename)
        try:
            file = open(cacheIndexFilename.toOsSpecific(), 'w')
        except IOError, e:
            self.notify.warning('error opening news cache file %s: %s' %
                                (cacheIndexFilename, str(e)))
            return

        for filename, (size, date) in self.newsCache.items():
            print >> file, '%s\t%s\t%s' % (filename, size, date)
示例#57
0
    def readContentsFile(self, tempFilename = None, freshDownload = False):
        """ Reads the contents.xml file for this particular host, once
        it has been downloaded into the indicated temporary file.
        Returns true on success, false if the contents file is not
        already on disk or is unreadable.

        If tempFilename is specified, it is the filename read, and it
        is copied the file into the standard location if it's not
        there already.  If tempFilename is not specified, the standard
        filename is read if it is known. """

        if not hasattr(PandaModules, 'TiXmlDocument'):
            return False

        if not tempFilename:
            if self.hostDir:
                # If the filename is not specified, we can infer it
                # if we already know our hostDir
                hostDir = self.hostDir
            else:
                # Otherwise, we have to guess the hostDir.
                hostDir = self.__determineHostDir(None, self.hostUrl)

            tempFilename = Filename(hostDir, 'contents.xml')

        doc = PandaModules.TiXmlDocument(tempFilename.toOsSpecific())
        if not doc.LoadFile():
            return False

        xcontents = doc.FirstChildElement('contents')
        if not xcontents:
            return False

        maxAge = xcontents.Attribute('max_age')
        if maxAge:
            try:
                maxAge = int(maxAge)
            except:
                maxAge = None
        if maxAge is None:
            # Default max_age if unspecified (see p3d_plugin.h).
            from direct.p3d.AppRunner import AppRunner
            maxAge = AppRunner.P3D_CONTENTS_DEFAULT_MAX_AGE

        # Get the latest possible expiration time, based on the max_age
        # indication.  Any expiration time later than this is in error.
        now = int(time.time())
        self.contentsExpiration = now + maxAge

        if freshDownload:
            self.contentsSpec.readHash(tempFilename)

            # Update the XML with the new download information.
            xorig = xcontents.FirstChildElement('orig')
            while xorig:
                xcontents.RemoveChild(xorig)
                xorig = xcontents.FirstChildElement('orig')

            xorig = PandaModules.TiXmlElement('orig')
            self.contentsSpec.storeXml(xorig)
            xorig.SetAttribute('expiration', str(self.contentsExpiration))

            xcontents.InsertEndChild(xorig)
            
        else:
            # Read the download hash and expiration time from the XML.
            expiration = None
            xorig = xcontents.FirstChildElement('orig')
            if xorig:
                self.contentsSpec.loadXml(xorig)
                expiration = xorig.Attribute('expiration')
                if expiration:
                    try:
                        expiration = int(expiration)
                    except:
                        expiration = None
            if not self.contentsSpec.hash:
                self.contentsSpec.readHash(tempFilename)

            if expiration is not None:
                self.contentsExpiration = min(self.contentsExpiration, expiration)

        # Look for our own entry in the hosts table.
        if self.hostUrl:
            self.__findHostXml(xcontents)
        else:
            assert self.hostDir
            self.__findHostXmlForHostDir(xcontents)

        if not self.hostDir:
            self.hostDir = self.__determineHostDir(None, self.hostUrl)

        # Get the list of packages available for download and/or import.
        xpackage = xcontents.FirstChildElement('package')
        while xpackage:
            name = xpackage.Attribute('name')
            platform = xpackage.Attribute('platform')
            version = xpackage.Attribute('version')
            try:
                solo = int(xpackage.Attribute('solo') or '')
            except ValueError:
                solo = False
                
            package = self.__makePackage(name, platform, version, solo)
            package.descFile = FileSpec()
            package.descFile.loadXml(xpackage)
            package.setupFilenames()

            package.importDescFile = None
            ximport = xpackage.FirstChildElement('import')
            if ximport:
                package.importDescFile = FileSpec()
                package.importDescFile.loadXml(ximport)

            xpackage = xpackage.NextSiblingElement('package')

        self.hasContentsFile = True

        # Now save the contents.xml file into the standard location.
        if not self.appRunner or self.appRunner.verifyContents != self.appRunner.P3DVCNever:
            assert self.hostDir
            filename = Filename(self.hostDir, 'contents.xml')
            filename.makeDir()
            if freshDownload:
                doc.SaveFile(filename.toOsSpecific())
            else:
                if filename != tempFilename:
                    tempFilename.copyTo(filename)

        return True
示例#58
0
    def __unpackArchive(self, step):
        """ Unpacks any files in the archive that want to be unpacked
        to disk.  Yields one of stepComplete, stepFailed, 
        restartDownload, or stepContinue. """

        if not self.extracts:
            # Nothing to extract.
            self.hasPackage = True
            yield self.stepComplete; return

        if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever:
            # We're not allowed to!
            yield self.stepFailed; return

        self.updated = True

        mfPathname = Filename(self.getPackageDir(), self.uncompressedArchive.filename)
        self.notify.info("Unpacking %s" % (mfPathname))
        mf = Multifile()
        if not mf.openRead(mfPathname):
            self.notify.warning("Couldn't open %s" % (mfPathname))
            yield self.stepFailed; return
        
        allExtractsOk = True
        step.bytesDone = 0
        for file in self.extracts:
            i = mf.findSubfile(file.filename)
            if i == -1:
                self.notify.warning("Not in Multifile: %s" % (file.filename))
                allExtractsOk = False
                continue

            targetPathname = Filename(self.getPackageDir(), file.filename)
            targetPathname.unlink()
            if not mf.extractSubfile(i, targetPathname):
                self.notify.warning("Couldn't extract: %s" % (file.filename))
                allExtractsOk = False
                continue
            
            if not file.quickVerify(self.getPackageDir(), notify = self.notify):
                self.notify.warning("After extracting, still incorrect: %s" % (file.filename))
                allExtractsOk = False
                continue

            # Make sure it's executable, and not writable.
            os.chmod(targetPathname.toOsSpecific(), 0555)

            step.bytesDone += file.size
            self.__updateStepProgress(step)
            if taskMgr.destroyed:
                # If the task manager has been destroyed, we must
                # be shutting down.  Get out of here.
                self.notify.warning("Task Manager destroyed, aborting unpacking %s" % (mfPathname))
                yield self.stepFailed; return

            yield self.stepContinue

        if not allExtractsOk:
            yield self.stepFailed; return

        self.hasPackage = True
        yield self.stepComplete; return
示例#59
0
    def __readDescFile(self):
        """ Reads the desc xml file for this particular package,
        assuming it's been already downloaded and verified.  Returns
        true on success, false on failure. """

        if self.hasDescFile:
            # No need to read it again.
            return True

        if self.solo:
            # If this is a "solo" package, we don't actually "read"
            # the desc file; that's the entire contents of the
            # package.
            self.hasDescFile = True
            self.hasPackage = True
            return True

        filename = Filename(self.getPackageDir(), self.descFileBasename)

        if not hasattr(PandaModules, 'TiXmlDocument'):
            return False
        doc = PandaModules.TiXmlDocument(filename.toOsSpecific())
        if not doc.LoadFile():
            return False

        xpackage = doc.FirstChildElement('package')
        if not xpackage:
            return False

        try:
            self.patchVersion = int(xpackage.Attribute('patch_version') or '')
        except ValueError:
            self.patchVersion = None

        self.displayName = None
        xconfig = xpackage.FirstChildElement('config')
        if xconfig:
            # The name for display to an English-speaking user.
            self.displayName = xconfig.Attribute('display_name')

            # True if any apps that use this package must be GUI apps.
            guiApp = xconfig.Attribute('gui_app')
            if guiApp:
                self.guiApp = int(guiApp)

        # The uncompressed archive, which will be mounted directly,
        # and also used for patching.
        xuncompressedArchive = xpackage.FirstChildElement(
            'uncompressed_archive')
        if xuncompressedArchive:
            self.uncompressedArchive = FileSpec()
            self.uncompressedArchive.loadXml(xuncompressedArchive)

        # The compressed archive, which is what is downloaded.
        xcompressedArchive = xpackage.FirstChildElement('compressed_archive')
        if xcompressedArchive:
            self.compressedArchive = FileSpec()
            self.compressedArchive.loadXml(xcompressedArchive)

        # The list of files that should be extracted to disk.
        self.extracts = []
        xextract = xpackage.FirstChildElement('extract')
        while xextract:
            file = FileSpec()
            file.loadXml(xextract)
            self.extracts.append(file)
            xextract = xextract.NextSiblingElement('extract')

        # The list of additional packages that must be installed for
        # this package to function properly.
        self.requires = []
        xrequires = xpackage.FirstChildElement('requires')
        while xrequires:
            packageName = xrequires.Attribute('name')
            version = xrequires.Attribute('version')
            hostUrl = xrequires.Attribute('host')
            if packageName and hostUrl:
                host = self.host.appRunner.getHostWithAlt(hostUrl)
                self.requires.append((packageName, version, host))
            xrequires = xrequires.NextSiblingElement('requires')

        self.hasDescFile = True

        # Now that we've read the desc file, go ahead and use it to
        # verify the download status.
        if self.__checkArchiveStatus():
            # It's all fully downloaded, unpacked, and ready.
            self.hasPackage = True
            return True

        # Still have to download it.
        self.__buildInstallPlans()
        return True