Forráskód Böngészése

contents seq, package seq

David Rose 15 éve
szülő
commit
547b3abea9

+ 25 - 1
direct/src/p3d/PackageMerger.py

@@ -1,4 +1,5 @@
 from direct.p3d.FileSpec import FileSpec
+from direct.p3d.SeqValue import SeqValue
 from pandac.PandaModules import *
 import copy
 import shutil
@@ -8,7 +9,7 @@ class PackageMergerError(StandardError):
     pass
 
 class PackageMerger:
-    """ This class will combine two or more separately-build stage
+    """ This class will combine two or more separately-built stage
     directories, the output of Packager.py or the ppackage tool, into
     a single output directory.  It assumes that the clocks on all
     hosts are in sync, so that the file across all builds with the
@@ -41,6 +42,9 @@ class PackageMerger:
             self.descFile = FileSpec()
             self.descFile.loadXml(xpackage)
 
+            self.packageSeq = SeqValue()
+            self.packageSeq.loadXml(xpackage)
+
             self.importDescFile = None
             ximport = xpackage.FirstChildElement('import')
             if ximport:
@@ -59,6 +63,7 @@ class PackageMerger:
                 xpackage.SetAttribute('solo', '1')
 
             self.descFile.storeXml(xpackage)
+            self.packageSeq.storeXml(xpackage)
 
             if self.importDescFile:
                 ximport = TiXmlElement('import')
@@ -72,6 +77,8 @@ class PackageMerger:
         self.installDir = installDir
         self.xhost = None
         self.contents = {}
+        self.maxAge = None
+        self.contentsSeq = SeqValue()
 
         # We allow the first one to fail quietly.
         self.__readContentsFile(self.installDir)
@@ -89,6 +96,18 @@ class PackageMerger:
 
         xcontents = doc.FirstChildElement('contents')
         if xcontents:
+            maxAge = xcontents.Attribute('max_age')
+            if maxAge:
+                maxAge = int(maxAge)
+                if self.maxAge is None:
+                    self.maxAge = maxAge
+                else:
+                    self.maxAge = min(self.maxAge, maxAge)
+
+            contentsSeq = SeqValue()
+            if contentsSeq.loadXml(xcontents):
+                self.contentsSeq = max(self.contentsSeq, contentsSeq)
+
             xhost = xcontents.FirstChildElement('host')
             if xhost:
                 self.xhost = xhost.Clone()
@@ -119,6 +138,10 @@ class PackageMerger:
         if self.xhost:
             xcontents.InsertEndChild(self.xhost)
 
+        if self.maxAge is not None:
+            xcontents.SetAttribute('max_age', str(self.maxAge))
+        self.contentsSeq.storeXml(xcontents)
+
         contents = self.contents.items()
         contents.sort()
         for key, pe in contents:
@@ -203,5 +226,6 @@ class PackageMerger:
                 # Here's a new subdirectory we have to copy in.
                 self.__copySubdirectory(pe)
 
+        self.contentsSeq += 1
         self.__writeContentsFile()
         

+ 51 - 1
direct/src/p3d/Packager.py

@@ -13,6 +13,7 @@ import types
 import getpass
 import platform
 from direct.p3d.FileSpec import FileSpec
+from direct.p3d.SeqValue import SeqValue
 from direct.showbase import Loader
 from direct.showbase import AppRunnerGlobal
 from direct.showutil import FreezeTool
@@ -165,7 +166,7 @@ class Packager:
         file. """
         
         def __init__(self):
-            pass
+            self.packageSeq = SeqValue()
 
         def getKey(self):
             """ Returns a tuple used for sorting the PackageEntry
@@ -194,6 +195,9 @@ class Packager:
             solo = xpackage.Attribute('solo')
             self.solo = int(solo or '0')
 
+            self.packageSeq = SeqValue()
+            self.packageSeq.loadXml(xpackage)
+
             self.descFile = FileSpec()
             self.descFile.loadXml(xpackage)
 
@@ -215,6 +219,7 @@ class Packager:
             if self.solo:
                 xpackage.SetAttribute('solo', '1')
 
+            self.packageSeq.storeXml(xpackage)
             self.descFile.storeXml(xpackage)
 
             if self.importDescFile:
