Пример #1
0
    def _import_compiled_module(self, fullname):
        """ Loads the compiled C/C++ shared object as a Python module,
        and returns it. """

        vfile = vfs.getFile(self.filename, False)

        # We can only import a compiled module if it already exists on
        # disk.  This means if it's a truly virtual file that has no
        # on-disk equivalent, we have to write it to a temporary file
        # first.
        if hasattr(vfile, 'getMount') and \
           isinstance(vfile.getMount(), VirtualFileMountSystem):
            # It's a real file.
            filename = self.filename
        else:
            # It's a virtual file.  Dump it.
            filename = Filename.temporary(
                '',
                self.filename.getBasenameWoExtension(),
                '.' + self.filename.getExtension(),
                type=Filename.TDso)
            filename.setExtension(self.filename.getExtension())
            fin = open(vfile, 'rb')
            fout = open(filename, 'wb')
            data = fin.read(4096)
            while data:
                fout.write(data)
                data = fin.read(4096)
            fin.close()
            fout.close()

        module = imp.load_module(fullname, None, filename.toOsSpecific(),
                                 self.desc)
        module.__file__ = self.filename.cStr()
        return module
Пример #2
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)
    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)
Пример #4
0
    def __applyPatch(self, step, patchfile):
        """ Applies the indicated patching in-place to the current
        uncompressed archive.  The patchfile is removed after the
        operation.  Yields one of stepComplete, stepFailed, 
        restartDownload, or stepContinue. """

        self.updated = True

        origPathname = Filename(self.getPackageDir(),
                                self.uncompressedArchive.filename)
        patchPathname = Filename(self.getPackageDir(), patchfile.file.filename)
        result = Filename.temporary('', 'patch_')
        self.notify.info("Patching %s with %s" % (origPathname, patchPathname))

        p = PandaModules.Patchfile()  # The C++ class

        ret = p.initiate(patchPathname, origPathname, result)
        if ret == EUSuccess:
            ret = p.run()
        while ret == EUOk:
            step.bytesDone = step.bytesNeeded * p.getProgress()
            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 patch %s" %
                    (origPathname))
                yield self.stepFailed
                return

            yield self.stepContinue
            ret = p.run()
        del p
        patchPathname.unlink()

        if ret < 0:
            self.notify.warning("Patching of %s failed." % (origPathname))
            result.unlink()
            yield self.stepFailed
            return

        if not result.renameTo(origPathname):
            self.notify.warning("Couldn't rename %s to %s" %
                                (result, origPathname))
            yield self.stepFailed
            return

        yield self.stepComplete
        return
Пример #5
0
    def freshenFile(self, host, fileSpec, localPathname):
        """ Ensures that the localPathname is the most current version
        of the file defined by fileSpec, as offered by host.  If not,
        it downloads a new version on-the-spot.  Returns true on
        success, false on failure. """

        if fileSpec.quickVerify(pathname = localPathname):
            # It's good, keep it.
            return True

        assert self.http

        # It's stale, get a new one.
        doc = None
        if self.superMirrorUrl:
            # Use the "super mirror" first.
            url = PandaModules.URLSpec(self.superMirrorUrl + fileSpec.filename)
            self.notify.info("Freshening %s" % (url))
            doc = self.http.getDocument(url)

        if not doc or not doc.isValid():
            # Failing the super mirror, contact the actual host.
            url = PandaModules.URLSpec(host.hostUrlPrefix + fileSpec.filename)
            self.notify.info("Freshening %s" % (url))
            doc = self.http.getDocument(url)
            if not doc.isValid():
                return False

        file = Filename.temporary('', 'p3d_')
        if not doc.downloadToFile(file):
            # Failed to download.
            file.unlink()
            return False

        # Successfully downloaded!
        localPathname.makeDir()
        if not file.renameTo(localPathname):
            # Couldn't move it into place.
            file.unlink()
            return False

        if not fileSpec.fullVerify(pathname = localPathname):
            # No good after download.
            self.notify.info("%s is still no good after downloading." % (url))
            return False

        return True
