Browse Source

exclude, requires

David Rose 16 years ago
parent
commit
5b84a46753
2 changed files with 158 additions and 44 deletions
  1. 23 6
      direct/src/showutil/FreezeTool.py
  2. 135 38
      direct/src/showutil/Packager.py

+ 23 - 6
direct/src/showutil/FreezeTool.py

@@ -422,7 +422,7 @@ class Freezer:
         constructor, but it may be called at any point during
         constructor, but it may be called at any point during
         processing. """
         processing. """
 
 
-        for key, value in freezer.modules:
+        for key, value in freezer.modules.items():
             self.previousModules[key] = value
             self.previousModules[key] = value
             self.modules[key] = value
             self.modules[key] = value
 
 
@@ -686,9 +686,26 @@ class Freezer:
     def mangleName(self, moduleName):
     def mangleName(self, moduleName):
         return 'M_' + moduleName.replace('.', '__').replace('-', '_')
         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 = []
         moduleDefs = []
 
 
         for newName, mdef in self.modules.items():
         for newName, mdef in self.modules.items():
@@ -831,7 +848,7 @@ class Freezer:
         python code into the indicated Multifile. """
         python code into the indicated Multifile. """
 
 
         moduleDirs = {}
         moduleDirs = {}
-        for moduleName, mdef in self.__getModuleDefs():
+        for moduleName, mdef in self.getModuleDefs():
             if mdef.token != self.MTForbid:
             if mdef.token != self.MTForbid:
                 self.__addPythonFile(multifile, moduleDirs, moduleName, mdef)
                 self.__addPythonFile(multifile, moduleDirs, moduleName, mdef)
     
     
@@ -874,7 +891,7 @@ class Freezer:
         moduleDefs = []
         moduleDefs = []
         moduleList = []
         moduleList = []
         
         
-        for moduleName, mdef in self.__getModuleDefs():
+        for moduleName, mdef in self.getModuleDefs():
             token = mdef.token
             token = mdef.token
             origName = mdef.moduleName
             origName = mdef.moduleName
             if token == self.MTForbid:
             if token == self.MTForbid:

+ 135 - 38
direct/src/showutil/Packager.py

@@ -29,6 +29,7 @@ class Packager:
 
 
     class PackFile:
     class PackFile:
         def __init__(self, filename, newName = None, deleteTemp = False):
         def __init__(self, filename, newName = None, deleteTemp = False):
+            assert isinstance(filename, Filename)
             self.filename = filename
             self.filename = filename
             self.newName = newName
             self.newName = newName
             self.deleteTemp = deleteTemp
             self.deleteTemp = deleteTemp
@@ -37,37 +38,66 @@ class Packager:
         def __init__(self, packageName, packager):
         def __init__(self, packageName, packager):
             self.packageName = packageName
             self.packageName = packageName
             self.packager = packager
             self.packager = packager
-            self.version = 'dev'
+            self.version = None
+            self.platform = None
+            self.p3dApplication = False
             self.files = []
             self.files = []
             self.compressionLevel = 0
             self.compressionLevel = 0
             self.importedMapsDir = 'imported_maps'
             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
             # This records the current list of modules we have added so
             # far.
             # far.
             self.freezer = FreezeTool.Freezer()
             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):
         def close(self):
             """ Writes out the contents of the current package. """
             """ Writes out the contents of the current package. """
 
 
             packageFilename = self.packageName
             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:
             try:
                 os.unlink(packageFilename)
                 os.unlink(packageFilename)
             except OSError:
             except OSError:
                 pass
                 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
             # Build up a cross-reference of files we've already
             # discovered.
             # discovered.
             self.sourceFilenames = {}
             self.sourceFilenames = {}
             self.targetFilenames = {}
             self.targetFilenames = {}
+            processFiles = []
             for file in self.files:
             for file in self.files:
                 if not file.newName:
                 if not file.newName:
                     file.newName = file.filename
                     file.newName = file.filename
+                if file.newName in self.skipFilenames:
+                    # Skip this file.
+                    continue
 
 
                 # Convert the source filename to an unambiguous
                 # Convert the source filename to an unambiguous
                 # filename for searching.
                 # filename for searching.
@@ -76,12 +106,13 @@ class Packager:
                 
                 
                 self.sourceFilenames[filename] = file
                 self.sourceFilenames[filename] = file
                 self.targetFilenames[file.newName] = file
                 self.targetFilenames[file.newName] = file
+                processFiles.append(file)
 
 
-            for file in self.files:
+            for file in processFiles:
                 ext = file.filename.getExtension()
                 ext = file.filename.getExtension()
                 if ext == 'py':
                 if ext == 'py':
                     self.addPyFile(file)
                     self.addPyFile(file)