@@ -658,6 +663,7 @@ class Packager:
                 os.chmod(self.packageFullpath.toOsSpecific(), 0755)
             else:
                 self.readDescFile()
+                self.packageSeq += 1
                 self.compressMultifile()
                 self.writeDescFile()
                 self.writeImportDescFile()
@@ -672,6 +678,7 @@ class Packager:
                 pe.fromFile(self.packageName, self.platform, self.version,
                             False, self.packager.installDir,
                             self.packageDesc, self.packageImportDesc)
+                pe.packageSeq = self.packageSeq
                 
                 self.packager.contents[pe.getKey()] = pe
                 self.packager.contentsChanged = True
@@ -733,6 +740,10 @@ class Packager:
             pe.fromFile(self.packageName, self.platform, self.version,
                         True, self.packager.installDir,
                         Filename(packageDir, file.newName), None)
+            peOrig = self.packager.contents.get(pe.getKey(), None)
+            if peOrig:
+                pe.packageSeq = peOrig.packageSeq + 1
+
             self.packager.contents[pe.getKey()] = pe
             self.packager.contentsChanged = True
 
@@ -1204,6 +1215,7 @@ class Packager:
                 if package.version:
                     xrequires.SetAttribute('version', package.version)
                 xrequires.SetAttribute('host', package.host)
+                package.packageSeq.storeXml(xrequires)
                 requireHosts[package.host] = True
                 xpackage.InsertEndChild(xrequires)
 
