diff --git a/direct/src/showutil/FreezeTool.py b/direct/src/showutil/FreezeTool.py index 48edf2e1c0..c7142b3e82 100644 --- a/direct/src/showutil/FreezeTool.py +++ b/direct/src/showutil/FreezeTool.py @@ -422,7 +422,7 @@ class Freezer: constructor, but it may be called at any point during processing. """ - for key, value in freezer.modules: + for key, value in freezer.modules.items(): self.previousModules[key] = value self.modules[key] = value @@ -686,9 +686,26 @@ class Freezer: def mangleName(self, moduleName): return 'M_' + moduleName.replace('.', '__').replace('-', '_') - def __getModuleDefs(self): - # Collect a list of all of the modules we will be explicitly - # referencing. + def getAllModuleNames(self): + """ Return a list of all module names that have been included + or forbidden, either in this current pass or in a previous + pass. Module names that have been excluded are not included + in this list. """ + + moduleNames = [] + + for newName, mdef in self.modules.items(): + if mdef.token != self.MTExclude: + moduleNames.append(newName) + + moduleNames.sort() + return moduleNames + + def getModuleDefs(self): + """ Return a list of all of the modules we will be explicitly + or implicitly including. The return value is actually a list + of tuples: (moduleName, moduleDef).""" + moduleDefs = [] for newName, mdef in self.modules.items(): @@ -831,7 +848,7 @@ class Freezer: python code into the indicated Multifile. """ moduleDirs = {} - for moduleName, mdef in self.__getModuleDefs(): + for moduleName, mdef in self.getModuleDefs(): if mdef.token != self.MTForbid: self.__addPythonFile(multifile, moduleDirs, moduleName, mdef) @@ -874,7 +891,7 @@ class Freezer: moduleDefs = [] moduleList = [] - for moduleName, mdef in self.__getModuleDefs(): + for moduleName, mdef in self.getModuleDefs(): token = mdef.token origName = mdef.moduleName if token == self.MTForbid: diff --git a/direct/src/showutil/Packager.py b/direct/src/showutil/Packager.py index ae7e900373..e33d0b5b82 100644 --- a/direct/src/showutil/Packager.py +++ b/direct/src/showutil/Packager.py @@ -29,6 +29,7 @@ class Packager: class PackFile: def __init__(self, filename, newName = None, deleteTemp = False): + assert isinstance(filename, Filename) self.filename = filename self.newName = newName self.deleteTemp = deleteTemp @@ -37,37 +38,66 @@ class Packager: def __init__(self, packageName, packager): self.packageName = packageName self.packager = packager - self.version = 'dev' + self.version = None + self.platform = None + self.p3dApplication = False self.files = [] self.compressionLevel = 0 self.importedMapsDir = 'imported_maps' + # This is the set of files and modules, already included + # by required packages, that we can skip. + self.skipFilenames = {} + self.skipModules = {} + # This records the current list of modules we have added so # far. self.freezer = FreezeTool.Freezer() + # Set this true to parse and build up the internal + # filelist, but not generate any output. + self.dryRun = False + def close(self): """ Writes out the contents of the current package. """ packageFilename = self.packageName - packageFilename += '_' + self.version - packageFilename += '.mf' + if self.platform: + packageFilename += '_' + self.platform + if self.version: + packageFilename += '_' + self.version + + if self.p3dApplication: + packageFilename += '.p3d' + else: + packageFilename += '.mf' try: os.unlink(packageFilename) except OSError: pass - - self.multifile = Multifile() - self.multifile.openReadWrite(packageFilename) + + if self.dryRun: + self.multifile = None + else: + self.multifile = Multifile() + self.multifile.openReadWrite(packageFilename) + + # Exclude modules already imported in a required package. + for moduleName in self.skipModules.keys(): + self.freezer.excludeModule(moduleName) # Build up a cross-reference of files we've already # discovered. self.sourceFilenames = {} self.targetFilenames = {} + processFiles = [] for file in self.files: if not file.newName: file.newName = file.filename + if file.newName in self.skipFilenames: + # Skip this file. + continue # Convert the source filename to an unambiguous # filename for searching. @@ -76,12 +106,13 @@ class Packager: self.sourceFilenames[filename] = file self.targetFilenames[file.newName] = file + processFiles.append(file) - for file in self.files: + for file in processFiles: ext = file.filename.getExtension() if ext == 'py': self.addPyFile(file) - else: + elif not self.dryRun: if ext == 'pz': # Strip off an implicit .pz extension. filename = Filename(file.filename) @@ -100,22 +131,31 @@ class Packager: self.addBamFile(file) elif ext in self.packager.imageExtensions: self.addTexture(file) + elif ext in self.packager.uncompressibleExtensions: + # An uncompressible file. + self.multifile.addSubfile(file.newName, file.filename, 0) else: - # An ordinary file. + # Any other file. self.multifile.addSubfile(file.newName, file.filename, self.compressionLevel) # Pick up any unfrozen Python files. self.freezer.done() - self.freezer.addToMultifile(self.multifile) - self.multifile.repack() - self.multifile.close() + # Add known module names. + self.moduleNames = {} + for moduleName in self.freezer.getAllModuleNames(): + self.moduleNames[moduleName] = True + + if not self.dryRun: + self.freezer.addToMultifile(self.multifile) + self.multifile.repack() + self.multifile.close() # Now that all the files have been packed, we can delete # the temporary files. for file in self.files: if file.deleteTemp: - os.unlink(file.filename) + file.filename.unlink() def addPyFile(self, file): """ Adds the indicated python file, identified by filename @@ -319,15 +359,21 @@ class Packager: self.sfxManagerList = None self.musicManager = None + # This is filled in during readPackageDef(). + self.packageList = None + + # A table of all known packages by name. + self.packages = {} + + self.dryRun = False + + def setup(self): """ Call this method to initialize the class after filling in some of the values in the constructor. """ self.knownExtensions = self.imageExtensions + self.modelExtensions + self.textExtensions + self.binaryExtensions + self.uncompressibleExtensions - # We need a stack of packages for managing begin_package - # .. end_package. - self.packageStack = [] self.currentPackage = None # The persist dir is the directory in which the results from @@ -353,10 +399,13 @@ class Packager: # created there os.chdir(self.persistDir.toOsSpecific()) - def readPackageDef(self, packageDef): - """ Reads the lines in packageDef and dispatches to the - appropriate handler method for each line. """ + """ Reads the lines in the .pdef file named by packageDef and + dispatches to the appropriate handler method for each + line. Returns the list of package files.""" + + assert self.packageList is None + self.packageList = [] self.notify.info('Reading %s' % (packageDef)) file = open(packageDef.toOsSpecific()) @@ -418,6 +467,11 @@ class Packager: inst.args = (inst.args[0] + ' on line %s of %s' % (lineNum[0], packageDef),) raise + packageList = self.packageList + self.packageList = None + + return packageList + def parse_setenv(self, lineList): """ setenv variable value @@ -430,7 +484,7 @@ class Packager: value = ExecutionEnvironment.expandString(value) ExecutionEnvironment.setEnvironmentVariable(variable, value) - + def parse_begin_package(self, lineList): """ begin_package packageName @@ -455,6 +509,23 @@ class Packager: self.endPackage(packageName) + def parse_require(self, lineList): + """ + require packageName + """ + + try: + command, packageName = lineList + except ValueError: + raise ArgumentError + + package = self.findPackage(packageName) + if not package: + message = "Unknown package %s" % (packageName) + raise PackagerError, message + + self.require(package) + def parse_module(self, lineList): """ module moduleName [newName] @@ -533,12 +604,13 @@ class Packager: """ Begins a new package specification. packageName is the basename of the package. Follow this with a number of calls to file() etc., and close the package with endPackage(). """ - - package = self.Package(packageName, self) + if self.currentPackage: - package.freezer.excludeFrom(self.currentPackage.freezer) - - self.packageStack.append(package) + raise PackagerError, 'unmatched end_package %s' % (self.currentPackage.packageName) + + package = self.Package(packageName, self) + package.dryRun = self.dryRun + self.currentPackage = package def endPackage(self, packageName): @@ -555,12 +627,36 @@ class Packager: package = self.currentPackage package.close() - del self.packageStack[-1] - if self.packageStack: - self.currentPackage = self.packageStack[-1] - self.currentPackage.freezer.excludeFrom(package.freezer) - else: - self.currentPackage = None + self.packageList.append(package) + self.packages[package.packageName] = package + self.currentPackage = None + + def findPackage(self, packageName, searchUrl = None): + """ Searches for the named package from a previous publish + operation, either at the indicated URL or along the default + search path. + + Returns the Package object, or None if the package cannot be + located. """ + + # Is it a package we already have resident? + package = self.packages.get(packageName, None) + if package: + return package + + return None + + def require(self, package): + """ Indicates a dependency on the indicated package. + + Attempts to install this package will implicitly install the + named package also. Files already included in the named + package will be omitted from this one. """ + + for filename in package.targetFilenames.keys(): + self.currentPackage.skipFilenames[filename] = True + for moduleName in package.moduleNames.keys(): + self.currentPackage.skipModules[moduleName] = True def module(self, moduleName, newName = None): """ Adds the indicated Python module to the current package. """ @@ -584,14 +680,15 @@ class Packager: freezer = package.freezer freezer.done() - dirname = '' - basename = filename - if '/' in basename: - dirname, basename = filename.rsplit('/', 1) - dirname += '/' - basename = freezer.generateCode(basename, compileToExe = compileToExe) + if not package.dryRun: + dirname = '' + basename = filename + if '/' in basename: + dirname, basename = filename.rsplit('/', 1) + dirname += '/' + basename = freezer.generateCode(basename, compileToExe = compileToExe) - package.files.append(self.PackFile(basename, newName = dirname + basename, deleteTemp = True)) + package.files.append(self.PackFile(Filename(basename), newName = dirname + basename, deleteTemp = True)) # Reset the freezer for more Python files. freezer.reset()