guarantee proper ordering of download phases

This commit is contained in:
David Rose 2009-12-19 03:38:03 +00:00
parent 74264f850f
commit 6eba1cf08a
2 changed files with 53 additions and 56 deletions

View File

@ -39,6 +39,7 @@ from direct.stdpy import file
from direct.task.TaskManagerGlobal import taskMgr from direct.task.TaskManagerGlobal import taskMgr
from direct.showbase.MessengerGlobal import messenger from direct.showbase.MessengerGlobal import messenger
from direct.showbase import AppRunnerGlobal from direct.showbase import AppRunnerGlobal
from direct.directnotify.DirectNotifyGlobal import directNotify
from direct.p3d.HostInfo import HostInfo from direct.p3d.HostInfo import HostInfo
# These imports are read by the C++ wrapper in p3dPythonRun.cxx. # These imports are read by the C++ wrapper in p3dPythonRun.cxx.
@ -63,6 +64,8 @@ class AppRunner(DirectObject):
It does not usually exist while running Python directly, but you It does not usually exist while running Python directly, but you
can use dummyAppRunner() to create one at startup for testing or can use dummyAppRunner() to create one at startup for testing or
development purposes. """ development purposes. """
notify = directNotify.newCategory("AppRunner")
def __init__(self): def __init__(self):
DirectObject.__init__(self) DirectObject.__init__(self)
@ -171,7 +174,7 @@ class AppRunner(DirectObject):
if args[1] == 'notify': if args[1] == 'notify':
# Quietly ignore notifies. # Quietly ignore notifies.
return return
print "Ignoring request: %s" % (args,) self.notify.info("Ignoring request: %s" % (args,))
self.requestFunc = defaultRequestFunc self.requestFunc = defaultRequestFunc
# This will be filled in with the default WindowProperties for # This will be filled in with the default WindowProperties for
@ -245,8 +248,8 @@ class AppRunner(DirectObject):
# All right, get the package info now. # All right, get the package info now.
package = host.getPackage(packageName, version) package = host.getPackage(packageName, version)
if not package: if not package:
print "Package %s %s not known on %s" % ( self.notify.warning("Package %s %s not known on %s" % (
packageName, version, hostUrl) packageName, version, hostUrl))
return False return False
return self.__rInstallPackage(package, []) return self.__rInstallPackage(package, [])
@ -266,7 +269,7 @@ class AppRunner(DirectObject):
if host.downloadContentsFile(self.http): if host.downloadContentsFile(self.http):
p2 = host.getPackage(packageName, version) p2 = host.getPackage(packageName, version)
if not p2: if not p2:
print "Couldn't find %s %s on %s" % (packageName, version, host.hostUrl) self.notify.warning("Couldn't find %s %s on %s" % (packageName, version, host.hostUrl))
else: else:
if p2 not in nested: if p2 not in nested:
self.__rInstallPackage(p2, nested) self.__rInstallPackage(p2, nested)
@ -279,8 +282,8 @@ class AppRunner(DirectObject):
if not package.installPackage(self): if not package.installPackage(self):
return False return False
print "Package %s %s installed." % ( self.notify.info("Package %s %s installed." % (
package.packageName, package.packageVersion) package.packageName, package.packageVersion))
return True return True
def getHostWithAlt(self, hostUrl): def getHostWithAlt(self, hostUrl):
@ -353,13 +356,13 @@ class AppRunner(DirectObject):
if self.superMirrorUrl: if self.superMirrorUrl:
# Use the "super mirror" first. # Use the "super mirror" first.
url = PandaModules.URLSpec(self.superMirrorUrl + fileSpec.filename) url = PandaModules.URLSpec(self.superMirrorUrl + fileSpec.filename)
print "Freshening %s" % (url) self.notify.info("Freshening %s" % (url))
doc = self.http.getDocument(url) doc = self.http.getDocument(url)
if not doc or not doc.isValid(): if not doc or not doc.isValid():
# Failing the super mirror, contact the actual host. # Failing the super mirror, contact the actual host.
url = PandaModules.URLSpec(host.hostUrlPrefix + fileSpec.filename) url = PandaModules.URLSpec(host.hostUrlPrefix + fileSpec.filename)
print "Freshening %s" % (url) self.notify.info("Freshening %s" % (url))
doc = self.http.getDocument(url) doc = self.http.getDocument(url)
if not doc.isValid(): if not doc.isValid():
return False return False
@ -379,7 +382,7 @@ class AppRunner(DirectObject):
if not fileSpec.fullVerify(pathname = localPathname): if not fileSpec.fullVerify(pathname = localPathname):
# No good after download. # No good after download.
print "%s is still no good after downloading." % (url) self.notify.info("%s is still no good after downloading." % (url))
return False return False
return True return True