@@ -1249,6 +1261,7 @@ class Packager:
             it.  We need this to preserve the list of patches, and
             similar historic data, between sessions. """
 
+            self.packageSeq = SeqValue()
             self.patchVersion = None
             self.patches = []
 
@@ -1263,6 +1276,8 @@ class Packager:
             if not xpackage:
                 return
 
+            self.packageSeq.loadXml(xpackage)
+
             xcompressed = xpackage.FirstChildElement('compressed_archive')
             if xcompressed:
                 compressedFilename = xcompressed.Attribute('filename')
@@ -1309,6 +1324,8 @@ class Packager:
             if self.patchVersion:
                 xpackage.SetAttribute('last_patch_version', self.patchVersion)
 
+            self.packageSeq.storeXml(xpackage)
+
             self.__addConfigs(xpackage)
 
             for package in self.requires:
@@ -1318,6 +1335,7 @@ class Packager:
                     xrequires.SetAttribute('platform', package.platform)
                 if package.version:
                     xrequires.SetAttribute('version', package.version)
+                package.packageSeq.storeXml(xrequires)
                 xrequires.SetAttribute('host', package.host)
                 xpackage.InsertEndChild(xrequires)
 
@@ -1379,6 +1397,8 @@ class Packager:
                 xpackage.SetAttribute('version', self.version)
             xpackage.SetAttribute('host', self.host)
 
+            self.packageSeq.storeXml(xpackage)
+
             for package in self.requires:
                 xrequires = TiXmlElement('requires')
                 xrequires.SetAttribute('name', package.packageName)
@@ -1386,6 +1406,7 @@ class Packager:
                     xrequires.SetAttribute('platform', package.platform)
                 if package.version:
                     xrequires.SetAttribute('version', package.version)
+                package.packageSeq.storeXml(xrequires)
                 xrequires.SetAttribute('host', package.host)
                 xpackage.InsertEndChild(xrequires)
 
@@ -1400,6 +1421,8 @@ class Packager:
             """ Reads the import desc file.  Returns True on success,
             False on failure. """
 
+            self.packageSeq = SeqValue()
+
             doc = TiXmlDocument(filename.toOsSpecific())
             if not doc.LoadFile():
                 return False
@@ -1412,6 +1435,8 @@ class Packager:
             self.version = xpackage.Attribute('version')
             self.host = xpackage.Attribute('host')
 
+            self.packageSeq.loadXml(xpackage)
+
             self.requires = []
             xrequires = xpackage.FirstChildElement('requires')
             while xrequires:
@@ -1868,6 +1893,25 @@ class Packager:
         # contents.xml before re-querying the server, in seconds.
         self.maxAge = 0
 
+        # The contents seq: a tuple of integers, representing the
+        # current seq value.  The contents seq generally increments
+        # with each modification to the contents.xml file.  There is
+        # also a package seq for each package, which generally
+        # increments with each modification to the package.
+        
+        # The contents seq and package seq are used primarily for
+        # documentation purposes, to note when a new version is
+        # released.  The package seq value can also be used to verify
+        # that the contents.xml, desc.xml, and desc.import.xml files
+        # were all built at the same time.
+
+        # Although the package seqs are used at runtime to verify that
+        # the latest contents.xml file has been downloaded, they are
+        # not otherwise used at runtime, and they are not binding on
+        # the download version.  The md5 hash, not the package seq, is
+        # actually used to differentiate different download versions.
+        self.contentsSeq = SeqValue()
+
         # A search list for previously-built local packages.
 
         # We use a bit of caution to read the Filenames out of the
@@ -3163,6 +3207,7 @@ class Packager:
         self.addHost(self.host)
 
         self.maxAge = 0
+        self.contentsSeq = SeqValue()
         self.contents = {}
         self.contentsChanged = False
 
@@ -3181,6 +3226,8 @@ class Packager:
             maxAge = xcontents.Attribute('max_age')
             if maxAge:
                 self.maxAge = int(maxAge)
+
+            self.contentsSeq.loadXml(xcontents)
                 
             xhost = xcontents.FirstChildElement('host')
             if xhost:
@@ -3212,6 +3259,9 @@ class Packager:
         xcontents = TiXmlElement('contents')
         if self.maxAge:
             xcontents.SetAttribute('max_age', str(self.maxAge))
+
+        self.contentsSeq += 1
+        self.contentsSeq.storeXml(xcontents)
             
         if self.host:
             he = self.hosts.get(self.host, None)

+ 40 - 8
direct/src/p3d/PatchMaker.py

@@ -1,4 +1,5 @@
 from direct.p3d.FileSpec import FileSpec
+from direct.p3d.SeqValue import SeqValue
 from pandac.PandaModules import *
 import copy
 
@@ -427,14 +428,15 @@ class PatchMaker:
 
                 if doProcessing:
                     newCompressedFilename = '%s.%s.pz' % (self.currentFile.filename, self.patchVersion)
-                    oldCompressedPathname = Filename(self.packageDir, oldCompressedFilename)
-                    newCompressedPathname = Filename(self.packageDir, newCompressedFilename)
-                    if oldCompressedPathname.renameTo(newCompressedPathname):
-                        compressedFile.fromFile(self.packageDir, newCompressedFilename)
-                        compressedFile.storeXml(xcompressed)
+                    if newCompressedFilename != oldCompressedFilename:
+                        oldCompressedPathname = Filename(self.packageDir, oldCompressedFilename)
+                        newCompressedPathname = Filename(self.packageDir, newCompressedFilename)
+                        if oldCompressedPathname.renameTo(newCompressedPathname):
+                            compressedFile.fromFile(self.packageDir, newCompressedFilename)
+                            compressedFile.storeXml(xcompressed)
 
-                    self.compressedFilename = newCompressedFilename
-                    self.anyChanges = True
+                        self.compressedFilename = newCompressedFilename
+                        self.anyChanges = True
 
             # Get the base_version--the bottom (oldest) of the patch
             # chain.
@@ -484,6 +486,11 @@ class PatchMaker:
             if not xpackage:
                 return
 
+            packageSeq = SeqValue()
+            packageSeq.loadXml(xpackage)
+            packageSeq += 1
+            packageSeq.storeXml(xpackage)
+
             # Remove all of the old patch entries from the desc file
             # we read earlier.
             xremove = []
@@ -516,6 +523,19 @@ class PatchMaker:
 
             self.doc.SaveFile()
 
+            # Also copy the seq to the import desc file, for
+            # documentation purposes.
+
+            importDescFullpath = Filename(self.patchMaker.installDir, self.packageDesc.cStr()[:-3] + 'import.xml')
+            doc = TiXmlDocument(importDescFullpath.toOsSpecific())
+            if doc.LoadFile():
+                xpackage = doc.FirstChildElement('package')
+                if xpackage:
+                    packageSeq.storeXml(xpackage)
+                    doc.SaveFile()
+            else:
+                print "Couldn't read %s" % (importDescFullpath)
+
             if self.contentsDocPackage:
                 # Now that we've rewritten the xml file, we have to
                 # change the contents.xml file that references it to
@@ -523,7 +543,14 @@ class PatchMaker:
                 fileSpec = FileSpec()
                 fileSpec.fromFile(self.patchMaker.installDir, self.packageDesc)
                 fileSpec.storeXml(self.contentsDocPackage)
-            
+
+                # Also copy the package seq value into the
+                # contents.xml file, mainly for documentation purposes
+                # (the authoritative seq value is within the desc
+                # file).
+                packageSeq.storeXml(self.contentsDocPackage)
+
+
     # PatchMaker constructor.
     def __init__(self, installDir):
         self.installDir = installDir
@@ -601,6 +628,11 @@ class PatchMaker:
 
         xcontents = doc.FirstChildElement('contents')
         if xcontents:
+            contentsSeq = SeqValue()
+            contentsSeq.loadXml(xcontents)
+            contentsSeq += 1
+            contentsSeq.storeXml(xcontents)
+            
             xpackage = xcontents.FirstChildElement('package')
             while xpackage:
                 solo = xpackage.Attribute('solo')

+ 52 - 0
direct/src/p3d/SeqValue.py

@@ -0,0 +1,52 @@
+class SeqValue:
+
+    """ This represents a sequence value read from a contents.xml
+    file, either from the <contents> or the <package> section.  It's
+    represented as series of dotted integers in the xml file, and
+    stored internally as a tuple of integers.
+
+    It may be incremented, which increments only the last integer in
+    the series; or it may be compared with another SeqValue, which
+    compares all of the integers componentwise. """
+
+    def __init__(self, *value):
+        self.value = value
+        if not self.value:
+            self.value = (0,)
+
+    def loadXml(self, xelement):
+        """ Reads the seq from the indicated XML element.  Returns
+        true if loaded, false if not given or if there was an
+        error. """
+
+        self.value = (0,)
+        value = xelement.Attribute('seq')
+        if value:
+            value = value.split('.')
+            try:
+                value = map(int, value)
+            except ValueError:
+                value = None
+        if value:
+            self.value = tuple(value)
+            return True
+        return False
+
+
+    def storeXml(self, xelement):
+        """ Adds the seq to the indicated XML element. """
+        value = '.'.join(map(str, self.value))
+        xelement.SetAttribute('seq', value)
+
+    def __add__(self, inc):
+        """ Increments the seq value, returning the new value. """
+        value = self.value[:-1] + (self.value[-1] + inc,)
+        return SeqValue(*value)
+
+    def __cmp__(self, other):
+        """ Compares to another seq value. """
+        return cmp(self.value, other.value)
+
+    def __str__(self):
+        return 'SeqValue%s' % (repr(self.value))
+    

+ 9 - 5
direct/src/plugin/p3dHost.I

@@ -91,16 +91,20 @@ has_contents_file() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: P3DHost::get_contents_seq
+//     Function: P3DHost::get_contents_iseq
 //       Access: Public
 //  Description: Returns a number that increments whenever a new
 //               version of the contents.xml file has been read.  This
-//               can be used by packages to determine whether they
-//               need to redownload from scratch.
+//               number is local to the session only; it has nothing
+//               to do with the "seq" value written into the
+//               contents.xml file itself.  
+//
+//               This can be used by packages to determine whether
+//               they need to redownload from scratch.
 ////////////////////////////////////////////////////////////////////
 inline int P3DHost::
-get_contents_seq() const {
-  return _contents_seq;
+get_contents_iseq() const {
+  return _contents_iseq;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 106 - 4
direct/src/plugin/p3dHost.cxx

@@ -41,7 +41,7 @@ P3DHost(const string &host_url) :
 
   _xcontents = NULL;
   _contents_expiration = 0;
-  _contents_seq = 0;
+  _contents_iseq = 0;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -171,7 +171,7 @@ read_contents_file(const string &contents_filename, bool fresh_download) {
     delete _xcontents;
   }
   _xcontents = (TiXmlElement *)xcontents->Clone();
-  ++_contents_seq;
+  ++_contents_iseq;
   _contents_spec = FileSpec();
 
   int max_age = P3D_CONTENTS_DEFAULT_MAX_AGE;
@@ -336,17 +336,24 @@ read_xhost(TiXmlElement *xhost) {
 //       Access: Public
 //  Description: Returns a (possibly shared) pointer to the indicated
 //               package.
+//
+//               The package_seq value should be the expected minimum
+//               package_seq value for the indicated package.  If the
+//               given seq value is higher than the package_seq value
+//               in the contents.xml file cached for the host, it is a
+//               sign that the contents.xml file is out of date and
+//               needs to be redownloaded.
 ////////////////////////////////////////////////////////////////////
 P3DPackage *P3DHost::
 get_package(const string &package_name, const string &package_version,
-            const string &alt_host) {
+            const string &package_seq, const string &alt_host) {
   if (!alt_host.empty()) {
     if (_xcontents != NULL) {
       // If we're asking for an alt host and we've already read our
       // contents.xml file, then we already know all of our hosts, and
       // we can start the package off with the correct host immediately.
       P3DHost *new_host = get_alt_host(alt_host);
-      return new_host->get_package(package_name, package_version);
+      return new_host->get_package(package_name, package_version, package_seq);
     }
 
     // If we haven't read contents.xml yet, we need to create the
@@ -379,6 +386,27 @@ get_package(const string &package_name, const string &package_version,
       new P3DPackage(this, package_name, package_version, alt_host);
     package_map[key] = package;
   }
+
+  P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
+  if (!package_seq.empty() && has_current_contents_file(inst_mgr)) {
+    // If we were given a specific package_seq file to verify, and we
+    // believe we have a valid contents.xml file, then check the seq
+    // value in the contents.
+    FileSpec desc_file;
+    string platform, seq;
+    bool solo;
+    if (get_package_desc_file(desc_file, platform, seq, solo,
+                              package_name, package_version)) {
+      nout << package_name << ": asked for seq " << package_seq
+           << ", we have seq " << seq << "\n";
+      if (compare_seq(package_seq, seq) > 0) {
+        // The requested seq value is higher than the one we have on
+        // file; our contents.xml file must be out of date after all.
+        nout << "expiring contents.xml for " << get_host_url() << "\n";
+        _contents_expiration = 0;
+      }
+    }
+  }
     
   return package;
 }
@@ -396,6 +424,7 @@ get_package(const string &package_name, const string &package_version,
 bool P3DHost::
 get_package_desc_file(FileSpec &desc_file,              // out
                       string &package_platform,         // out
+                      string &package_seq,              // out
                       bool &package_solo,               // out
                       const string &package_name,       // in
                       const string &package_version) {  // in
@@ -412,16 +441,21 @@ get_package_desc_file(FileSpec &desc_file,              // out
     const char *name = xpackage->Attribute("name");
     const char *platform = xpackage->Attribute("platform");
     const char *version = xpackage->Attribute("version");
+    const char *seq = xpackage->Attribute("seq");
     const char *solo = xpackage->Attribute("solo");
     if (version == NULL) {
       version = "";
     }
+    if (seq == NULL) {
+      seq = "";
+    }
     if (name != NULL && platform != NULL &&
         package_name == name && 
         inst_mgr->get_platform() == platform &&
         package_version == version) {
       // Here's the matching package definition.
       desc_file.load_xml(xpackage);
+      package_seq = seq;
       package_platform = platform;
       package_solo = false;
       if (solo != NULL) {
@@ -439,6 +473,7 @@ get_package_desc_file(FileSpec &desc_file,              // out
     const char *name = xpackage->Attribute("name");
     const char *platform = xpackage->Attribute("platform");
     const char *version = xpackage->Attribute("version");
+    const char *seq = xpackage->Attribute("seq");
     const char *solo = xpackage->Attribute("solo");
     if (platform == NULL) {
       platform = "";
@@ -446,12 +481,16 @@ get_package_desc_file(FileSpec &desc_file,              // out
     if (version == NULL) {
       version = "";
     }
+    if (seq == NULL) {
+      seq = "";
+    }
     if (name != NULL &&
         package_name == name && 
         *platform == '\0' &&
         package_version == version) {
       // Here's the matching package definition.
       desc_file.load_xml(xpackage);
+      package_seq = seq;
       package_platform = platform;
       package_solo = false;
       if (solo != NULL) {
@@ -805,3 +844,66 @@ save_xml_file(TiXmlDocument *doc, const string &to_filename) {
   unlink(temp_filename.c_str());
   return false;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DHost::compare_seq
+//       Access: Private, Static
+//  Description: Compares the two dotted-integer sequence values
+//               numerically.  Returns -1 if seq_a sorts first, 1 if
+//               seq_b sorts first, 0 if they are equivalent.
+////////////////////////////////////////////////////////////////////
+int P3DHost::
+compare_seq(const string &seq_a, const string &seq_b) {
+  const char *num_a = seq_a.c_str();
+  const char *num_b = seq_b.c_str();
+  int comp = compare_seq_int(num_a, num_b);
+  while (comp == 0) {
+    if (*num_a != '.') {
+      if (*num_b != '.') {
+        // Both strings ran out together.
+        return 0;
+      }
+      // a ran out first.
+      return -1;
+    } else if (*num_b != '.') {
+      // b ran out first.
+      return 1;
+    }
+
+    // Increment past the dot.
+    ++num_a;
+    ++num_b;
+    comp = compare_seq(num_a, num_b);
+  }
+
+  return comp;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DHost::compare_seq_int
+//       Access: Private, Static
+//  Description: Numerically compares the formatted integer value at
+//               num_a with num_b.  Increments both num_a and num_b to
+//               the next character following the valid integer.
+////////////////////////////////////////////////////////////////////
+int P3DHost::
+compare_seq_int(const char *&num_a, const char *&num_b) {
+  long int a;
+  char *next_a;
+  long int b;
+  char *next_b;
+
+  a = strtol((char *)num_a, &next_a, 10);
+  b = strtol((char *)num_b, &next_b, 10);
+
+  num_a = next_a;
+  num_b = next_b;
+
+  if (a < b) {
+    return -1;
+  } else if (b < a) {
+    return 1;
+  } else {
+    return 0;
+  }
+}

+ 6 - 2
direct/src/plugin/p3dHost.h

@@ -44,7 +44,7 @@ public:
 
   inline bool has_contents_file() const;
   bool has_current_contents_file(P3DInstanceManager *inst_mgr) const;
-  inline int get_contents_seq() const;
+  inline int get_contents_iseq() const;
   inline bool check_contents_hash(const string &pathname) const;
 
   bool read_contents_file();
@@ -53,9 +53,11 @@ public:
 
   P3DPackage *get_package(const string &package_name, 
                           const string &package_version,
+                          const string &package_seq,
                           const string &alt_host = "");
   bool get_package_desc_file(FileSpec &desc_file, 
                              string &package_platform,
+                             string &package_seq,
                              bool &package_solo,
                              const string &package_name,
                              const string &package_version);
@@ -74,6 +76,8 @@ private:
   static string standardize_filename(const string &filename);
   static bool copy_file(const string &from_filename, const string &to_filename);
   static bool save_xml_file(TiXmlDocument *doc, const string &to_filename);
+  static int compare_seq(const string &seq_a, const string &seq_b);
+  static int compare_seq_int(const char *&num_a, const char *&num_b);
 
 private:
   string _host_dir;
@@ -83,7 +87,7 @@ private:
   string _descriptive_name;
   TiXmlElement *_xcontents;
   time_t _contents_expiration;
-  int _contents_seq;
+  int _contents_iseq;
   FileSpec _contents_spec;
 
   typedef vector<string> Mirrors;

+ 21 - 8
direct/src/plugin/p3dInstance.cxx

@@ -232,7 +232,7 @@ P3DInstance(P3D_request_ready_func *func,
   // put up a splash image (for instance, the above IT_download image)
   // while we download the real contents.
   P3DHost *host = inst_mgr->get_host(inst_mgr->get_host_url());
-  _image_package = host->get_package("images", "");
+  _image_package = host->get_package("images", "", "");
   if (_image_package != NULL) {
     _image_package->add_instance(this);
   }
@@ -758,7 +758,7 @@ get_request() {
         P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
         P3DHost *host = inst_mgr->get_host(host_url);
         if (package_name != NULL) {
-          P3DPackage *package = host->get_package(package_name, package_version);
+          P3DPackage *package = host->get_package(package_name, package_version, "");
           host->forget_package(package);
         } else {
           // If a NULL package name is given, forget the whole host.
@@ -1021,9 +1021,17 @@ get_log_pathname() const {
 //               instance.  The instance will share responsibility for
 //               downloading the package with any of the other
 //               instances that use the same package.
+//
+//               The seq value should be the expected minimum
+//               package_seq value for the indicated package.  If the
+//               given seq value is higher than the package_seq value
+//               in the contents.xml file cached for the host, it is a
+//               sign that the contents.xml file is out of date and
+//               needs to be redownloaded.
 ////////////////////////////////////////////////////////////////////
 void P3DInstance::
-add_package(const string &name, const string &version, P3DHost *host) {
+add_package(const string &name, const string &version, const string &seq,
+            P3DHost *host) {
   string alt_host = _fparams.lookup_token("alt_host");
 
   // Look up in the p3d_info.xml file to see if this p3d file has
@@ -1043,7 +1051,7 @@ add_package(const string &name, const string &version, P3DHost *host) {
     get_host_info(host);
   }
   
-  P3DPackage *package = host->get_package(name, version, alt_host);
+  P3DPackage *package = host->get_package(name, version, seq, alt_host);
   add_package(package);
 }
     
@@ -1859,7 +1867,7 @@ check_p3d_signature() {
     // We have to go download this package.
     P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
     P3DHost *host = inst_mgr->get_host(inst_mgr->get_host_url());
-    _certlist_package = host->get_package("certlist", "");
+    _certlist_package = host->get_package("certlist", "", "");
     if (_certlist_package != NULL) {
       _certlist_package->add_instance(this);
     }
@@ -1900,7 +1908,7 @@ mark_p3d_untrusted() {
     // We have to go download this package.
     P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
     P3DHost *host = inst_mgr->get_host(inst_mgr->get_host_url());
-    _p3dcert_package = host->get_package("p3dcert", "");
+    _p3dcert_package = host->get_package("p3dcert", "", "");
     if (_p3dcert_package != NULL) {
       _p3dcert_package->add_instance(this);
     }
@@ -2123,8 +2131,12 @@ add_packages() {
       if (version == NULL) {
         version = "";
       }
+      const char *seq = xrequires->Attribute("seq");
+      if (seq == NULL) {
+        seq = "";
+      }
       P3DHost *host = inst_mgr->get_host(host_url);
-      add_package(name, version, host);
+      add_package(name, version, seq, host);
     }
 
     xrequires = xrequires->NextSiblingElement("requires");
@@ -2876,7 +2888,8 @@ report_package_info_ready(P3DPackage *package) {
   P3DPackage::Requires::const_iterator ri;
   for (ri = package->_requires.begin(); ri != package->_requires.end(); ++ri) {
     const P3DPackage::RequiredPackage &rp = (*ri);
-    add_package(rp._package_name, rp._package_version, rp._host);
+    add_package(rp._package_name, rp._package_version, rp._package_seq, 
+                rp._host);
   }
 
   if (get_packages_info_ready()) {

+ 2 - 1
direct/src/plugin/p3dInstance.h

@@ -93,7 +93,8 @@ public:
 
   inline P3D_request_ready_func *get_request_ready_func() const;
 
-  void add_package(const string &name, const string &version, P3DHost *host);
+  void add_package(const string &name, const string &version, 
+                   const string &seq, P3DHost *host);
   void add_package(P3DPackage *package);
   void remove_package(P3DPackage *package);
   bool get_packages_info_ready() const;

+ 2 - 1
direct/src/plugin/p3dPackage.I

@@ -210,9 +210,10 @@ report_step_progress() {
 ////////////////////////////////////////////////////////////////////
 inline P3DPackage::RequiredPackage::
 RequiredPackage(const string &package_name, const string &package_version,
-                P3DHost *host) :
+                const string &package_seq, P3DHost *host) :
   _package_name(package_name),
   _package_version(package_version),
+  _package_seq(package_seq),
   _host(host)
 {
 }

+ 15 - 10
direct/src/plugin/p3dPackage.cxx

@@ -59,7 +59,7 @@ P3DPackage(P3DHost *host, const string &package_name,
   // file, instead of an xml file and a multifile to unpack.
   _package_solo = false;
 
-  _host_contents_seq = 0;
+  _host_contents_iseq = 0;
 
   _xconfig = NULL;
   _temp_contents_file = NULL;
@@ -474,8 +474,8 @@ redownload_contents_file(P3DPackage::Download *download) {
   assert(_active_download == NULL);
   assert(_saved_download == NULL);
   
-  if (_host->get_contents_seq() != _host_contents_seq) {
-    // If the contents_seq number has changed, we don't even need to
+  if (_host->get_contents_iseq() != _host_contents_iseq) {
+    // If the contents_iseq number has changed, we don't even need to
     // download anything--just go restart the download.
     host_got_contents_file();
     return;
@@ -504,8 +504,8 @@ void P3DPackage::
 contents_file_redownload_finished(bool success) {
   bool contents_changed = false;
   
-  if (_host->get_contents_seq() != _host_contents_seq) {
-    // If the contents_seq number has changed, we don't even need to
+  if (_host->get_contents_iseq() != _host_contents_iseq) {
+    // If the contents_iseq number has changed, we don't even need to
     // bother reading what we just downloaded.
     contents_changed = true;
   }
@@ -592,7 +592,7 @@ host_got_contents_file() {
   // Record this now, so we'll know later whether the host has been
   // reloaded (e.g. due to some other package, from some other
   // instance, reloading it).
-  _host_contents_seq = _host->get_contents_seq();
+  _host_contents_iseq = _host->get_contents_iseq();
 
   // Now that we have a valid host, we can define the _package_dir.
   _package_dir = _host->get_host_dir() + string("/") + _package_name;
@@ -619,8 +619,9 @@ download_desc_file() {
   // Attempt to check the desc file for freshness.  If it already
   // exists, and is consistent with the server contents file, we don't
   // need to re-download it.
+  string package_seq;
   if (!_host->get_package_desc_file(_desc_file, _package_platform, 
-                                    _package_solo,
+                                    package_seq, _package_solo,
                                     _package_name, _package_version)) {
     nout << "Couldn't find package " << _package_fullname
          << " in contents file.\n";
@@ -768,14 +769,18 @@ got_desc_file(TiXmlDocument *doc, bool freshly_downloaded) {
   TiXmlElement *xrequires = xpackage->FirstChildElement("requires");
   while (xrequires != NULL) {
     const char *package_name = xrequires->Attribute("name");
-    const char *version = xrequires->Attribute("version");
     const char *host_url = xrequires->Attribute("host");
     if (package_name != NULL && host_url != NULL) {
-      P3DHost *host = inst_mgr->get_host(host_url);
+      const char *version = xrequires->Attribute("version");
       if (version == NULL) {
         version = "";
       }
-      _requires.push_back(RequiredPackage(package_name, version, host));
+      const char *seq = xrequires->Attribute("seq");
+      if (seq == NULL) {
+        seq = "";
+      }
+      P3DHost *host = inst_mgr->get_host(host_url);
+      _requires.push_back(RequiredPackage(package_name, version, seq, host));
     }
 
     xrequires = xrequires->NextSiblingElement("requires");

+ 3 - 1
direct/src/plugin/p3dPackage.h

@@ -245,9 +245,11 @@ public:
   public:
     inline RequiredPackage(const string &package_name,
                            const string &package_version,
+                           const string &package_seq,
                            P3DHost *host);
     string _package_name;
     string _package_version;
+    string _package_seq;
     P3DHost *_host;
   };
   typedef vector<RequiredPackage> Requires;
@@ -255,7 +257,7 @@ public:
 
 private:
   P3DHost *_host;
-  int _host_contents_seq;
+  int _host_contents_iseq;
 
   string _package_name;
   string _package_version;