def buildAPP(self, output, platform):

        output = Filename(output)
        if output.isDirectory() and output.getExtension() != 'app':
            output = Filename(output, "%s.app" % self.fullname)
        Installer.notify.info("Creating %s..." % output)

        # Create the executable for the application bundle
        exefile = Filename(output, "Contents/MacOS/" + self.shortname)
        exefile.makeDir()
        if self.includeRequires:
            extraTokens = {"host_dir": "../Resources"}
        else:
            extraTokens = {}
        self.standalone.build(exefile, platform, extraTokens)
        hostDir = Filename(output, "Contents/Resources/")
        hostDir.makeDir()
        self.installPackagesInto(hostDir, platform)

        # Create the application plist file.
        # Although it might make more sense to use Python's plistlib module here,
        # it is not available on non-OSX systems before Python 2.6.
        plist = open(
            Filename(output, "Contents/Info.plist").toOsSpecific(), "w")
        print >> plist, '<?xml version="1.0" encoding="UTF-8"?>'
        print >> plist, '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'
        print >> plist, '<plist version="1.0">'
        print >> plist, '<dict>'
        print >> plist, '\t<key>CFBundleDevelopmentRegion</key>'
        print >> plist, '\t<string>English</string>'
        print >> plist, '\t<key>CFBundleDisplayName</key>'
        print >> plist, '\t<string>%s</string>' % self.fullname
        print >> plist, '\t<key>CFBundleExecutable</key>'
        print >> plist, '\t<string>%s</string>' % exefile.getBasename()
        print >> plist, '\t<key>CFBundleIdentifier</key>'
        print >> plist, '\t<string>%s.%s</string>' % (self.authorid,
                                                      self.shortname)
        print >> plist, '\t<key>CFBundleInfoDictionaryVersion</key>'
        print >> plist, '\t<string>6.0</string>'
        print >> plist, '\t<key>CFBundleName</key>'
        print >> plist, '\t<string>%s</string>' % self.shortname
        print >> plist, '\t<key>CFBundlePackageType</key>'
        print >> plist, '\t<string>APPL</string>'
        print >> plist, '\t<key>CFBundleShortVersionString</key>'
        print >> plist, '\t<string>%s</string>' % self.version
        print >> plist, '\t<key>CFBundleVersion</key>'
        print >> plist, '\t<string>%s</string>' % self.version
        print >> plist, '\t<key>LSHasLocalizedDisplayName</key>'
        print >> plist, '\t<false/>'
        print >> plist, '\t<key>NSAppleScriptEnabled</key>'
        print >> plist, '\t<false/>'
        print >> plist, '\t<key>NSPrincipalClass</key>'
        print >> plist, '\t<string>NSApplication</string>'
        print >> plist, '</dict>'
        print >> plist, '</plist>'
        plist.close()

        return output
    def buildAPP(self, output, platform):

        output = Filename(output)
        if output.isDirectory() and output.getExtension() != "app":
            output = Filename(output, "%s.app" % self.fullname)
        Installer.notify.info("Creating %s..." % output)

        # Create the executable for the application bundle
        exefile = Filename(output, "Contents/MacOS/" + self.shortname)
        exefile.makeDir()
        if self.includeRequires:
            extraTokens = {"host_dir": "../Resources"}
        else:
            extraTokens = {}
        self.standalone.build(exefile, platform, extraTokens)
        hostDir = Filename(output, "Contents/Resources/")
        hostDir.makeDir()
        self.installPackagesInto(hostDir, platform)

        # Create the application plist file.
        # Although it might make more sense to use Python's plistlib module here,
        # it is not available on non-OSX systems before Python 2.6.
        plist = open(Filename(output, "Contents/Info.plist").toOsSpecific(), "w")
        print >> plist, '<?xml version="1.0" encoding="UTF-8"?>'
        print >> plist, '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'
        print >> plist, '<plist version="1.0">'
        print >> plist, "<dict>"
        print >> plist, "\t<key>CFBundleDevelopmentRegion</key>"
        print >> plist, "\t<string>English</string>"
        print >> plist, "\t<key>CFBundleDisplayName</key>"
        print >> plist, "\t<string>%s</string>" % self.fullname
        print >> plist, "\t<key>CFBundleExecutable</key>"
        print >> plist, "\t<string>%s</string>" % exefile.getBasename()
        print >> plist, "\t<key>CFBundleIdentifier</key>"
        print >> plist, "\t<string>%s.%s</string>" % (self.authorid, self.shortname)
        print >> plist, "\t<key>CFBundleInfoDictionaryVersion</key>"
        print >> plist, "\t<string>6.0</string>"
        print >> plist, "\t<key>CFBundleName</key>"
        print >> plist, "\t<string>%s</string>" % self.shortname
        print >> plist, "\t<key>CFBundlePackageType</key>"
        print >> plist, "\t<string>APPL</string>"
        print >> plist, "\t<key>CFBundleShortVersionString</key>"
        print >> plist, "\t<string>%s</string>" % self.version
        print >> plist, "\t<key>CFBundleVersion</key>"
        print >> plist, "\t<string>%s</string>" % self.version
        print >> plist, "\t<key>LSHasLocalizedDisplayName</key>"
        print >> plist, "\t<false/>"
        print >> plist, "\t<key>NSAppleScriptEnabled</key>"
        print >> plist, "\t<false/>"
        print >> plist, "\t<key>NSPrincipalClass</key>"
        print >> plist, "\t<string>NSApplication</string>"
        print >> plist, "</dict>"
        print >> plist, "</plist>"
        plist.close()

        return output
    def buildAll(self, outputDir="."):
        """ Creates a (graphical) installer for every known platform.
        Call this after you have set the desired parameters. """

        platforms = set()
        for package in self.standalone.host.getPackages(name="p3dembed"):
            platforms.add(package.platform)
        if len(platforms) == 0:
            Installer.notify.warning("No platforms found to build for!")

        outputDir = Filename(outputDir + "/")
        outputDir.makeDir()
        for platform in platforms:
            output = Filename(outputDir, platform + "/")
            output.makeDir()
            self.build(output, platform)
    def buildAll(self, outputDir="."):
        """ Creates a (graphical) installer for every known platform.
        Call this after you have set the desired parameters. """

        platforms = set()
        for package in self.standalone.host.getPackages(name="p3dembed"):
            platforms.add(package.platform)
        if len(platforms) == 0:
            Installer.notify.warning("No platforms found to build for!")

        outputDir = Filename(outputDir + "/")
        outputDir.makeDir()
        for platform in platforms:
            output = Filename(outputDir, platform + "/")
            output.makeDir()
            self.build(output, platform)
    def buildAll(self, outputDir="."):
        """ Builds standalone executables for every known platform,
        into the specified output directory. """

        platforms = set()
        for package in self.host.getPackages(name="p3dembed"):
            platforms.add(package.platform)
        if len(platforms) == 0:
            Standalone.notify.warning("No platforms found to build for!")

        outputDir = Filename(outputDir + "/")
        outputDir.makeDir()
        for platform in platforms:
            if platform.startswith("win"):
                self.build(Filename(outputDir, platform + "/" + self.basename + ".exe"), platform)
            else:
                self.build(Filename(outputDir, platform + "/" + self.basename), platform)
    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 buildAll(self, outputDir="."):
        """ Builds standalone executables for every known platform,
        into the specified output directory. """

        platforms = set()
        for package in self.host.getPackages(name="p3dembed"):
            platforms.add(package.platform)
        if len(platforms) == 0:
            Standalone.notify.warning("No platforms found to build for!")

        outputDir = Filename(outputDir + "/")
        outputDir.makeDir()
        for platform in platforms:
            if platform.startswith("win"):
                self.build(
                    Filename(outputDir,
                             platform + "/" + self.basename + ".exe"),
                    platform)
            else:
                self.build(Filename(outputDir, platform + "/" + self.basename),
                           platform)
    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 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 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()