Пример #6
0
    def freshenFile(self, host, fileSpec, localPathname):
        """ Ensures that the localPathname is the most current version
        of the file defined by fileSpec, as offered by host.  If not,
        it downloads a new version on-the-spot.  Returns true on
        success, false on failure. """

        if fileSpec.quickVerify(pathname=localPathname):
            # It's good, keep it.
            return True

        assert self.http

        # It's stale, get a new one.
        doc = None
        if self.superMirrorUrl:
            # Use the "super mirror" first.
            url = PandaModules.URLSpec(self.superMirrorUrl + fileSpec.filename)
            self.notify.info("Freshening %s" % (url))
            doc = self.http.getDocument(url)

        if not doc or not doc.isValid():
            # Failing the super mirror, contact the actual host.
            url = PandaModules.URLSpec(host.hostUrlPrefix + fileSpec.filename)
            self.notify.info("Freshening %s" % (url))
            doc = self.http.getDocument(url)
            if not doc.isValid():
                return False

        file = Filename.temporary('', 'p3d_')
        if not doc.downloadToFile(file):
            # Failed to download.
            file.unlink()
            return False

        # Successfully downloaded!
        localPathname.makeDir()
        if not file.renameTo(localPathname):
            # Couldn't move it into place.
            file.unlink()
            return False

        if not fileSpec.fullVerify(pathname=localPathname):
            # No good after download.
            self.notify.info("%s is still no good after downloading." % (url))
            return False

        return True
Пример #7
0
    def __applyPatch(self, step, patchfile):
        """ Applies the indicated patching in-place to the current
        uncompressed archive.  The patchfile is removed after the
        operation.  Yields one of stepComplete, stepFailed, 
        restartDownload, or stepContinue. """

        self.updated = True

        origPathname = Filename(self.getPackageDir(), self.uncompressedArchive.filename)
        patchPathname = Filename(self.getPackageDir(), patchfile.file.filename)
        result = Filename.temporary("", "patch_")
        self.notify.info("Patching %s with %s" % (origPathname, patchPathname))

        p = PandaModules.Patchfile()  # The C++ class

        ret = p.initiate(patchPathname, origPathname, result)
        if ret == EUSuccess:
            ret = p.run()
        while ret == EUOk:
            step.bytesDone = step.bytesNeeded * p.getProgress()
            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 patch %s" % (origPathname))
                yield self.stepFailed
                return

            yield self.stepContinue
            ret = p.run()
        del p
        patchPathname.unlink()

        if ret < 0:
            self.notify.warning("Patching of %s failed." % (origPathname))
            result.unlink()
            yield self.stepFailed
            return

        if not result.renameTo(origPathname):
            self.notify.warning("Couldn't rename %s to %s" % (result, origPathname))
            yield self.stepFailed
            return

        yield self.stepComplete
        return
    def __init__(self, p3dfile, tokens={}):
        self.p3dfile = Filename(p3dfile)
        self.basename = self.p3dfile.getBasenameWoExtension()
        self.tokens = tokens

        self.tempDir = Filename.temporary("", self.basename, "") + "/"
        self.tempDir.makeDir()
        self.host = HostInfo(
            PandaSystem.getPackageHostUrl(), appRunner=appRunner, hostDir=self.tempDir, asMirror=False, perPlatform=True
        )

        self.http = HTTPClient.getGlobalPtr()
        if not self.host.hasContentsFile:
            if not self.host.readContentsFile():
                if not self.host.downloadContentsFile(self.http):
                    Standalone.notify.error("couldn't read host")
                    return
    def __init__(self, p3dfile, tokens={}):
        self.p3dfile = Filename(p3dfile)
        self.basename = self.p3dfile.getBasenameWoExtension()
        self.tokens = tokens

        self.tempDir = Filename.temporary("", self.basename, "") + "/"
        self.tempDir.makeDir()
        self.host = HostInfo(PandaSystem.getPackageHostUrl(),
                             appRunner=appRunner,
                             hostDir=self.tempDir,
                             asMirror=False,
                             perPlatform=True)

        self.http = HTTPClient.getGlobalPtr()
        if not self.host.hasContentsFile:
            if not self.host.readContentsFile():
                if not self.host.downloadContentsFile(self.http):
                    Standalone.notify.error("couldn't read host")
                    return