View File

@ -4,6 +4,7 @@ from direct.showbase.MessengerGlobal import messenger
from direct.task.TaskManagerGlobal import taskMgr from direct.task.TaskManagerGlobal import taskMgr
from direct.p3d.PackageInfo import PackageInfo from direct.p3d.PackageInfo import PackageInfo
from pandac.PandaModules import TPLow from pandac.PandaModules import TPLow
from direct.directnotify.DirectNotifyGlobal import directNotify
class PackageInstaller(DirectObject): class PackageInstaller(DirectObject):
@ -27,6 +28,8 @@ class PackageInstaller(DirectObject):
.. packageFinished() may therefore overlap. .. packageFinished() may therefore overlap.
""" """
notify = directNotify.newCategory("PackageInstaller")
globalLock = Lock() globalLock = Lock()
nextUniqueId = 1 nextUniqueId = 1
@ -101,8 +104,8 @@ class PackageInstaller(DirectObject):
# All right, get the package info now. # All right, get the package info now.
package = self.host.getPackage(self.packageName, self.version) package = self.host.getPackage(self.packageName, self.version)
if not package: if not package:
print "Package %s %s not known on %s" % ( self.notify.warning("Package %s %s not known on %s" % (
self.packageName, self.version, self.host.hostUrl) self.packageName, self.version, self.host.hostUrl))
return False return False
self.package = package self.package = package
@ -126,8 +129,8 @@ class PackageInstaller(DirectObject):
# All right, get the package info now. # All right, get the package info now.
package = self.host.getPackage(self.packageName, self.version) package = self.host.getPackage(self.packageName, self.version)
if not package: if not package:
print "Package %s %s not known on %s" % ( self.notify.warning("Package %s %s not known on %s" % (
self.packageName, self.version, self.host.hostUrl) self.packageName, self.version, self.host.hostUrl))
return False return False
self.package = package self.package = package
@ -251,30 +254,15 @@ class PackageInstaller(DirectObject):
return return
self.packages.append(pp) self.packages.append(pp)
if not pp.checkDescFile():
# Still need to download the desc file.
self.needsDescFile.append(pp)
if not self.descFileTask:
self.descFileTask = taskMgr.add(
self.__getDescFileTask, 'getDescFile',
taskChain = self.taskChain)
else: # We always add the package to needsDescFile, even if we
# The desc file is ready, which means so are the requirements. # already have its desc file; this guarantees that packages
for packageName, version, host in pp.package.requires: # are downloaded in the order they are added.
pp2 = self.PendingPackage(packageName, version, host) self.needsDescFile.append(pp)
self.__internalAddPackage(pp2) if not self.descFileTask:
self.descFileTask = taskMgr.add(
# Now that we've added the required packages, add the self.__getDescFileTask, 'getDescFile',
# package itself. taskChain = self.taskChain)
if not pp.package.hasPackage:
# The desc file is good, but the package itself needs
# to be downloaded.
self.needsDownload.append(pp)
else:
# The package is already fully downloaded.
self.earlyDone.append(pp)
def donePackages(self): def donePackages(self):
""" After calling addPackage() for each package to be """ After calling addPackage() for each package to be
@ -314,27 +302,31 @@ class PackageInstaller(DirectObject):
is called; at the time of this callback, the total download is called; at the time of this callback, the total download
size is known, and we can sensibly report progress through the size is known, and we can sensibly report progress through the
whole. """ whole. """
pass
self.notify.info("downloadStarted")
def packageStarted(self, package): def packageStarted(self, package):
""" This callback is made for each package between """ This callback is made for each package between
downloadStarted() and downloadFinished() to indicate the start downloadStarted() and downloadFinished() to indicate the start
of a new package. """ of a new package. """
pass
self.notify.debug("packageStarted: %s" % (package.packageName))
def packageProgress(self, package, progress): def packageProgress(self, package, progress):
""" This callback is made repeatedly between packageStarted() """ This callback is made repeatedly between packageStarted()
and packageFinished() to update the current progress on the and packageFinished() to update the current progress on the
indicated package only. The progress value ranges from 0 indicated package only. The progress value ranges from 0
(beginning) to 1 (complete). """ (beginning) to 1 (complete). """
pass
self.notify.debug("packageProgress: %s %s" % (package.packageName, progress))
def downloadProgress(self, overallProgress): def downloadProgress(self, overallProgress):
""" This callback is made repeatedly between downloadStarted() """ This callback is made repeatedly between downloadStarted()
and downloadFinished() to update the current progress through and downloadFinished() to update the current progress through
all packages. The progress value ranges from 0 (beginning) to all packages. The progress value ranges from 0 (beginning) to
1 (complete). """ 1 (complete). """
pass
self.notify.debug("downloadProgress: %s" % (overallProgress))
def packageFinished(self, package, success): def packageFinished(self, package, success):
""" This callback is made for each package between """ This callback is made for each package between
@ -346,7 +338,8 @@ class PackageInstaller(DirectObject):
already downloaded), this callback will be made immediately, already downloaded), this callback will be made immediately,
*without* a corresponding call to packageStarted(), and may *without* a corresponding call to packageStarted(), and may
even be made before downloadStarted(). """ even be made before downloadStarted(). """
pass
self.notify.info("packageFinished: %s %s" % (package.packageName, success))
def downloadFinished(self, success): def downloadFinished(self, success):
""" This callback is made when all of the packages have been """ This callback is made when all of the packages have been
@ -356,7 +349,8 @@ class PackageInstaller(DirectObject):
If there were no packages that required downloading, this If there were no packages that required downloading, this
callback will be made immediately, *without* a corresponding callback will be made immediately, *without* a corresponding
call to downloadStarted(). """ call to downloadStarted(). """
pass
self.notify.info("downloadFinished: %s" % (success))
def __prepareToStart(self): def __prepareToStart(self):
""" This is called internally when transitioning from S_ready """ This is called internally when transitioning from S_ready
@ -401,14 +395,14 @@ class PackageInstaller(DirectObject):
def __packageStarted(self, pp): def __packageStarted(self, pp):
""" This method is called when a single package is beginning """ This method is called when a single package is beginning
to download. """ to download. """
print "Downloading package %s" % (pp.packageName)
self.__callDownloadStarted() self.__callDownloadStarted()
self.__callPackageStarted(pp) self.__callPackageStarted(pp)
def __packageDone(self, pp): def __packageDone(self, pp):
""" This method is called when a single package has been """ This method is called when a single package has been
downloaded and installed, or has failed. """ downloaded and installed, or has failed. """
print "Downloaded %s: %s" % (pp.packageName, pp.success)
self.__callPackageFinished(pp, pp.success) self.__callPackageFinished(pp, pp.success)
pp.notified = True pp.notified = True
@ -507,16 +501,15 @@ class PackageInstaller(DirectObject):
self.packageLock.release() self.packageLock.release()
# Now serve this one package. # Now serve this one package.
if not pp.getDescFile(self.appRunner.http): if not pp.checkDescFile():
self.__donePackage(pp, False) if not pp.getDescFile(self.appRunner.http):
return task.cont self.__donePackage(pp, False)
return task.cont
if pp.package.hasPackage: # This package is now ready to be downloaded. We always add
# This package is already downloaded. # it to needsDownload, even if it's already downloaded, to
self.__donePackage(pp, True) # guarantee ordering of packages.
return task.cont
# This package is now ready to be downloaded.
self.packageLock.acquire() self.packageLock.acquire()
try: try:
# Also add any packages required by this one. # Also add any packages required by this one.
@ -552,9 +545,10 @@ class PackageInstaller(DirectObject):
messenger.send('PackageInstaller-%s-packageStarted' % self.uniqueId, messenger.send('PackageInstaller-%s-packageStarted' % self.uniqueId,
[pp], taskChain = 'default') [pp], taskChain = 'default')
if not pp.package.downloadPackage(self.appRunner.http): if not pp.package.hasPackage:
self.__donePackage(pp, False) if not pp.package.downloadPackage(self.appRunner.http):
return task.cont self.__donePackage(pp, False)
return task.cont
# Successfully downloaded and installed. # Successfully downloaded and installed.
self.__donePackage(pp, True) self.__donePackage(pp, True)