示例#11
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()
    def buildNSIS(self, output, platform):
        # Check if we have makensis first
        makensis = None
        if (sys.platform.startswith("win")):
            syspath = os.defpath.split(";") + os.environ["PATH"].split(";")
            for p in set(syspath):
                p1 = os.path.join(p, "makensis.exe")
                p2 = os.path.join(os.path.dirname(p), "nsis", "makensis.exe")
                if os.path.isfile(p1):
                    makensis = p1
                    break
                elif os.path.isfile(p2):
                    makensis = p2
                    break
            if not makensis:
                import pandac
                makensis = os.path.dirname(os.path.dirname(pandac.__file__))
                makensis = os.path.join(makensis, "nsis", "makensis.exe")
                if not os.path.isfile(makensis): makensis = None
        else:
            for p in os.defpath.split(":") + os.environ["PATH"].split(":"):
                if os.path.isfile(os.path.join(p, "makensis")):
                    makensis = os.path.join(p, "makensis")

        if makensis == None:
            Installer.notify.warning(
                "Makensis utility not found, no Windows installer will be built!"
            )
            return None

        output = Filename(output)
        if output.isDirectory():
            output = Filename(output,
                              "%s %s.exe" % (self.fullname, self.version))
        Installer.notify.info("Creating %s..." % output)
        output.makeAbsolute()
        extrafiles = self.standalone.getExtraFiles(platform)

        exefile = Filename(Filename.getTempDirectory(),
                           self.shortname + ".exe")
        exefile.unlink()
        if self.includeRequires:
            extraTokens = {"host_dir": "."}
        else:
            extraTokens = {}
        self.standalone.build(exefile, platform, extraTokens)

        # Temporary directory to store the hostdir in
        hostDir = Filename(self.tempDir, platform + "/")
        if not hostDir.exists():
            hostDir.makeDir()
            self.installPackagesInto(hostDir, platform)

        nsifile = Filename(Filename.getTempDirectory(),
                           self.shortname + ".nsi")
        nsifile.unlink()
        nsi = open(nsifile.toOsSpecific(), "w")

        # Some global info
        nsi.write('Name "%s"\n' % self.fullname)
        nsi.write('OutFile "%s"\n' % output.toOsSpecific())
        nsi.write('InstallDir "$PROGRAMFILES\\%s"\n' % self.fullname)
        nsi.write('SetCompress auto\n')
        nsi.write('SetCompressor lzma\n')
        nsi.write('ShowInstDetails nevershow\n')
        nsi.write('ShowUninstDetails nevershow\n')
        nsi.write('InstType "Typical"\n')

        # Tell Vista that we require admin rights
        nsi.write('RequestExecutionLevel admin\n')
        nsi.write('\n')
        nsi.write('Function launch\n')
        nsi.write('  ExecShell "open" "$INSTDIR\\%s.exe"\n' % self.shortname)
        nsi.write('FunctionEnd\n')
        nsi.write('\n')
        nsi.write('!include "MUI2.nsh"\n')
        nsi.write('!define MUI_ABORTWARNING\n')
        nsi.write('!define MUI_FINISHPAGE_RUN\n')
        nsi.write('!define MUI_FINISHPAGE_RUN_FUNCTION launch\n')
        nsi.write('!define MUI_FINISHPAGE_RUN_TEXT "Run %s"\n' % self.fullname)
        nsi.write('\n')
        nsi.write('Var StartMenuFolder\n')
        nsi.write('!insertmacro MUI_PAGE_WELCOME\n')
        if not self.licensefile.empty():
            abs = Filename(self.licensefile)
            abs.makeAbsolute()
            nsi.write('!insertmacro MUI_PAGE_LICENSE "%s"\n' %
                      abs.toOsSpecific())
        nsi.write('!insertmacro MUI_PAGE_DIRECTORY\n')
        nsi.write(
            '!insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder\n')
        nsi.write('!insertmacro MUI_PAGE_INSTFILES\n')
        nsi.write('!insertmacro MUI_PAGE_FINISH\n')
        nsi.write('!insertmacro MUI_UNPAGE_WELCOME\n')
        nsi.write('!insertmacro MUI_UNPAGE_CONFIRM\n')
        nsi.write('!insertmacro MUI_UNPAGE_INSTFILES\n')
        nsi.write('!insertmacro MUI_UNPAGE_FINISH\n')
        nsi.write('!insertmacro MUI_LANGUAGE "English"\n')

        # This section defines the installer.
        nsi.write('Section "" SecCore\n')
        nsi.write('  SetOutPath "$INSTDIR"\n')
        nsi.write('  File "%s"\n' % exefile.toOsSpecific())
        for f in extrafiles:
            nsi.write('  File "%s"\n' % f.toOsSpecific())
        curdir = ""
        for root, dirs, files in self.os_walk(hostDir.toOsSpecific()):
            for name in files:
                file = Filename.fromOsSpecific(os.path.join(root, name))
                file.makeAbsolute()
                file.makeRelativeTo(hostDir)
                outdir = file.getDirname().replace('/', '\\')
                if curdir != outdir:
                    nsi.write('  SetOutPath "$INSTDIR\\%s"\n' % outdir)
                    curdir = outdir
                nsi.write('  File "%s"\n' % os.path.join(root, name))
        nsi.write('  WriteUninstaller "$INSTDIR\\Uninstall.exe"\n')
        nsi.write('  ; Start menu items\n')
        nsi.write('  !insertmacro MUI_STARTMENU_WRITE_BEGIN Application\n')
        nsi.write('    CreateDirectory "$SMPROGRAMS\\$StartMenuFolder"\n')
        nsi.write(
            '    CreateShortCut "$SMPROGRAMS\\$StartMenuFolder\\%s.lnk" "$INSTDIR\\%s.exe"\n'
            % (self.fullname, self.shortname))
        nsi.write(
            '    CreateShortCut "$SMPROGRAMS\\$StartMenuFolder\\Uninstall.lnk" "$INSTDIR\\Uninstall.exe"\n'
        )
        nsi.write('  !insertmacro MUI_STARTMENU_WRITE_END\n')
        nsi.write('SectionEnd\n')

        # This section defines the uninstaller.
        nsi.write('Section Uninstall\n')
        nsi.write('  Delete "$INSTDIR\\%s.exe"\n' % self.shortname)
        for f in extrafiles:
            nsi.write('  Delete "%s"\n' % f.getBasename())
        nsi.write('  Delete "$INSTDIR\\Uninstall.exe"\n')
        nsi.write('  RMDir /r "$INSTDIR"\n')
        nsi.write('  ; Start menu items\n')
        nsi.write(
            '  !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuFolder\n'
        )
        nsi.write('  Delete "$SMPROGRAMS\\$StartMenuFolder\\Uninstall.lnk"\n')
        nsi.write('  RMDir "$SMPROGRAMS\\$StartMenuFolder"\n')
        nsi.write('SectionEnd')
        nsi.close()

        cmd = [makensis]
        for o in ["V2"]:
            if sys.platform.startswith("win"):
                cmd.append("/" + o)
            else:
                cmd.append("-" + o)
        cmd.append(nsifile.toOsSpecific())
        print cmd
        try:
            retcode = subprocess.call(cmd, shell=False)
            if retcode != 0:
                self.notify.warning("Failure invoking NSIS command.")
        except OSError:
            self.notify.warning("Unable to invoke NSIS command.")

        nsifile.unlink()
        return output