-                else:
+                elif not self.dryRun:
                     if ext == 'pz':
                     if ext == 'pz':
                         # Strip off an implicit .pz extension.
                         # Strip off an implicit .pz extension.
                         filename = Filename(file.filename)
                         filename = Filename(file.filename)
@@ -100,22 +131,31 @@ class Packager:
                         self.addBamFile(file)
                         self.addBamFile(file)
                     elif ext in self.packager.imageExtensions:
                     elif ext in self.packager.imageExtensions:
                         self.addTexture(file)
                         self.addTexture(file)
+                    elif ext in self.packager.uncompressibleExtensions:
+                        # An uncompressible file.
+                        self.multifile.addSubfile(file.newName, file.filename, 0)
                     else:
                     else:
-                        # An ordinary file.
+                        # Any other file.
                         self.multifile.addSubfile(file.newName, file.filename, self.compressionLevel)
                         self.multifile.addSubfile(file.newName, file.filename, self.compressionLevel)
 
 
             # Pick up any unfrozen Python files.
             # Pick up any unfrozen Python files.
             self.freezer.done()
             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
             # Now that all the files have been packed, we can delete
             # the temporary files.
             # the temporary files.
             for file in self.files:
             for file in self.files:
                 if file.deleteTemp:
                 if file.deleteTemp:
-                    os.unlink(file.filename)
+                    file.filename.unlink()
 
 
         def addPyFile(self, file):
         def addPyFile(self, file):
             """ Adds the indicated python file, identified by filename
             """ Adds the indicated python file, identified by filename
@@ -319,15 +359,21 @@ class Packager:
         self.sfxManagerList = None
         self.sfxManagerList = None
         self.musicManager = 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):
     def setup(self):
         """ Call this method to initialize the class after filling in
         """ Call this method to initialize the class after filling in
         some of the values in the constructor. """
         some of the values in the constructor. """
 
 
         self.knownExtensions = self.imageExtensions + self.modelExtensions + self.textExtensions + self.binaryExtensions + self.uncompressibleExtensions
         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
         self.currentPackage = None
 
 
         # The persist dir is the directory in which the results from
         # The persist dir is the directory in which the results from
@@ -353,10 +399,13 @@ class Packager:
         # created there
         # created there
         os.chdir(self.persistDir.toOsSpecific())
         os.chdir(self.persistDir.toOsSpecific())
 
 
-
     def readPackageDef(self, packageDef):
     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))
         self.notify.info('Reading %s' % (packageDef))
         file = open(packageDef.toOsSpecific())
         file = open(packageDef.toOsSpecific())
@@ -418,6 +467,11 @@ class Packager:
             inst.args = (inst.args[0] + ' on line %s of %s' % (lineNum[0], packageDef),)
             inst.args = (inst.args[0] + ' on line %s of %s' % (lineNum[0], packageDef),)
             raise
             raise
 
 
+        packageList = self.packageList
+        self.packageList = None
+
+        return packageList
+
     def parse_setenv(self, lineList):
     def parse_setenv(self, lineList):
         """
         """
         setenv variable value
         setenv variable value
@@ -430,7 +484,7 @@ class Packager:
 
 
         value = ExecutionEnvironment.expandString(value)
         value = ExecutionEnvironment.expandString(value)
         ExecutionEnvironment.setEnvironmentVariable(variable, value)
         ExecutionEnvironment.setEnvironmentVariable(variable, value)
-            
+
     def parse_begin_package(self, lineList):
     def parse_begin_package(self, lineList):
         """
         """
         begin_package packageName
         begin_package packageName
@@ -455,6 +509,23 @@ class Packager:
 
 
         self.endPackage(packageName)
         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):
     def parse_module(self, lineList):
         """
         """
         module moduleName [newName]
         module moduleName [newName]
@@ -533,12 +604,13 @@ class Packager:
         """ Begins a new package specification.  packageName is the
         """ Begins a new package specification.  packageName is the
         basename of the package.  Follow this with a number of calls
         basename of the package.  Follow this with a number of calls
         to file() etc., and close the package with endPackage(). """
         to file() etc., and close the package with endPackage(). """
-        
-        package = self.Package(packageName, self)
+
         if self.currentPackage:
         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
         self.currentPackage = package
 
 
     def endPackage(self, packageName):
     def endPackage(self, packageName):
@@ -555,12 +627,36 @@ class Packager:
         package = self.currentPackage
         package = self.currentPackage
         package.close()
         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):
     def module(self, moduleName, newName = None):
         """ Adds the indicated Python module to the current package. """
         """ Adds the indicated Python module to the current package. """
@@ -584,14 +680,15 @@ class Packager:
         freezer = package.freezer
         freezer = package.freezer
         freezer.done()
         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.
         # Reset the freezer for more Python files.
         freezer.reset()
         freezer.reset()