Browse Source

*** empty log message ***

David Rose 25 years ago
parent
commit
9d3475c77b

+ 254 - 275
pandatool/src/softprogs/softCVS.cxx

@@ -35,11 +35,6 @@ SoftCVS() {
   clear_runlines();
   clear_runlines();
   add_runline("[opts]");
   add_runline("[opts]");
 
 
-  add_option
-    ("i", "", 80,
-     "Prompt the user for confirmation before every operation.",
-     &SoftCVS::dispatch_none, &_interactive);
-
   add_option
   add_option
     ("nc", "", 80, 
     ("nc", "", 80, 
      "Do not attempt to add newly-created files to CVS.  The default "
      "Do not attempt to add newly-created files to CVS.  The default "
@@ -79,30 +74,61 @@ run() {
     exit(1);
     exit(1);
   }
   }
 
 
-  // Begin the traversal.
-  traverse(".");
+  // Scan all the files in the database.
+  traverse_root();
+
+  // Collapse out the higher-versioned scene files.
+  collapse_scene_files();
+
+  // Now determine which element files are actually referenced by at
+  // least one of the scene files.
+  count_references();
+
+  // Finally, remove all the element files that are no longer
+  // referenced by any scenes.
+  remove_unused_elements();
 
 
-  // Now consider adjusting the scene files.
-  set<string>::iterator si;
-  for (si = _scene_files.begin(); si != _scene_files.end(); ++si) {
-    consider_scene_file(*si);
+  // Now do all the cvs adding and removing we need.
+  if (!_no_cvs) {
+    cvs_add_or_remove("remove", _cvs_remove);
+    cvs_add_or_remove("add", _cvs_add);
   }
   }
+}
 
 
-  // Finally, add everything to CVS that needs to be added.  We do
-  // this all at once at the end, instead of one at a time as we
-  // encounter each file, to speed things up a bit.
-  cvs_add_all();
+////////////////////////////////////////////////////////////////////
+//     Function: SoftCVS::traverse_root
+//       Access: Private
+//  Description: Reads all of the toplevel directory names,
+//               e.g. SCENES, MATERIALS, etc., and traverses them.
+////////////////////////////////////////////////////////////////////
+void SoftCVS::
+traverse_root() {
+  Filename root(".");
+
+  // Get the list of subdirectories.
+  vector_string subdirs;
+  if (!root.scan_directory(subdirs)) {
+    nout << "Unable to scan directory.\n";
+    return;
+  }
+
+  vector_string::const_iterator di;
+  for (di = subdirs.begin(); di != subdirs.end(); ++di) {
+    Filename subdir = (*di);
+    if (subdir.is_directory() && subdir != "CVS") {
+      traverse_subdir(subdir);
+    }
+  }  
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: SoftCVS::traverse
+//     Function: SoftCVS::traverse_subdir
 //       Access: Private
 //       Access: Private
-//  Description: Reads the directory indicated by prefix, looking for
-//               files that are named something like *.2-0.ext,
-//               and renames these to *.1-0.ext.
+//  Description: Reads the directory indicated by prefix and
+//               identifies all of the SoftImage files stored there.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void SoftCVS::
 void SoftCVS::
-traverse(const Filename &directory) {
+traverse_subdir(const Filename &directory) {
   // Get the list of files in the directory.
   // Get the list of files in the directory.
   vector_string files;
   vector_string files;
   if (!directory.scan_directory(files)) {
   if (!directory.scan_directory(files)) {
@@ -118,74 +144,156 @@ traverse(const Filename &directory) {
     in_cvs = scan_cvs(directory, cvs_elements);
     in_cvs = scan_cvs(directory, cvs_elements);
   }
   }
 
 
-  // Now go through and identify files with version numbers, and
-  // collect together those files that are different versions of the
-  // same file.
-  vector<SoftFilename> versions;
+  bool is_scenes = false;
+  bool keep_all = false;
+
+  // Now make some special-case behavior based on the particular
+  // SoftImage subdirectory we're in.
+  string dirname = directory.get_basename();
+  if (dirname == "SCENES") {
+    is_scenes = true;
+
+  } else if (dirname == "PICTURES") {
+    // In the pictures directory, we must keep everything, since the
+    // scene files don't explicitly reference these but they're still
+    // important.  Textures that are no longer used will pile up; we
+    // leave this is as the user's problem.
+    keep_all = true;
+  }
+
   vector_string::const_iterator fi;
   vector_string::const_iterator fi;
   for (fi = files.begin(); fi != files.end(); ++fi) {
   for (fi = files.begin(); fi != files.end(); ++fi) {
     const string &filename = (*fi);
     const string &filename = (*fi);
-    if (!filename.empty() && filename[0] != '.' && 
-	!(filename == "CVS")) {
-      SoftFilename v(filename);
-      if (v.has_version()) {
-	versions.push_back(v);
+    if (filename == "CVS") {
+      // This special filename is not to be considered.
+
+    } else if (filename == "Chapter.rsrc") {
+      // This special filename should not be considered, except to add
+      // it to CVS.
+      if (in_cvs && cvs_elements.count(filename) == 0) {
+	_cvs_add.push_back(Filename(directory, filename));
+      }
+
+    } else {
+      SoftFilename soft(directory, filename);
+
+      if (in_cvs && cvs_elements.count(filename) != 0) {
+	// This file is known to be in CVS.
+	soft.set_in_cvs(true);
+      }
+
+      if (keep_all) {
+	soft.increment_use_count();
+      }
+
+      if (is_scenes && soft.has_version() && soft.get_extension() == ".dsc") {
+	_scene_files.push_back(soft);
       } else {
       } else {
-	// Maybe this is a subdirectory?
-	Filename subdir(directory, filename);
-	if (subdir.is_directory()) {
-	  traverse(subdir);
-	} else {
-	  // No, not a subdirectory; maybe a regular file that needs
-	  // to get added to CVS?
-	  if (in_cvs) {
-	    consider_add_cvs(directory, filename, cvs_elements);
-	  }
-	}
+	_element_files.insert(soft);
       }
       }
     }
     }
   }
   }
+}
 
 
-  if (!versions.empty()) {
-    // Now sort the versioned filenames in order so we can scan for
-    // higher versions.
-    sort(versions.begin(), versions.end());
+////////////////////////////////////////////////////////////////////
+//     Function: SoftCVS::collapse_scene_files
+//       Access: Private
+//  Description: Walks through the list of scene files found, and
+//               renames the higher-versioned ones to version 1-0,
+//               removing the intervening versions.
+////////////////////////////////////////////////////////////////////
+void SoftCVS::
+collapse_scene_files() {
+  // Get a copy of the scene files vector so we can modify it.  Also
+  // empty out the _scene_files at the same time so we can fill it up
+  // again.
+  SceneFiles versions;
+  versions.swap(_scene_files);
+
+  // And sort them into order so we can easily compare higher and
+  // lower versions.
+  sort(versions.begin(), versions.end());
+
+  SceneFiles::iterator vi;
+  vi = versions.begin();
+  while (vi != versions.end()) {
+    SoftFilename &file = (*vi);
     
     
-    vector<SoftFilename>::iterator vi;
-    vi = versions.begin();
-    while (vi != versions.end()) {
-      SoftFilename &file = (*vi);
-      _versioned_files.insert(file.get_base());
-
-      if (!file.is_1_0()) {
-	// Here's a file that needs to be renamed.  But first, identify
-	// all the other versions of the same file.
-	vector<SoftFilename>::iterator start_vi;
-	start_vi = vi;
-	while (vi != versions.end() && (*vi).is_same_file(file)) {
-	  ++vi;
-	}
-	
-	if (rename_file(directory, start_vi, vi)) {
-	  if (in_cvs) {
-	    consider_add_cvs(directory, file.get_1_0_filename(), cvs_elements);
-	  }
-
-	  if (file.get_extension() == ".dsc") {
-	    _scene_files.insert(Filename(directory, file.get_1_0_filename()));
-	  }
-	}
-	
-      } else {
-	if (in_cvs) {
-	  consider_add_cvs(directory, file.get_filename(), cvs_elements);
-	}
-
-	if (file.get_extension() == ".dsc") {
-	  _scene_files.insert(Filename(directory, file.get_filename()));
-	}
+    if (!file.is_1_0()) {
+      // Here's a file that needs to be renamed.  But first, identify
+      // all the other versions of the same file.
+      SceneFiles::iterator start_vi;
+      start_vi = vi;
+      while (vi != versions.end() && (*vi).is_same_file(file)) {
 	++vi;
 	++vi;
       }
       }
+      
+      rename_file(start_vi, vi);
+      
+    } else {
+      ++vi;
+    }
+
+    file.make_1_0();
+    _scene_files.push_back(file);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftCVS::count_references
+//       Access: Private
+//  Description: Walks through the list of scene files and looks for
+//               the set of element files referenced by the scene
+//               file.  Also add the scene files to CVS if warranted.
+////////////////////////////////////////////////////////////////////
+void SoftCVS::
+count_references() {
+  SceneFiles::const_iterator vi;
+  for (vi = _scene_files.begin(); vi != _scene_files.end(); ++vi) {
+    const SoftFilename &sf = (*vi);
+    Filename file(sf.get_dirname(), sf.get_filename());
+    if (!sf.get_in_cvs()) {
+      _cvs_add.push_back(file);
+    }
+
+    file.set_text();
+    ifstream in;
+    if (!file.open_read(in)) {
+      nout << "Unable to read " << file << "\n";
+    } else {
+      nout << "Scanning " << file << "\n";
+      scan_scene_file(in);
+    }
+  }
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftCVS::remove_unused_elements
+//       Access: Private
+//  Description: Remove all the element files that weren't referenced
+//               by any scene file.  Also plan to cvs add all those
+//               that were referenced.
+////////////////////////////////////////////////////////////////////
+void SoftCVS::
+remove_unused_elements() {
+  ElementFiles::const_iterator fi;
+  for (fi = _element_files.begin(); fi != _element_files.end(); ++fi) {
+    const SoftFilename &sf = (*fi);
+    Filename file(sf.get_dirname(), sf.get_filename());
+
+    if (sf.get_use_count() == 0) {
+      nout << file << " is unused.\n";
+
+      if (!file.unlink()) {
+	nout << "Unable to remove " << file << ".\n";
+
+      } else if (sf.get_in_cvs()) {
+	_cvs_remove.push_back(file);
+      }
+
+    } else if (!sf.get_in_cvs()) {
+      _cvs_add.push_back(file);
     }
     }
   }
   }
 }
 }
@@ -200,18 +308,20 @@ traverse(const Filename &directory) {
 //               false otherwise.
 //               false otherwise.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool SoftCVS::
 bool SoftCVS::
-rename_file(const string &dirname,
-	    vector<SoftFilename>::const_iterator begin, 
-	    vector<SoftFilename>::const_iterator end) {
+rename_file(SoftCVS::SceneFiles::iterator begin, 
+	    SoftCVS::SceneFiles::iterator end) {
   int length = end - begin;
   int length = end - begin;
   nassertr(length > 0, false);
   nassertr(length > 0, false);
 
 
-  string source_filename = (*begin).get_filename();
-  string dest_filename = (*begin).get_1_0_filename();
+  SoftFilename &orig = (*begin);
+
+  string dirname = orig.get_dirname();
+  string source_filename = orig.get_filename();
+  string dest_filename = orig.get_1_0_filename();
 
 
   if (length > 2) {
   if (length > 2) {
     nout << source_filename << " supercedes:\n";
     nout << source_filename << " supercedes:\n";
-    vector<SoftFilename>::const_iterator p;
+    SceneFiles::const_iterator p;
     for (p = begin + 1; p != end; ++p) {
     for (p = begin + 1; p != end; ++p) {
       nout << "  " << (*p).get_filename() << "\n";
       nout << "  " << (*p).get_filename() << "\n";
     }
     }
@@ -221,36 +331,44 @@ rename_file(const string &dirname,
 	 << (*(begin + 1)).get_filename() << ".\n";
 	 << (*(begin + 1)).get_filename() << ".\n";
 
 
   } else {
   } else {
-    if (_interactive) {
-      nout << source_filename << " needs renaming.\n";
-    } else {
-      nout << source_filename << " renamed.\n";
-    }
-  }
-
-  if (_interactive) {
-    if (!prompt_yesno("Rename this file (y/n)? ")) {
-      return false;
-    }
+    nout << source_filename << " renamed.\n";
   }
   }
 
 
   // Now remove all of the "wrong" files.
   // Now remove all of the "wrong" files.
-  vector<SoftFilename>::const_iterator p;
+
+  bool cvs_has_1_0 = false;
+
+  SceneFiles::const_iterator p;
   for (p = begin + 1; p != end; ++p) {
   for (p = begin + 1; p != end; ++p) {
-    Filename file = dirname + "/" + (*p).get_filename();
+    Filename file((*p).get_dirname(), (*p).get_filename());
     if (!file.unlink()) {
     if (!file.unlink()) {
       nout << "Unable to remove " << file << ".\n";
       nout << "Unable to remove " << file << ".\n";
+    } else if ((*p).is_1_0()) {
+      cvs_has_1_0 = true;
+      // We don't cvs remove the 1.0 version.
+    } else {
+      _cvs_remove.push_back(file);
     }
     }
   }
   }
 
 
   // And rename the good one.
   // And rename the good one.
-  Filename source = dirname + "/" + source_filename;
-  Filename dest = dirname + "/" + dest_filename;
+  Filename source(dirname, source_filename);
+  Filename dest(dirname, dest_filename);
+
   if (!source.rename_to(dest)) {
   if (!source.rename_to(dest)) {
     nout << "Unable to rename " << source << " to " << dest_filename << ".\n";
     nout << "Unable to rename " << source << " to " << dest_filename << ".\n";
     exit(1);
     exit(1);
   }
   }
 
 
+  if (orig.get_in_cvs()) {
+    // We do have to cvs remove the old one.
+    _cvs_remove.push_back(source);
+  }
+  if (!cvs_has_1_0) {
+    // And we have to cvs add the new one.
+    _cvs_add.push_back(dest);
+  }
+
   return true;
   return true;
 }
 }
 
 
@@ -267,13 +385,6 @@ scan_cvs(const string &dirname, set<string> &cvs_elements) {
   Filename cvs_entries = dirname + "/CVS/Entries";
   Filename cvs_entries = dirname + "/CVS/Entries";
   if (!cvs_entries.exists()) {
   if (!cvs_entries.exists()) {
     // Try to CVSify the directory.
     // Try to CVSify the directory.
-    if (_interactive) {
-      nout << "Directory " << dirname << " is not CVS-controlled.\n";
-      if (!prompt_yesno("Add the directory to CVS (y/n)? ")) {
-	return false;
-      }
-    }
-
     if (!cvs_add(dirname)) {
     if (!cvs_add(dirname)) {
       return false;
       return false;
     }
     }
@@ -282,7 +393,7 @@ scan_cvs(const string &dirname, set<string> &cvs_elements) {
   ifstream in;
   ifstream in;
   cvs_entries.set_text();
   cvs_entries.set_text();
   if (!cvs_entries.open_read(in)) {
   if (!cvs_entries.open_read(in)) {
-    cerr << "Unable to read CVS directory.\n";
+    nout << "Unable to read CVS directory.\n";
     return true;
     return true;
   }
   }
 
 
@@ -293,7 +404,14 @@ scan_cvs(const string &dirname, set<string> &cvs_elements) {
       size_t slash = line.find('/', 1);
       size_t slash = line.find('/', 1);
       if (slash != string::npos) {
       if (slash != string::npos) {
 	string filename = line.substr(1, slash - 1);
 	string filename = line.substr(1, slash - 1);
-	cvs_elements.insert(filename);
+
+	if (line.substr(slash + 1, 2) == "-1") {
+	  // If the first number after the slash is -1, the file used
+	  // to be here but was recently cvs removed.  It counts as no
+	  // longer being an element.
+	} else {
+	  cvs_elements.insert(filename);
+	}
       }
       }
     }
     }
 
 
@@ -303,102 +421,20 @@ scan_cvs(const string &dirname, set<string> &cvs_elements) {
   return true;
   return true;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: SoftCVS::consider_add_cvs
-//       Access: Private
-//  Description: Considers adding the indicated file to the CVS
-//               repository, if it is not already there.
-////////////////////////////////////////////////////////////////////
-void SoftCVS::
-consider_add_cvs(const string &dirname, const string &filename,
-		 const set<string> &cvs_elements) {
-  if (cvs_elements.count(filename) != 0) {
-    // Already in CVS!
-    return;
-  }
-
-  string path = dirname + "/" + filename;
-
-  if (_interactive) {
-    if (!prompt_yesno("Add " + path + " to CVS (y/n)? ")) {
-      return;
-    }
-  }
-
-  _cvs_paths.push_back(path);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: SoftCVS::consider_scene_file
-//       Access: Private
-//  Description: Checks to see if the indicated file is a scene file,
-//               and that it contains references to a higher-version
-//               filename.  If so, offers to adjust it.
-////////////////////////////////////////////////////////////////////
-void SoftCVS::
-consider_scene_file(Filename path) {
-  path.set_text();
-  ifstream in;
-  if (!path.open_read(in)) {
-    nout << "Could not read " << path << ".\n";
-    return;
-  }
-  
-  // Scan the scene file into memory.
-  ostringstream scene;
-  if (!scan_scene_file(in, scene)) {
-    // The scene file doesn't need to change.
-    return;
-  }
-  
-  // The scene file should change.
-  if (_interactive) {
-    nout << "Scene file " << path << " needs to be updated.\n";
-    if (!prompt_yesno("Modify this file (y/n)? ")) {
-      return;
-    }
-  }
-  
-  // Rewrite the scene file.
-  in.close();
-  path.unlink();
-  ofstream out;
-  if (!path.open_write(out)) {
-    nout << "Could not write " << path << ".\n";
-    return;
-  }
-  
-  string data = scene.str();
-  out.write(data.data(), data.length());
-  
-  if (out.fail()) {
-    nout << "Error writing " << path << ".\n";
-    return;
-  }
-  nout << "Updated scene file " << path << ".\n";
-}
-
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: SoftCVS::scan_scene_file
 //     Function: SoftCVS::scan_scene_file
 //       Access: Private
 //       Access: Private
 //  Description: Copies a scene file from the input stream to the
 //  Description: Copies a scene file from the input stream to the
-//               output stream, looking for stale file references
-//               (i.e. filenames whose version number is greater than
-//               1-0).  If any such filenames are found, replaces them
-//               with the equivalent 1-0 filename, and returns true;
-//               otherwise, returns false.
+//               output stream, looking for references to element
+//               files.  For each reference found, increments the
+//               appropriate element file's reference count.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-bool SoftCVS::
-scan_scene_file(istream &in, ostream &out) {
-  bool any_changed = false;
-  int c;
-
-  c = in.get();
+void SoftCVS::
+scan_scene_file(istream &in) {
+  int c = in.get();
   while (!in.eof() && !in.fail()) {
   while (!in.eof() && !in.fail()) {
     // Skip whitespace.
     // Skip whitespace.
     while (isspace(c) && !in.eof() && !in.fail()) {
     while (isspace(c) && !in.eof() && !in.fail()) {
-      out.put(c);
       c = in.get();
       c = in.get();
     }
     }
 
 
@@ -410,23 +446,22 @@ scan_scene_file(istream &in, ostream &out) {
     }
     }
 
 
     if (!word.empty()) {
     if (!word.empty()) {
-      // Here's the name of a "versioned" element.  Should we rename
-      // it?  Only if the version is not 1-0, and this kind of element
-      // is versioned by filename.  (Some elements are not versioned
-      // by filename; instead, they keep the same filename but store
-      // multiple versions within themselves.  Trouble.)
-      SoftFilename v(word);
-      if (v.has_version() && !v.is_1_0() &&
-	  _versioned_files.count(v.get_base()) != 0) {
-	out << v.get_1_0_filename();
-	any_changed = true;
-      } else {
-	out << word;
+      SoftFilename v("", word);
+
+      // Increment the use count on all matching elements of the multiset.
+      pair<set<SoftFilename>::iterator, set<SoftFilename>::iterator> range;
+      range = _element_files.equal_range(v);
+
+      set<SoftFilename>::iterator ei;
+      for (ei = range.first; ei != range.second; ++ei) {
+	// We cheat and get a non-const reference to the filename out
+	// of the set.  We can safely do this because incrementing the
+	// use count won't change its position in the set.
+	SoftFilename &file = (SoftFilename &)(*ei);
+	file.increment_use_count();
       }
       }
     }
     }
   }
   }
-
-  return any_changed;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -450,21 +485,21 @@ cvs_add(const string &path) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: SoftCVS::cvs_add_all
+//     Function: SoftCVS::cvs_add_or_remove
 //       Access: Private
 //       Access: Private
-//  Description: Invokes CVS to add all of the files in _cvs_paths to
-//               the repository.  Returns true on success, false on
-//               failure.
+//  Description: Invokes CVS to add (or remove) all of the files in
+//               the indicated vector.  Returns true on success, false
+//               on failure.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool SoftCVS::
 bool SoftCVS::
-cvs_add_all() {
+cvs_add_or_remove(const string &cvs_command, const vector_string &paths) {
   static const int max_command = 4096;
   static const int max_command = 4096;
 
 
-  if (!_cvs_paths.empty()) {
-    string command = _cvs_binary + " add";
+  if (!paths.empty()) {
+    string command = _cvs_binary + " " + cvs_command;
     vector_string::const_iterator pi;
     vector_string::const_iterator pi;
-    pi = _cvs_paths.begin();
-    while (pi != _cvs_paths.end()) {
+    pi = paths.begin();
+    while (pi != paths.end()) {
       const string &path = (*pi);
       const string &path = (*pi);
 
 
       if ((int)command.length() + 1 + (int)path.length() >= max_command) {
       if ((int)command.length() + 1 + (int)path.length() >= max_command) {
@@ -477,7 +512,7 @@ cvs_add_all() {
 	  return false;
 	  return false;
 	}
 	}
 
 
-	command = _cvs_binary + " add";
+	command = _cvs_binary + " " + cvs_command;
       }
       }
 
 
       command += ' ';
       command += ' ';
@@ -496,62 +531,6 @@ cvs_add_all() {
   return true;
   return true;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: SoftCVS::prompt_yesno
-//       Access: Private
-//  Description: Asks the user a yes-or-no question.  Returns true if
-//               the answer is yes, false otherwise.
-////////////////////////////////////////////////////////////////////
-bool SoftCVS::
-prompt_yesno(const string &message) {
-  while (true) {
-    string result = prompt(message);
-    nassertr(!result.empty(), false);
-    if (result.size() == 1) {
-      if (tolower(result[0]) == 'y') {
-	return true;
-      } else if (tolower(result[0]) == 'n') {
-	return false;
-      }
-    }
-
-    nout << "*** Invalid response: " << result << "\n\n";
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: SoftCVS::prompt
-//       Access: Private
-//  Description: Issues a prompt to the user and waits for a typed
-//               response.  Returns the response (which will not be
-//               empty).
-////////////////////////////////////////////////////////////////////
-string SoftCVS::
-prompt(const string &message) {
-  nout << flush;
-  while (true) {
-    cerr << message << flush;
-    string response;
-    getline(cin, response);
-
-    // Remove leading and trailing whitespace.
-    size_t p = 0;
-    while (p < response.length() && isspace(response[p])) {
-      p++;
-    }
-    
-    size_t q = response.length();
-    while (q > p && isspace(response[q - 1])) {
-      q--;
-    }
-
-    if (q > p) {
-      return response.substr(p, q - p);
-    }
-  }
-}
-
-
 int main(int argc, char *argv[]) {
 int main(int argc, char *argv[]) {
   SoftCVS prog;
   SoftCVS prog;
   prog.parse_command_line(argc, argv);
   prog.parse_command_line(argc, argv);

+ 18 - 16
pandatool/src/softprogs/softCVS.h

@@ -30,30 +30,32 @@ public:
   void run();
   void run();
 
 
 private:
 private:
-  void traverse(const Filename &directory);
+  typedef vector<SoftFilename> SceneFiles;
+  typedef multiset<SoftFilename> ElementFiles;
 
 
-  bool rename_file(const string &dirname,
-		   vector<SoftFilename>::const_iterator begin, 
-		   vector<SoftFilename>::const_iterator end);
+  void traverse_root();
+  void traverse_subdir(const Filename &directory);
+
+  void collapse_scene_files();
+  void count_references();
+  void remove_unused_elements();
+
+  bool rename_file(SceneFiles::iterator begin, SceneFiles::iterator end);
   bool scan_cvs(const string &dirname, set<string> &cvs_elements);
   bool scan_cvs(const string &dirname, set<string> &cvs_elements);
-  void consider_add_cvs(const string &dirname, const string &filename, 
-			const set<string> &cvs_elements);
-  void consider_scene_file(Filename path);
-  bool scan_scene_file(istream &in, ostream &out);
 
 
-  bool cvs_add(const string &path);
-  bool cvs_add_all();
+  void scan_scene_file(istream &in);
 
 
-  bool prompt_yesno(const string &message);
-  string prompt(const string &message);
+  bool cvs_add(const string &path);
+  bool cvs_add_or_remove(const string &cvs_command, 
+			 const vector_string &paths);
 
 
-  set<string> _scene_files;
-  set<string> _versioned_files;
+  SceneFiles _scene_files;
+  ElementFiles _element_files;
 
 
-  vector_string _cvs_paths;
+  vector_string _cvs_add;
+  vector_string _cvs_remove;
   
   
 protected:
 protected:
-  bool _interactive;
   bool _no_cvs;
   bool _no_cvs;
   string _cvs_binary;
   string _cvs_binary;
 };
 };

+ 98 - 19
pandatool/src/softprogs/softFilename.cxx

@@ -13,12 +13,17 @@
 //  Description: 
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 SoftFilename::
 SoftFilename::
-SoftFilename(const string &filename) :
+SoftFilename(const string &dirname, const string &filename) :
+  _dirname(dirname),
   _filename(filename)
   _filename(filename)
 {
 {
   _has_version = false;
   _has_version = false;
   _major = 0;
   _major = 0;
   _minor = 0;
   _minor = 0;
+  _in_cvs = false;
+  _use_count = 0;
+
+  _base = _filename;
 
 
   // Scan for a version number and an optional extension after each
   // Scan for a version number and an optional extension after each
   // dot in the filename.
   // dot in the filename.
@@ -56,12 +61,15 @@ SoftFilename(const string &filename) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 SoftFilename::
 SoftFilename::
 SoftFilename(const SoftFilename &copy) :
 SoftFilename(const SoftFilename &copy) :
+  _dirname(copy._dirname),
   _filename(copy._filename),
   _filename(copy._filename),
   _has_version(copy._has_version),
   _has_version(copy._has_version),
   _base(copy._base),
   _base(copy._base),
   _major(copy._major),
   _major(copy._major),
   _minor(copy._minor),
   _minor(copy._minor),
-  _ext(copy._ext)
+  _ext(copy._ext),
+  _in_cvs(copy._in_cvs),
+  _use_count(copy._use_count)
 {
 {
 }
 }
 
 
@@ -72,12 +80,26 @@ SoftFilename(const SoftFilename &copy) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void SoftFilename::
 void SoftFilename::
 operator = (const SoftFilename &copy) {
 operator = (const SoftFilename &copy) {
+  _dirname = copy._dirname;
   _filename = copy._filename;
   _filename = copy._filename;
   _has_version = copy._has_version;
   _has_version = copy._has_version;
   _base = copy._base;
   _base = copy._base;
   _major = copy._major;
   _major = copy._major;
   _minor = copy._minor;
   _minor = copy._minor;
   _ext = copy._ext;
   _ext = copy._ext;
+  _in_cvs = copy._in_cvs;
+  _use_count = copy._use_count;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftFilename::get_dirname
+//       Access: Public
+//  Description: Returns the name of the directory this file was 
+//               found in.
+////////////////////////////////////////////////////////////////////
+const string &SoftFilename::
+get_dirname() const {
+  return _dirname;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -184,6 +206,19 @@ is_1_0() const {
   return (_major == 1 && _minor == 0);
   return (_major == 1 && _minor == 0);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: SoftFilename::make_1_0
+//       Access: Public
+//  Description: Makes this a 1_0 filename.
+////////////////////////////////////////////////////////////////////
+void SoftFilename::
+make_1_0() {
+  _has_version = true;
+  _major = 1;
+  _minor = 0;
+  _filename = get_1_0_filename();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: SoftFilename::is_same_file
 //     Function: SoftFilename::is_same_file
 //       Access: Public
 //       Access: Public
@@ -200,31 +235,75 @@ is_same_file(const SoftFilename &other) const {
 //     Function: SoftFilename::Ordering operator
 //     Function: SoftFilename::Ordering operator
 //       Access: Public
 //       Access: Public
 //  Description: Puts filenames in order such that the files with the
 //  Description: Puts filenames in order such that the files with the
-//               same base and extension are sorted together; and
-//               within files with the same base and exntension, files
-//               are sorted in decreasing version number order so that
-//               the most recent version appears first.
-//
-//               The ordering operator is only defined for files that
-//               have a version number.
+//               same base are sorted together, ignoring extension;
+//               and within files with the same base, files are sorted
+//               in decreasing version number order so that the most
+//               recent version appears first.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool SoftFilename::
 bool SoftFilename::
 operator < (const SoftFilename &other) const {
 operator < (const SoftFilename &other) const {
-  nassertr(_has_version, false);
-  nassertr(other._has_version, false);
-
   if (_base != other._base) {
   if (_base != other._base) {
     return _base < other._base;
     return _base < other._base;
   }
   }
-  if (_ext != other._ext) {
-    return _ext < other._ext;
-  }
-  if (_major != other._major) {
-    return _major > other._major;
+
+  if (_has_version != other._has_version) {
+    // If one has a version and the other one doesn't, the one without
+    // a version comes first.
+    return _has_version < other._has_version;
   }
   }
-  if (_minor != other._minor) {
-    return _minor > other._minor;
+
+  if (_has_version) {
+    if (_major != other._major) {
+      return _major > other._major;
+    }
+    if (_minor != other._minor) {
+      return _minor > other._minor;
+    }
   }
   }
 
 
   return false;
   return false;
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftFilename::set_in_cvs
+//       Access: Public
+//  Description: Sets the flag that indicates whether this file is
+//               known to be entered into the CVS database.
+////////////////////////////////////////////////////////////////////
+void SoftFilename::
+set_in_cvs(bool in_cvs) {
+  _in_cvs = in_cvs;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftFilename::get_in_cvs
+//       Access: Public
+//  Description: Returns true if this file is known to be entered in
+//               the CVS database, false if it is not.
+////////////////////////////////////////////////////////////////////
+bool SoftFilename::
+get_in_cvs() const {
+  return _in_cvs;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftFilename::increment_use_count
+//       Access: Public
+//  Description: Indicates that this filename is referenced by one
+//               more scene file.
+////////////////////////////////////////////////////////////////////
+void SoftFilename::
+increment_use_count() {
+  _use_count++;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftFilename::get_use_count
+//       Access: Public
+//  Description: Returns the number of scene files that referenced
+//               this filename.
+////////////////////////////////////////////////////////////////////
+int SoftFilename::
+get_use_count() const {
+  return _use_count;
+}

+ 19 - 3
pandatool/src/softprogs/softFilename.h

@@ -11,15 +11,21 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 // 	 Class : SoftFilename
 // 	 Class : SoftFilename
 // Description : This encapsulates a SoftImage versioned filename, of
 // Description : This encapsulates a SoftImage versioned filename, of
-//               the form base.v-v.ext: it consists of a base, a major
-//               and minor version number, and an optional extension.
+//               the form base.v-v.ext: it consists of a directory
+//               name, a base, a major and minor version number, and
+//               an optional extension.
+//
+//               It also keeps track of whether the named file has
+//               been added to CVS, and how many scene files it is
+//               referenced by,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class SoftFilename {
 class SoftFilename {
 public:
 public:
-  SoftFilename(const string &filename);
+  SoftFilename(const string &dirname, const string &filename);
   SoftFilename(const SoftFilename &copy);
   SoftFilename(const SoftFilename &copy);
   void operator = (const SoftFilename &copy);
   void operator = (const SoftFilename &copy);
 
 
+  const string &get_dirname() const;
   const string &get_filename() const;
   const string &get_filename() const;
   bool has_version() const;
   bool has_version() const;
 
 
@@ -32,17 +38,27 @@ public:
   string get_non_extension() const;
   string get_non_extension() const;
 
 
   bool is_1_0() const;
   bool is_1_0() const;
+  void make_1_0();
 
 
   bool is_same_file(const SoftFilename &other) const;
   bool is_same_file(const SoftFilename &other) const;
   bool operator < (const SoftFilename &other) const;
   bool operator < (const SoftFilename &other) const;
 
 
+  void set_in_cvs(bool in_cvs);
+  bool get_in_cvs() const;
+
+  void increment_use_count();
+  int get_use_count() const;
+
 private:
 private:
+  string _dirname;
   string _filename;
   string _filename;
   bool _has_version;
   bool _has_version;
   string _base;
   string _base;
   int _major;
   int _major;
   int _minor;
   int _minor;
   string _ext;
   string _ext;
+  bool _in_cvs;
+  int _use_count;
 };
 };
 
 
 #endif
 #endif