示例#14
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
示例#15
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
class PackageTree:
    """ A class used internally to build a temporary package
    tree for inclusion into an installer. """

    def __init__(self, platform, hostDir, hostUrl):
        self.platform = platform
        self.hosts = {}
        self.packages = {}
        self.hostUrl = hostUrl
        self.hostDir = Filename(hostDir)
        self.hostDir.makeDir()
        self.http = HTTPClient.getGlobalPtr()

    def getHost(self, hostUrl):
        if hostUrl in self.hosts:
            return self.hosts[hostUrl]

        host = HostInfo(hostUrl, appRunner=appRunner, hostDir=self.hostDir, asMirror=False, perPlatform=False)
        if not host.hasContentsFile:
            if not host.readContentsFile():
                if not host.downloadContentsFile(self.http):
                    Installer.notify.error("couldn't read host %s" % host.hostUrl)
                    return None
        self.hosts[hostUrl] = host
        return host

    def installPackage(self, name, version, hostUrl=None):
        """ Installs the named package into the tree. """

        if hostUrl is None:
            hostUrl = self.hostUrl

        pkgIdent = (name, version)
        if pkgIdent in self.packages:
            return self.packages[pkgIdent]

        package = None
        # Always try the super host first, if any.
        if appRunner and appRunner.superMirrorUrl:
            superHost = self.getHost(appRunner.superMirrorUrl)
            if self.platform:
                package = superHost.getPackage(name, version, self.platform)
            if not package:
                package = superHost.getPackage(name, version)

        if not package:
            host = self.getHost(hostUrl)
            if self.platform:
                package = host.getPackage(name, version, self.platform)
            if not package:
                package = host.getPackage(name, version)

        if not package:
            Installer.notify.error("Package %s %s for %s not known on %s" % (name, version, self.platform, hostUrl))
            return

        package.installed = True  # Hack not to let it unnecessarily install itself
        if not package.downloadDescFile(self.http):
            Installer.notify.error("  -> %s failed for platform %s" % (package.packageName, package.platform))
            return
        if not package.downloadPackage(self.http):
            Installer.notify.error("  -> %s failed for platform %s" % (package.packageName, package.platform))
            return

        self.packages[pkgIdent] = package

        # Check for any dependencies.
        for rname, rversion, rhost in package.requires:
            self.installPackage(rname, rversion, rhost.hostUrl)

        return package
