18 #include "multifile.h" 32 set_program_brief(
"prepare a SoftImage database directory for adding to CVS");
33 set_program_description
34 (
"softcvs is designed to prepare a directory hierarchy " 35 "representing a SoftImage database for adding to CVS. " 36 "First, it eliminates SoftImage's silly filename-based " 37 "versioning system by renaming versioned filenames higher " 38 "than 1-0 back to version 1-0. Then, it rolls up all the " 39 "files for each scene except the texture images into a Panda " 40 "multifile, which is added to CVS; the texture images are " 41 "directly added to CVS where they are.\n\n" 43 "The reduction of hundreds of SoftImage files per scene down to one " 44 "multifile and a handle of texture images should greatly improve " 45 "the update and commit times of CVS.\n\n" 47 "You must run this from within the root of a SoftImage database " 48 "directory; e.g. the directory that contains SCENES, PICTURES, MODELS, " 52 add_runline(
"[opts]");
56 "Do not attempt to add newly-created files to CVS. The default " 58 &SoftCVS::dispatch_none, &_no_cvs);
61 (
"cvs",
"cvs_binary", 80,
62 "Specify how to run the cvs program for adding newly-created files. " 63 "The default is simply \"cvs\".",
64 &SoftCVS::dispatch_string, NULL, &_cvs_binary);
79 nout <<
"No SCENES directory found; you are not in the root of a " 80 "SoftImage database.\n";
86 Filename cvs_entries =
"CVS/Entries";
87 if (!_no_cvs && !cvs_entries.
exists()) {
88 nout <<
"You do not appear to be within a CVS-controlled source " 97 collapse_scene_files();
107 remove_unused_elements();
111 cvs_add_or_remove(
"remove", _cvs_remove);
112 cvs_add_or_remove(
"add -kb", _cvs_add);
127 vector_string subdirs;
128 if (!root.scan_directory(subdirs)) {
129 nout <<
"Unable to scan directory.\n";
133 vector_string::const_iterator di;
134 for (di = subdirs.begin(); di != subdirs.end(); ++di) {
137 traverse_subdir(subdir);
149 traverse_subdir(
const Filename &directory) {
153 nout <<
"Unable to scan directory " << directory <<
"\n";
162 in_cvs = scan_cvs(directory, cvs_elements);
165 bool is_scenes =
false;
166 bool keep_all =
false;
167 bool wants_cvs =
false;
172 if (dirname ==
"SCENES") {
175 }
else if (dirname ==
"CAMERAS") {
181 }
else if (dirname ==
"PICTURES") {
196 wants_cvs = !_no_cvs;
199 vector_string::const_iterator fi;
200 for (fi = files.begin(); fi != files.end(); ++fi) {
201 const string &filename = (*fi);
202 if (filename ==
"CVS") {
205 }
else if (filename ==
"Chapter.rsrc") {
208 _global_files.push_back(
Filename(directory, filename));
213 if (cvs_elements.count(filename) != 0) {
215 soft.set_in_cvs(
true);
219 soft.increment_use_count();
221 if (wants_cvs && !in_cvs) {
226 soft.set_wants_cvs(wants_cvs);
228 if (is_scenes && soft.has_version() && soft.get_extension() ==
".dsc") {
229 _scene_files.push_back(soft);
231 _element_files.insert(soft);
245 collapse_scene_files() {
250 versions.swap(_scene_files);
254 sort(versions.begin(), versions.end());
256 SceneFiles::iterator vi;
257 vi = versions.begin();
258 while (vi != versions.end()) {
264 SceneFiles::iterator start_vi;
266 while (vi != versions.end() && (*vi).is_same_file(file)) {
270 rename_file(start_vi, vi);
277 _scene_files.push_back(file);
296 scan_cvs(
".", cvs_elements);
299 SceneFiles::const_iterator vi;
300 for (vi = _scene_files.begin(); vi != _scene_files.end(); ++vi) {
306 if (!file.open_read(in)) {
307 nout <<
"Unable to read " << file <<
"\n";
309 nout <<
"Scanning " << file <<
"\n";
315 nout <<
"Unable to open " << multifile_name <<
" for updating.\n";
319 if (!scan_scene_file(in, multifile)) {
326 vector_string::const_iterator gi;
327 for (gi = _global_files.begin(); gi != _global_files.end(); ++gi) {
329 nout <<
"Unable to add " << (*gi) <<
"\n";
336 nout <<
"Unable to add " << file <<
"\n";
340 bool flushed =
false;
342 flushed = multifile.
repack();
344 flushed = multifile.
flush();
347 nout <<
"Failed to write " << multifile_name <<
".\n";
350 nout <<
"Wrote " << multifile_name <<
".\n";
352 if (!_no_cvs && cvs_elements.count(multifile_name) == 0) {
354 _cvs_add.push_back(multifile_name);
373 remove_unused_elements() {
374 ElementFiles::const_iterator fi;
375 for (fi = _element_files.begin(); fi != _element_files.end(); ++fi) {
380 nout << file <<
" is unused.\n";
382 if (!file.unlink()) {
383 nout <<
"Unable to remove " << file <<
".\n";
386 _cvs_remove.push_back(file);
390 _cvs_add.push_back(file);
405 rename_file(SoftCVS::SceneFiles::iterator begin,
406 SoftCVS::SceneFiles::iterator end) {
407 int length = end - begin;
408 nassertr(length > 0,
false);
417 nout << source_filename <<
" supercedes:\n";
418 SceneFiles::const_iterator p;
419 for (p = begin + 1; p != end; ++p) {
420 nout <<
" " << (*p).get_filename() <<
"\n";
423 }
else if (length == 2) {
424 nout << source_filename <<
" supercedes " 425 << (*(begin + 1)).get_filename() <<
".\n";
428 nout << source_filename <<
" renamed.\n";
433 SceneFiles::const_iterator p;
434 for (p = begin + 1; p != end; ++p) {
435 Filename file((*p).get_dirname(), (*p).get_filename());
436 if (!file.unlink()) {
437 nout <<
"Unable to remove " << file <<
".\n";
442 Filename source(dirname, source_filename);
443 Filename dest(dirname, dest_filename);
445 if (!source.rename_to(dest)) {
446 nout <<
"Unable to rename " << source <<
" to " << dest_filename <<
".\n";
462 scan_cvs(
const string &dirname,
pset<string> &cvs_elements) {
463 Filename cvs_entries = dirname +
"/CVS/Entries";
464 if (!cvs_entries.
exists()) {
471 nout <<
"Unable to read CVS directory.\n";
477 while (!in.fail() && !in.eof()) {
478 if (!line.empty() && line[0] ==
'/') {
479 size_t slash = line.find(
'/', 1);
480 if (slash != string::npos) {
481 string filename = line.substr(1, slash - 1);
483 if (line.substr(slash + 1, 2) ==
"-1") {
488 cvs_elements.insert(filename);
507 scan_scene_file(istream &in,
Multifile &multifile) {
511 while (!in.eof() && !in.fail()) {
513 while (isspace(c) && !in.eof() && !in.fail()) {
519 while (!isspace(c) && !in.eof() && !in.fail()) {
528 pair<ElementFiles::iterator, ElementFiles::iterator> range;
529 range = _element_files.equal_range(v);
531 ElementFiles::iterator ei;
532 for (ei = range.first; ei != range.second; ++ei) {
541 nout <<
"Unable to add " << file <<
"\n";
559 cvs_add(
const string &path) {
560 string command = _cvs_binary +
" add -kb " + path;
561 nout << command <<
"\n";
562 int result = system(command.c_str());
565 nout <<
"Failure invoking cvs.\n";
579 cvs_add_or_remove(
const string &cvs_command,
const vector_string &paths) {
580 static const int max_command = 4096;
582 if (!paths.empty()) {
583 string command = _cvs_binary +
" " + cvs_command;
584 vector_string::const_iterator pi;
586 while (pi != paths.end()) {
587 const string &path = (*pi);
589 if ((
int)command.length() + 1 + (int)path.length() >= max_command) {
591 nout << command <<
"\n";
592 int result = system(command.c_str());
595 nout <<
"Failure invoking cvs.\n";
599 command = _cvs_binary +
" " + cvs_command;
607 nout << command <<
"\n";
608 int result = system(command.c_str());
611 nout <<
"Failure invoking cvs.\n";
619 int main(
int argc,
char *argv[]) {
string get_1_0_filename() const
Returns what the filename would be if it were version 1-0.
string get_basename() const
Returns the basename part of the filename.
const string & get_dirname() const
Returns the name of the directory this file was found in.
virtual void parse_command_line(int argc, char **argv)
Dispatches on each of the options on the command line, and passes the remaining parameters to handle_...
bool needs_repack() const
Returns true if the Multifile index is suboptimal and should be repacked.
void set_text()
Indicates that the filename represents a text file.
bool is_1_0() const
Returns true if this is a version 1_0 filename, false otherwise.
const string & get_base() const
Returns the base part of the filename.
bool get_wants_cvs() const
Returns true if this file should be entered into the CVS database, false otherwise.
bool open_read(ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
string update_subfile(const string &subfile_name, const Filename &filename, int compression_level)
Adds a file on disk to the subfile.
bool repack()
Forces a complete rewrite of the Multifile and all of its contents, so that its index will appear at ...
void increment_use_count()
Indicates that this filename is referenced by one more scene file.
The name of a file, such as a texture file or an Egg file.
int get_use_count() const
Returns the number of scene files that referenced this filename.
bool open_read_write(const Filename &multifile_name)
Opens the named Multifile on disk for reading and writing.
bool flush()
Writes all contents of the Multifile to disk.
const string & get_filename() const
Returns the actual filename as found in the directory.
bool is_directory() const
Returns true if the filename exists and is a directory name, false otherwise.
This encapsulates a SoftImage versioned filename, of the form base.v-v.ext: it consists of a director...
A file that contains a set of files.
bool scan_directory(vector_string &contents) const
Attempts to open the named filename as if it were a directory and looks for the non-hidden files with...
void make_1_0()
Makes this a 1_0 filename.
This program prepares a SoftImage database for CVS by renaming everything to version 1-0...
bool exists() const
Returns true if the filename exists on the disk, false otherwise.
bool get_in_cvs() const
Returns true if this file is known to be entered in the CVS database, false if it is not...