Пример #10
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)
Пример #11
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)
Пример #12
0
                            launcher.setPandaErrorCode(4)
                        else:
                            # There are other kinds of failures, but these will
                            # generally have been caught already by the first test; so
                            # if we get here there may be some bigger problem.  Just
                            # give the generic "big problem" message.
                            launcher.setPandaErrorCode(6)
                    except NameError, e:
                        # no launcher
                        pass
                    except AttributeError, e:
                        self.notify.warning("%s" % (str(e),))
                        pass
                    return False

        tempFilename = Filename.temporary("", "p3d_", ".xml")
        if rf:
            f = open(tempFilename.toOsSpecific(), "wb")
            f.write(rf.getData())
            f.close()
            if hashVal:
                hashVal.hashString(rf.getData())

            if not self.readContentsFile(tempFilename, freshDownload=True):
                self.notify.warning("Failure reading %s" % (url))
                tempFilename.unlink()
                return False

            tempFilename.unlink()
            return True
Пример #13
0
                            launcher.setPandaErrorCode(4)
                        else:
                            # There are other kinds of failures, but these will
                            # generally have been caught already by the first test; so
                            # if we get here there may be some bigger problem.  Just
                            # give the generic "big problem" message.
                            launcher.setPandaErrorCode(6)
                    except NameError,e:
                        # no launcher
                        pass
                    except AttributeError, e:
                        self.notify.warning("%s" % (str(e),))
                        pass
                    return False
                    
        tempFilename = Filename.temporary('', 'p3d_', '.xml')
        if rf:
            f = open(tempFilename.toOsSpecific(), 'wb')
            f.write(rf.getData())
            f.close()
            if hashVal:
                hashVal.hashString(rf.getData())

            if not self.readContentsFile(tempFilename, freshDownload = True):
                self.notify.warning("Failure reading %s" % (url))
                tempFilename.unlink()
                return False

            tempFilename.unlink()
            return True
Пример #14
0
def runPackedApp(args):
    if not args:
        raise ArgumentError, "No Panda app specified.  Use:\npython RunAppMF.py app.mf"

    vfs = VirtualFileSystem.getGlobalPtr()

    fname = Filename.fromOsSpecific(args[0])
    if not vfs.exists(fname):
        raise ArgumentError, "No such file: %s" % (args[0])

    mf = Multifile()
    if not mf.openRead(fname):
        raise ArgumentError, "Not a Panda Multifile: %s" % (args[0])

    # Clear *all* the mount points, including "/", so that we no
    # longer access the disk directly.
    vfs.unmountAll()

    # Mount the Multifile under /mf, by convention, and make that our
    # "current directory".
    vfs.mount(mf, MultifileRoot, vfs.MFReadOnly)
    vfs.chdir(MultifileRoot)

    # Make sure the directories on our standard Python path are mounted
    # read-only, so we can still load Python.
    for dirname in sys.path:
        vfs.mount(dirname, dirname, vfs.MFReadOnly)

    # Also mount some standard directories read-write (temporary and
    # app-data directories).
    tdir = Filename.temporary('', '')
    for dirname in set([
            tdir.getDirname(),
            Filename.getTempDirectory().cStr(),
            Filename.getUserAppdataDirectory().cStr(),
            Filename.getCommonAppdataDirectory().cStr()
    ]):
        vfs.mount(dirname, dirname, 0)

    # Now set up Python to import this stuff.
    VFSImporter.register()
    sys.path = [MultifileRoot] + sys.path

    # Put our root directory on the model-path and prc-path, too.
    getModelPath().prependDirectory(MultifileRoot)

    # Load the implicit App.prc file.
    loadPrcFileData(AppPrcFilename, AppPrc)

    # Load any prc files in the root.  We have to load them
    # explicitly, since the ConfigPageManager can't directly look
    # inside the vfs.
    for f in vfs.scanDirectory(MultifileRoot):
        if f.getFilename().getExtension() == 'prc':
            data = f.readFile(True)
            loadPrcFileData(f.getFilename().cStr(), data)

    # Replace the builtin open and file symbols so user code will get
    # our versions by default, which can open and read files out of
    # the multifile.
    __builtin__.file = file.file
    __builtin__.open = file.open
    os.listdir = file.listdir
    os.walk = file.walk

    import main
    if hasattr(main, 'main') and callable(main.main):
        main.main()