示例#17
0
        if failed:
            sys.exit(1)

    # Now build for the requested platforms.
    if currentPlatform:
        platform = PandaSystem.getPlatform()
        if platform.startswith("win"):
            i.build(outputDir, platform)
        else:
            i.build(outputDir, platform)
    elif len(platforms) == 0:
        i.buildAll(outputDir)
    else:
        for platform in platforms:
            output = Filename(outputDir, platform + "/")
            output.makeDir()
            i.build(output, platform)

    del i

elif deploy_mode == 'html':
    w, h = tokens.get("width", 640), tokens.get("height", 480)
    if "data" not in tokens:
        tokens["data"] = appFilename.getBasename()

    print "Creating %s.html..." % shortname
    html = open(Filename(outputDir, shortname + ".html").toOsSpecific(), "w")
    print >> html, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"
    print >> html, "<html xmlns=\"http://www.w3.org/1999/xhtml\">"
    print >> html, "  <head>"
    print >> html, "    <title>%s</title>" % fullname
示例#18
0
        if failed:
            sys.exit(1)

    # Now build for the requested platforms.
    if currentPlatform:
        platform = PandaSystem.getPlatform()
        if platform.startswith("win"):
            i.build(outputDir, platform)
        else:
            i.build(outputDir, platform)
    elif len(platforms) == 0:
        i.buildAll(outputDir)
    else:
        for platform in platforms:
            output = Filename(outputDir, platform + "/")
            output.makeDir()
            i.build(output, platform)

    del i

elif deploy_mode == "html":
    w, h = tokens.get("width", 640), tokens.get("height", 480)
    if "data" not in tokens:
        tokens["data"] = appFilename.getBasename()

    print "Creating %s.html..." % shortname
    html = open(Filename(outputDir, shortname + ".html").toOsSpecific(), "w")
    print >> html, '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
    print >> html, '<html xmlns="http://www.w3.org/1999/xhtml">'
    print >> html, "  <head>"
    print >> html, "    <title>%s</title>" % fullname
示例#19
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
    def buildNSIS(self, output, platform):
        # Check if we have makensis first
        makensis = None
        if sys.platform.startswith("win"):
            syspath = os.defpath.split(";") + os.environ["PATH"].split(";")
            for p in set(syspath):
                p1 = os.path.join(p, "makensis.exe")
                p2 = os.path.join(os.path.dirname(p), "nsis", "makensis.exe")
                if os.path.isfile(p1):
                    makensis = p1
                    break
                elif os.path.isfile(p2):
                    makensis = p2
                    break
            if not makensis:
                import pandac

                makensis = os.path.dirname(os.path.dirname(pandac.__file__))
                makensis = os.path.join(makensis, "nsis", "makensis.exe")
                if not os.path.isfile(makensis):
                    makensis = None
        else:
            for p in os.defpath.split(":") + os.environ["PATH"].split(":"):
                if os.path.isfile(os.path.join(p, "makensis")):
                    makensis = os.path.join(p, "makensis")

        if makensis == None:
            Installer.notify.warning("Makensis utility not found, no Windows installer will be built!")
            return None

        output = Filename(output)
        if output.isDirectory():
            output = Filename(output, "%s %s.exe" % (self.fullname, self.version))
        Installer.notify.info("Creating %s..." % output)
        output.makeAbsolute()
        extrafiles = self.standalone.getExtraFiles(platform)

        exefile = Filename(Filename.getTempDirectory(), self.shortname + ".exe")
        exefile.unlink()
        if self.includeRequires:
            extraTokens = {"host_dir": "."}
        else:
            extraTokens = {}
        self.standalone.build(exefile, platform, extraTokens)

        # Temporary directory to store the hostdir in
        hostDir = Filename(self.tempDir, platform + "/")
        if not hostDir.exists():
            hostDir.makeDir()
            self.installPackagesInto(hostDir, platform)

        nsifile = Filename(Filename.getTempDirectory(), self.shortname + ".nsi")
        nsifile.unlink()
        nsi = open(nsifile.toOsSpecific(), "w")

        # Some global info
        nsi.write('Name "%s"\n' % self.fullname)
        nsi.write('OutFile "%s"\n' % output.toOsSpecific())
        nsi.write('InstallDir "$PROGRAMFILES\\%s"\n' % self.fullname)
        nsi.write("SetCompress auto\n")
        nsi.write("SetCompressor lzma\n")
        nsi.write("ShowInstDetails nevershow\n")
        nsi.write("ShowUninstDetails nevershow\n")
        nsi.write('InstType "Typical"\n')

        # Tell Vista that we require admin rights
        nsi.write("RequestExecutionLevel admin\n")
        nsi.write("\n")
        nsi.write("Function launch\n")
        nsi.write('  ExecShell "open" "$INSTDIR\\%s.exe"\n' % self.shortname)
        nsi.write("FunctionEnd\n")
        nsi.write("\n")
        nsi.write('!include "MUI2.nsh"\n')
        nsi.write("!define MUI_ABORTWARNING\n")
        nsi.write("!define MUI_FINISHPAGE_RUN\n")
        nsi.write("!define MUI_FINISHPAGE_RUN_FUNCTION launch\n")
        nsi.write('!define MUI_FINISHPAGE_RUN_TEXT "Run %s"\n' % self.fullname)
        nsi.write("\n")
        nsi.write("Var StartMenuFolder\n")
        nsi.write("!insertmacro MUI_PAGE_WELCOME\n")
        if not self.licensefile.empty():
            abs = Filename(self.licensefile)
            abs.makeAbsolute()
            nsi.write('!insertmacro MUI_PAGE_LICENSE "%s"\n' % abs.toOsSpecific())
        nsi.write("!insertmacro MUI_PAGE_DIRECTORY\n")
        nsi.write("!insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder\n")
        nsi.write("!insertmacro MUI_PAGE_INSTFILES\n")
        nsi.write("!insertmacro MUI_PAGE_FINISH\n")
        nsi.write("!insertmacro MUI_UNPAGE_WELCOME\n")
        nsi.write("!insertmacro MUI_UNPAGE_CONFIRM\n")
        nsi.write("!insertmacro MUI_UNPAGE_INSTFILES\n")
        nsi.write("!insertmacro MUI_UNPAGE_FINISH\n")
        nsi.write('!insertmacro MUI_LANGUAGE "English"\n')

        # This section defines the installer.
        nsi.write('Section "" SecCore\n')
        nsi.write('  SetOutPath "$INSTDIR"\n')
        nsi.write('  File "%s"\n' % exefile.toOsSpecific())
        for f in extrafiles:
            nsi.write('  File "%s"\n' % f.toOsSpecific())
        curdir = ""
        for root, dirs, files in self.os_walk(hostDir.toOsSpecific()):
            for name in files:
                file = Filename.fromOsSpecific(os.path.join(root, name))
                file.makeAbsolute()
                file.makeRelativeTo(hostDir)
                outdir = file.getDirname().replace("/", "\\")
                if curdir != outdir:
                    nsi.write('  SetOutPath "$INSTDIR\\%s"\n' % outdir)
                    curdir = outdir
                nsi.write('  File "%s"\n' % os.path.join(root, name))
        nsi.write('  WriteUninstaller "$INSTDIR\\Uninstall.exe"\n')
        nsi.write("  ; Start menu items\n")
        nsi.write("  !insertmacro MUI_STARTMENU_WRITE_BEGIN Application\n")
        nsi.write('    CreateDirectory "$SMPROGRAMS\\$StartMenuFolder"\n')
        nsi.write(
            '    CreateShortCut "$SMPROGRAMS\\$StartMenuFolder\\%s.lnk" "$INSTDIR\\%s.exe"\n'
            % (self.fullname, self.shortname)
        )
        nsi.write('    CreateShortCut "$SMPROGRAMS\\$StartMenuFolder\\Uninstall.lnk" "$INSTDIR\\Uninstall.exe"\n')
        nsi.write("  !insertmacro MUI_STARTMENU_WRITE_END\n")
        nsi.write("SectionEnd\n")

        # This section defines the uninstaller.
        nsi.write("Section Uninstall\n")
        nsi.write('  Delete "$INSTDIR\\%s.exe"\n' % self.shortname)
        for f in extrafiles:
            nsi.write('  Delete "%s"\n' % f.getBasename())
        nsi.write('  Delete "$INSTDIR\\Uninstall.exe"\n')
        nsi.write('  RMDir /r "$INSTDIR"\n')
        nsi.write("  ; Start menu items\n")
        nsi.write("  !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuFolder\n")
        nsi.write('  Delete "$SMPROGRAMS\\$StartMenuFolder\\Uninstall.lnk"\n')
        nsi.write('  RMDir "$SMPROGRAMS\\$StartMenuFolder"\n')
        nsi.write("SectionEnd")
        nsi.close()

        cmd = [makensis]
        for o in ["V2"]:
            if sys.platform.startswith("win"):
                cmd.append("/" + o)
            else:
                cmd.append("-" + o)
        cmd.append(nsifile.toOsSpecific())
        print cmd
        try:
            retcode = subprocess.call(cmd, shell=False)
            if retcode != 0:
                self.notify.warning("Failure invoking NSIS command.")
        except OSError:
            self.notify.warning("Unable to invoke NSIS command.")

        nsifile.unlink()
        return output