Пример #15
0
    def markUsed(self):
        """ Marks the package as having been used.  This is normally
        called automatically by installPackage(). """

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

        if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever:
            # Not allowed to write any files to the package directory.
            return

        if self.updated:
            # If we've just installed a new version of the package,
            # re-measure the actual disk space used.
            self.diskSpace = self.__measureDiskSpace()

        filename = Filename(self.getPackageDir(), self.UsageBasename)
        doc = TiXmlDocument(filename.toOsSpecific())
        if not doc.LoadFile():
            decl = TiXmlDeclaration("1.0", "utf-8", "")
            doc.InsertEndChild(decl)

        xusage = doc.FirstChildElement('usage')
        if not xusage:
            doc.InsertEndChild(TiXmlElement('usage'))
            xusage = doc.FirstChildElement('usage')

        now = int(time.time())

        count = xusage.Attribute('count_app')
        try:
            count = int(count or '')
        except ValueError:
            count = 0
            xusage.SetAttribute('first_use', str(now))
        count += 1
        xusage.SetAttribute('count_app', str(count))

        xusage.SetAttribute('last_use', str(now))

        if self.updated:
            xusage.SetAttribute('last_update', str(now))
            self.updated = False
        else:
            # Since we haven't changed the disk space, we can just
            # read it from the previous xml file.
            diskSpace = xusage.Attribute('disk_space')
            try:
                diskSpace = int(diskSpace or '')
            except ValueError:
                # Unless it wasn't set already.
                self.diskSpace = self.__measureDiskSpace()

        xusage.SetAttribute('disk_space', str(self.diskSpace))

        # 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.getPackageDir().cStr(), '.xml')
        if doc.SaveFile(tfile.toOsSpecific()):
            tfile.renameTo(filename)