class PackageTree:
    """ A class used internally to build a temporary package
    tree for inclusion into an installer. """
    def __init__(self, platform, hostDir, hostUrl):
        self.platform = platform
        self.hosts = {}
        self.packages = {}
        self.hostUrl = hostUrl
        self.hostDir = Filename(hostDir)
        self.hostDir.makeDir()
        self.http = HTTPClient.getGlobalPtr()

    def getHost(self, hostUrl):
        if hostUrl in self.hosts:
            return self.hosts[hostUrl]

        host = HostInfo(hostUrl,
                        appRunner=appRunner,
                        hostDir=self.hostDir,
                        asMirror=False,
                        perPlatform=False)
        if not host.hasContentsFile:
            if not host.readContentsFile():
                if not host.downloadContentsFile(self.http):
                    Installer.notify.error("couldn't read host %s" %
                                           host.hostUrl)
                    return None
        self.hosts[hostUrl] = host
        return host

    def installPackage(self, name, version, hostUrl=None):
        """ Installs the named package into the tree. """

        if hostUrl is None:
            hostUrl = self.hostUrl

        pkgIdent = (name, version)
        if pkgIdent in self.packages:
            return self.packages[pkgIdent]

        package = None
        # Always try the super host first, if any.
        if appRunner and appRunner.superMirrorUrl:
            superHost = self.getHost(appRunner.superMirrorUrl)
            if self.platform:
                package = superHost.getPackage(name, version, self.platform)
            if not package:
                package = superHost.getPackage(name, version)

        if not package:
            host = self.getHost(hostUrl)
            if self.platform:
                package = host.getPackage(name, version, self.platform)
            if not package:
                package = host.getPackage(name, version)

        if not package:
            Installer.notify.error("Package %s %s for %s not known on %s" %
                                   (name, version, self.platform, hostUrl))
            return

        package.installed = True  # Hack not to let it unnecessarily install itself
        if not package.downloadDescFile(self.http):
            Installer.notify.error("  -> %s failed for platform %s" %
                                   (package.packageName, package.platform))
            return
        if not package.downloadPackage(self.http):
            Installer.notify.error("  -> %s failed for platform %s" %
                                   (package.packageName, package.platform))
            return

        self.packages[pkgIdent] = package

        # Check for any dependencies.
        for rname, rversion, rhost in package.requires:
            self.installPackage(rname, rversion, rhost.hostUrl)

        return package