Пример #16
0
    def markUsed(self):
        """ Marks the package as having been used.  This is normally
        called automatically by installPackage(). """

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

        if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever:
            # Not allowed to write any files to the package directory.
            return

        if self.updated:
            # If we've just installed a new version of the package,
            # re-measure the actual disk space used.
            self.diskSpace = self.__measureDiskSpace()

        filename = Filename(self.getPackageDir(), self.UsageBasename)
        doc = TiXmlDocument(filename.toOsSpecific())
        if not doc.LoadFile():
            decl = TiXmlDeclaration("1.0", "utf-8", "")
            doc.InsertEndChild(decl)
            
        xusage = doc.FirstChildElement('usage')
        if not xusage:
            doc.InsertEndChild(TiXmlElement('usage'))
            xusage = doc.FirstChildElement('usage')

        now = int(time.time())
        
        count = xusage.Attribute('count_app')
        try:
            count = int(count or '')
        except ValueError:
            count = 0
            xusage.SetAttribute('first_use', str(now))
        count += 1
        xusage.SetAttribute('count_app', str(count))

        xusage.SetAttribute('last_use', str(now))

        if self.updated:
            xusage.SetAttribute('last_update', str(now))
            self.updated = False
        else:
            # Since we haven't changed the disk space, we can just
            # read it from the previous xml file.
            diskSpace = xusage.Attribute('disk_space')
            try:
                diskSpace = int(diskSpace or '')
            except ValueError:
                # Unless it wasn't set already.
                self.diskSpace = self.__measureDiskSpace()

        xusage.SetAttribute('disk_space', str(self.diskSpace))

        # 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.getPackageDir().cStr(), '.xml')
        if doc.SaveFile(tfile.toOsSpecific()):
            tfile.renameTo(filename)
    def __init__(self, p3dfile, shortname, fullname, version, tokens={}):
        if not shortname:
            shortname = p3dfile.getBasenameWoExtension()
        self.shortname = shortname
        self.fullname = fullname
        self.version = str(version)
        self.includeRequires = False
        self.licensename = ""
        self.licensefile = Filename()
        self.authorid = "org.panda3d"
        self.authorname = os.environ.get("DEBFULLNAME", "")
        self.authoremail = os.environ.get("DEBEMAIL", "")

        # Try to determine a default author name ourselves.
        uname = None
        if pwd is not None and hasattr(os, 'getuid'):
            uinfo = pwd.getpwuid(os.getuid())
            if uinfo:
                uname = uinfo.pw_name
                if not self.authorname:
                    self.authorname = \
                        uinfo.pw_gecos.split(',', 1)[0]

        # Fallbacks in case that didn't work or wasn't supported.
        if not uname:
            uname = getpass.getuser()
        if not self.authorname:
            self.authorname = uname
        if not self.authoremail and ' ' not in uname:
            self.authoremail = "%s@%s" % (uname, socket.gethostname())

        self.standalone = Standalone(p3dfile, tokens)
        self.tempDir = Filename.temporary("", self.shortname, "") + "/"
        self.tempDir.makeDir()
        self.__linuxRoot = None

        # Load the p3d file to read out the required packages
        mf = Multifile()
        if not mf.openRead(p3dfile):
            Installer.notify.error("Not a Panda3D application: %s" %
                                   (p3dFilename))
            return

        # Now load the p3dInfo file.
        self.hostUrl = PandaSystem.getPackageHostUrl()
        if not self.hostUrl:
            self.hostUrl = self.standalone.host.hostUrl
        self.requires = []
        i = mf.findSubfile('p3d_info.xml')
        if i >= 0:
            stream = mf.openReadSubfile(i)
            p3dInfo = readXmlStream(stream)
            mf.closeReadSubfile(stream)
            if p3dInfo:
                p3dPackage = p3dInfo.FirstChildElement('package')
                p3dHost = p3dPackage.FirstChildElement('host')
                if p3dHost.Attribute('url'):
                    self.hostUrl = p3dHost.Attribute('url')
                p3dRequires = p3dPackage.FirstChildElement('requires')
                while p3dRequires:
                    self.requires.append((p3dRequires.Attribute('name'),
                                          p3dRequires.Attribute('version'),
                                          p3dRequires.Attribute('host')))
                    p3dRequires = p3dRequires.NextSiblingElement('requires')

                if not self.fullname:
                    p3dConfig = p3dPackage.FirstChildElement('config')
                    if p3dConfig:
                        self.fullname = p3dConfig.Attribute('display_name')

        if not self.fullname:
            self.fullname = self.shortname
    def __init__(self, p3dfile, shortname, fullname, version, tokens={}):
        if not shortname:
            shortname = p3dfile.getBasenameWoExtension()
        self.shortname = shortname
        self.fullname = fullname
        self.version = str(version)
        self.includeRequires = False
        self.licensename = ""
        self.licensefile = Filename()
        self.authorid = "org.panda3d"
        self.authorname = os.environ.get("DEBFULLNAME", "")
        self.authoremail = os.environ.get("DEBEMAIL", "")

        # Try to determine a default author name ourselves.
        uname = None
        if pwd is not None and hasattr(os, "getuid"):
            uinfo = pwd.getpwuid(os.getuid())
            if uinfo:
                uname = uinfo.pw_name
                if not self.authorname:
                    self.authorname = uinfo.pw_gecos.split(",", 1)[0]

        # Fallbacks in case that didn't work or wasn't supported.
        if not uname:
            uname = getpass.getuser()
        if not self.authorname:
            self.authorname = uname
        if not self.authoremail and " " not in uname:
            self.authoremail = "%s@%s" % (uname, socket.gethostname())

        self.standalone = Standalone(p3dfile, tokens)
        self.tempDir = Filename.temporary("", self.shortname, "") + "/"
        self.tempDir.makeDir()
        self.__linuxRoot = None

        # Load the p3d file to read out the required packages
        mf = Multifile()
        if not mf.openRead(p3dfile):
            Installer.notify.error("Not a Panda3D application: %s" % (p3dFilename))
            return

        # Now load the p3dInfo file.
        self.hostUrl = PandaSystem.getPackageHostUrl()
        if not self.hostUrl:
            self.hostUrl = self.standalone.host.hostUrl
        self.requires = []
        i = mf.findSubfile("p3d_info.xml")
        if i >= 0:
            stream = mf.openReadSubfile(i)
            p3dInfo = readXmlStream(stream)
            mf.closeReadSubfile(stream)
            if p3dInfo:
                p3dPackage = p3dInfo.FirstChildElement("package")
                p3dHost = p3dPackage.FirstChildElement("host")
                if p3dHost.Attribute("url"):
                    self.hostUrl = p3dHost.Attribute("url")
                p3dRequires = p3dPackage.FirstChildElement("requires")
                while p3dRequires:
                    self.requires.append(
                        (p3dRequires.Attribute("name"), p3dRequires.Attribute("version"), p3dRequires.Attribute("host"))
                    )
                    p3dRequires = p3dRequires.NextSiblingElement("requires")

                if not self.fullname:
                    p3dConfig = p3dPackage.FirstChildElement("config")
                    if p3dConfig:
                        self.fullname = p3dConfig.Attribute("display_name")

        if not self.fullname:
            self.fullname = self.shortname