mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-28 15:53:55 -04:00
*** empty log message ***
This commit is contained in:
parent
a85771f39d
commit
527b16a099
28
pandatool/src/cvscopy/Sources.pp
Normal file
28
pandatool/src/cvscopy/Sources.pp
Normal file
@ -0,0 +1,28 @@
|
||||
#begin lib_target
|
||||
#define TARGET cvscopy
|
||||
#define LOCAL_LIBS \
|
||||
progbase pandatoolbase
|
||||
|
||||
#define OTHER_LIBS \
|
||||
dconfig:c dtool:m
|
||||
|
||||
#define SOURCES \
|
||||
cvsCopy.cxx cvsCopy.h cvsSourceDirectory.cxx cvsSourceDirectory.h \
|
||||
cvsSourceTree.cxx cvsSourceTree.h
|
||||
|
||||
#define INSTALL_HEADERS \
|
||||
cvsCopy.h
|
||||
|
||||
#end lib_target
|
||||
|
||||
#begin test_bin_target
|
||||
#define TARGET testcopy
|
||||
#define LOCAL_LIBS cvscopy
|
||||
|
||||
#define OTHER_LIBS \
|
||||
dconfig:c dtool:m pystub
|
||||
|
||||
#define SOURCES \
|
||||
testCopy.cxx testCopy.h
|
||||
|
||||
#end test_bin_target
|
278
pandatool/src/cvscopy/cvsCopy.cxx
Normal file
278
pandatool/src/cvscopy/cvsCopy.cxx
Normal file
@ -0,0 +1,278 @@
|
||||
// Filename: cvsCopy.cxx
|
||||
// Created by: drose (31Oct00)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "cvsCopy.h"
|
||||
#include "cvsSourceDirectory.h"
|
||||
|
||||
#include <notify.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSCopy::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CVSCopy::
|
||||
CVSCopy() {
|
||||
_model_dirname = ".";
|
||||
_key_filename = "Sources.pp";
|
||||
_cvs_binary = "cvs";
|
||||
_model_dir = (CVSSourceDirectory *)NULL;
|
||||
_map_dir = (CVSSourceDirectory *)NULL;
|
||||
|
||||
clear_runlines();
|
||||
add_runline("[opts] file [file ... ]");
|
||||
|
||||
add_option
|
||||
("f", "", 80,
|
||||
"Force copy to happen without any input from the user. If a file "
|
||||
"with the same name exists anywhere in the source hierarchy, it will "
|
||||
"be overwritten without prompting; if a file does not yet exist, it "
|
||||
"will be created in the directory named by -d or by -m, as appropriate.",
|
||||
&CVSCopy::dispatch_none, &_force);
|
||||
|
||||
add_option
|
||||
("i", "", 80,
|
||||
"The opposite of -f, this will prompt the user before each action. "
|
||||
"The default is only to prompt the user when an action is ambiguous.",
|
||||
&CVSCopy::dispatch_none, &_interactive);
|
||||
|
||||
add_option
|
||||
("d", "dirname", 80,
|
||||
"Copy model files that are not already present somewhere in the tree "
|
||||
"to the indicated directory. The default is the current directory.",
|
||||
&CVSCopy::dispatch_filename, &_got_model_dirname, &_model_dirname);
|
||||
|
||||
add_option
|
||||
("m", "dirname", 80,
|
||||
"Copy texture map files to the indicated directory. The default "
|
||||
"is src/maps from the root directory.",
|
||||
&CVSCopy::dispatch_filename, &_got_map_dirname, &_map_dirname);
|
||||
|
||||
add_option
|
||||
("root", "dirname", 80,
|
||||
"Specify the root of the CVS source hierarchy. The default is to "
|
||||
"use the ppremake convention of locating the directory containing "
|
||||
"Package.pp.",
|
||||
&CVSCopy::dispatch_filename, &_got_root_dirname, &_root_dirname);
|
||||
|
||||
add_option
|
||||
("key", "filename", 80,
|
||||
"Specify the name of the file that must exist in each directory for "
|
||||
"it to be considered part of the CVS source hierarchy. The default "
|
||||
"is the ppremake convention, \"Sources.pp\". Other likely candidates "
|
||||
"are \"CVS\" to search the entire CVS hierarchy, or \".\" to include "
|
||||
"all subdirectories.",
|
||||
&CVSCopy::dispatch_filename, NULL, &_key_filename);
|
||||
|
||||
add_option
|
||||
("nc", "", 80,
|
||||
"Do not attempt to add newly-created files to CVS. The default "
|
||||
"is to add them.",
|
||||
&CVSCopy::dispatch_none, &_no_cvs);
|
||||
|
||||
add_option
|
||||
("cvs", "cvs_binary", 80,
|
||||
"Specify how to run the cvs program for adding newly-created files. "
|
||||
"The default is simply \"cvs\".",
|
||||
&CVSCopy::dispatch_string, NULL, &_cvs_binary);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSCopy::import
|
||||
// Access: Public
|
||||
// Description: Checks for the given filename somewhere in the
|
||||
// directory hierarchy, and chooses a place to import
|
||||
// it. Copies the file by calling copy_file().
|
||||
//
|
||||
// Type is an integer number that is defined by the
|
||||
// derivated class; CVSCopy simply passes it unchanged
|
||||
// to copy_file(). It presumably gives the class a hint
|
||||
// as to how the file should be copied. Suggested_dir
|
||||
// is the suggested directory in which to copy the file,
|
||||
// if it does not already exist elsewhere.
|
||||
//
|
||||
// On success, returns the CVSSourceDirectory it was
|
||||
// actually copied to. On failure, returns NULL.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CVSSourceDirectory *CVSCopy::
|
||||
import(const Filename &source, int type, CVSSourceDirectory *suggested_dir) {
|
||||
CopiedFiles::const_iterator ci;
|
||||
ci = _copied_files.find(source);
|
||||
if (ci != _copied_files.end()) {
|
||||
// We have already copied this file.
|
||||
return (*ci).second;
|
||||
}
|
||||
|
||||
if (!source.exists()) {
|
||||
cerr << "Source filename " << source << " does not exist!\n";
|
||||
return (CVSSourceDirectory *)NULL;
|
||||
}
|
||||
|
||||
string basename = source.get_basename();
|
||||
|
||||
CVSSourceDirectory *dir =
|
||||
_tree.choose_directory(basename, suggested_dir, _force, _interactive);
|
||||
nassertr(dir != (CVSSourceDirectory *)NULL, dir);
|
||||
|
||||
Filename dest = dir->get_fullpath() + "/" + basename;
|
||||
|
||||
_copied_files[source] = dir;
|
||||
|
||||
bool new_file = !dest.exists();
|
||||
if (!copy_file(source, dest, dir, type, new_file)) {
|
||||
return (CVSSourceDirectory *)NULL;
|
||||
}
|
||||
if (new_file) {
|
||||
create_file(dest);
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSCopy::handle_args
|
||||
// Access: Protected, Virtual
|
||||
// Description: Does something with the additional arguments on the
|
||||
// command line (after all the -options have been
|
||||
// parsed). Returns true if the arguments are good,
|
||||
// false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool CVSCopy::
|
||||
handle_args(Args &args) {
|
||||
if (args.empty()) {
|
||||
nout << "You must specify the file(s) to copy from on the command line.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
_source_files = args;
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSCopy::post_command_line
|
||||
// Access: Protected, Virtual
|
||||
// Description: This is called after the command line has been
|
||||
// completely processed, and it gives the program a
|
||||
// chance to do some last-minute processing and
|
||||
// validation of the options and arguments. It should
|
||||
// return true if everything is fine, false if there is
|
||||
// an error.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool CVSCopy::
|
||||
post_command_line() {
|
||||
if (!scan_hierarchy()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_model_dir = _tree.find_directory(_model_dirname);
|
||||
if (_model_dir == (CVSSourceDirectory *)NULL) {
|
||||
if (_got_model_dirname) {
|
||||
nout << "Warning: model directory " << _model_dirname
|
||||
<< " is not within the source hierarchy.\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (_got_map_dirname) {
|
||||
_map_dir = _tree.find_directory(_map_dirname);
|
||||
|
||||
if (_map_dir == (CVSSourceDirectory *)NULL) {
|
||||
nout << "Warning: map directory " << _map_dirname
|
||||
<< " is not within the source hierarchy.\n";
|
||||
}
|
||||
|
||||
} else {
|
||||
_map_dir = _tree.find_relpath("src/maps");
|
||||
|
||||
if (_map_dir == (CVSSourceDirectory *)NULL) {
|
||||
nout << "Warning: no directory " << _tree.get_root_dirname()
|
||||
<< "/src/maps.\n";
|
||||
_map_dir = _model_dir;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSCopy::create_file
|
||||
// Access: Protected
|
||||
// Description: Invokes CVS to add the indicated filename to the
|
||||
// repository, if the user so requested. Returns true
|
||||
// if successful, false if there is an error.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool CVSCopy::
|
||||
create_file(const Filename &filename) {
|
||||
if (_no_cvs) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!CVSSourceTree::temp_chdir(filename.get_dirname())) {
|
||||
nout << "Invalid directory: " << filename.get_dirname() << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
string command = _cvs_binary + " add " + filename.get_basename();
|
||||
nout << command << "\n";
|
||||
int result = system(command.c_str());
|
||||
|
||||
CVSSourceTree::restore_cwd();
|
||||
|
||||
if (result != 0) {
|
||||
nout << "Failure invoking cvs.\n";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSCopy::scan_hierarchy
|
||||
// Access: Private
|
||||
// Description: Starts the scan of the source hierarchy. This
|
||||
// identifies all of the files in the source hierarchy
|
||||
// we're to copy these into, so we can guess where
|
||||
// referenced files should be placed. Returns true if
|
||||
// everything is ok, false if there is an error.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool CVSCopy::
|
||||
scan_hierarchy() {
|
||||
if (!_got_root_dirname) {
|
||||
// If we didn't get a root directory name, find the directory
|
||||
// above this one that contains the file "Package.pp".
|
||||
if (!scan_for_root(_model_dirname)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_tree.set_root(_root_dirname);
|
||||
nout << "Root is " << _tree.get_root_fullpath() << "\n";
|
||||
|
||||
return _tree.scan(_key_filename);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSCopy::scan_for_root
|
||||
// Access: Private
|
||||
// Description: Searches for the root of the source directory by
|
||||
// looking for the parent directory that contains
|
||||
// "Package.pp". Returns true on success, false on
|
||||
// failure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool CVSCopy::
|
||||
scan_for_root(const string &dirname) {
|
||||
Filename sources = dirname + "/Sources.pp";
|
||||
if (!sources.exists()) {
|
||||
nout << "Couldn't find " << sources << " in source directory.\n";
|
||||
return false;
|
||||
}
|
||||
Filename package = dirname + "/Package.pp";
|
||||
if (package.exists()) {
|
||||
// Here's the root!
|
||||
_root_dirname = dirname;
|
||||
return true;
|
||||
}
|
||||
|
||||
return scan_for_root(dirname + "/..");
|
||||
}
|
67
pandatool/src/cvscopy/cvsCopy.h
Normal file
67
pandatool/src/cvscopy/cvsCopy.h
Normal file
@ -0,0 +1,67 @@
|
||||
// Filename: cvsCopy.h
|
||||
// Created by: drose (31Oct00)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef CVSCOPY_H
|
||||
#define CVSCOPY_H
|
||||
|
||||
#include <pandatoolbase.h>
|
||||
|
||||
#include "cvsSourceTree.h"
|
||||
|
||||
#include <programBase.h>
|
||||
#include <filename.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : CVSCopy
|
||||
// Description : This is the base class for a family of programs that
|
||||
// copy files, typically model files like .flt files and
|
||||
// their associated textures, into a CVS-controlled
|
||||
// source tree.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class CVSCopy : public ProgramBase {
|
||||
public:
|
||||
CVSCopy();
|
||||
|
||||
CVSSourceDirectory *
|
||||
import(const Filename &source, int type, CVSSourceDirectory *suggested_dir);
|
||||
|
||||
protected:
|
||||
virtual bool handle_args(Args &args);
|
||||
virtual bool post_command_line();
|
||||
|
||||
virtual bool copy_file(Filename source, Filename dest,
|
||||
CVSSourceDirectory *dest_dir,
|
||||
int type, bool new_file)=0;
|
||||
bool create_file(const Filename &filename);
|
||||
|
||||
private:
|
||||
bool scan_hierarchy();
|
||||
bool scan_for_root(const string &dirname);
|
||||
|
||||
protected:
|
||||
bool _force;
|
||||
bool _interactive;
|
||||
bool _got_model_dirname;
|
||||
Filename _model_dirname;
|
||||
bool _got_map_dirname;
|
||||
Filename _map_dirname;
|
||||
bool _got_root_dirname;
|
||||
Filename _root_dirname;
|
||||
Filename _key_filename;
|
||||
bool _no_cvs;
|
||||
string _cvs_binary;
|
||||
|
||||
typedef vector_string SourceFiles;
|
||||
SourceFiles _source_files;
|
||||
|
||||
CVSSourceTree _tree;
|
||||
CVSSourceDirectory *_model_dir;
|
||||
CVSSourceDirectory *_map_dir;
|
||||
|
||||
typedef map<string, CVSSourceDirectory *> CopiedFiles;
|
||||
CopiedFiles _copied_files;
|
||||
};
|
||||
|
||||
#endif
|
270
pandatool/src/cvscopy/cvsSourceDirectory.cxx
Normal file
270
pandatool/src/cvscopy/cvsSourceDirectory.cxx
Normal file
@ -0,0 +1,270 @@
|
||||
// Filename: cvsSourceDirectory.cxx
|
||||
// Created by: drose (31Oct00)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "cvsSourceDirectory.h"
|
||||
#include "cvsSourceTree.h"
|
||||
|
||||
#include <notify.h>
|
||||
|
||||
#ifdef WIN32_VC
|
||||
// Windows uses a different API for scanning for files in a directory.
|
||||
#define WINDOWS_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceDirectory::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CVSSourceDirectory::
|
||||
CVSSourceDirectory(CVSSourceTree *tree, CVSSourceDirectory *parent,
|
||||
const string &dirname) :
|
||||
_tree(tree),
|
||||
_parent(parent),
|
||||
_dirname(dirname)
|
||||
{
|
||||
if (_parent == (CVSSourceDirectory *)NULL) {
|
||||
_depth = 0;
|
||||
} else {
|
||||
_depth = _parent->_depth + 1;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceDirectory::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CVSSourceDirectory::
|
||||
~CVSSourceDirectory() {
|
||||
Children::iterator ci;
|
||||
for (ci = _children.begin(); ci != _children.end(); ++ci) {
|
||||
delete (*ci);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceDirectory::get_dirname
|
||||
// Access: Public
|
||||
// Description: Returns the local name of this particular directory.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string CVSSourceDirectory::
|
||||
get_dirname() const {
|
||||
return _dirname;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceDirectory::get_fullpath
|
||||
// Access: Public
|
||||
// Description: Returns the full pathname to this particular
|
||||
// directory.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string CVSSourceDirectory::
|
||||
get_fullpath() const {
|
||||
if (_parent == (CVSSourceDirectory *)NULL) {
|
||||
return _tree->get_root_fullpath();
|
||||
}
|
||||
return _parent->get_fullpath() + "/" + _dirname;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceDirectory::get_path
|
||||
// Access: Public
|
||||
// Description: Returns the relative pathname to this particular
|
||||
// directory, as seen from the root of the tree.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string CVSSourceDirectory::
|
||||
get_path() const {
|
||||
if (_parent == (CVSSourceDirectory *)NULL) {
|
||||
return _dirname;
|
||||
}
|
||||
return _parent->get_path() + "/" + _dirname;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceDirectory::get_rel_to
|
||||
// Access: Public
|
||||
// Description: Returns the relative path to the other directory from
|
||||
// this one. This does not include a trailing slash.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string CVSSourceDirectory::
|
||||
get_rel_to(const CVSSourceDirectory *other) const {
|
||||
const CVSSourceDirectory *a = this;
|
||||
const CVSSourceDirectory *b = other;
|
||||
|
||||
if (a == b) {
|
||||
return ".";
|
||||
}
|
||||
|
||||
string prefix, postfix;
|
||||
while (a->_depth > b->_depth) {
|
||||
prefix += "../";
|
||||
a = a->_parent;
|
||||
assert(a != (CVSSourceDirectory *)NULL);
|
||||
}
|
||||
|
||||
while (b->_depth > a->_depth) {
|
||||
postfix = b->_dirname + "/" + postfix;
|
||||
b = b->_parent;
|
||||
assert(b != (CVSSourceDirectory *)NULL);
|
||||
}
|
||||
|
||||
while (a != b) {
|
||||
prefix += "../";
|
||||
postfix = b->_dirname + "/" + postfix;
|
||||
a = a->_parent;
|
||||
b = b->_parent;
|
||||
assert(a != (CVSSourceDirectory *)NULL);
|
||||
assert(b != (CVSSourceDirectory *)NULL);
|
||||
}
|
||||
|
||||
string result = prefix + postfix;
|
||||
assert(!result.empty());
|
||||
return result.substr(0, result.length() - 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceDirectory::get_num_children
|
||||
// Access: Public
|
||||
// Description: Returns the number of subdirectories below this
|
||||
// directory.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int CVSSourceDirectory::
|
||||
get_num_children() const {
|
||||
return _children.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceDirectory::get_child
|
||||
// Access: Public
|
||||
// Description: Returns the nth subdirectory below this directory.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CVSSourceDirectory *CVSSourceDirectory::
|
||||
get_child(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_children.size(), NULL);
|
||||
return _children[n];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceDirectory::find_relpath
|
||||
// Access: Public
|
||||
// Description: Returns the source directory that corresponds to the
|
||||
// given relative path from this directory, or NULL if
|
||||
// there is no match.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CVSSourceDirectory *CVSSourceDirectory::
|
||||
find_relpath(const string &relpath) {
|
||||
if (relpath.empty()) {
|
||||
return this;
|
||||
}
|
||||
|
||||
size_t slash = relpath.find('/');
|
||||
string first = relpath.substr(0, slash);
|
||||
string rest;
|
||||
if (slash != string::npos) {
|
||||
rest = relpath.substr(slash + 1);
|
||||
}
|
||||
|
||||
if (first.empty() || first == ".") {
|
||||
return find_relpath(rest);
|
||||
|
||||
} else if (first == "..") {
|
||||
if (_parent != NULL) {
|
||||
return _parent->find_relpath(rest);
|
||||
}
|
||||
// Tried to back out past the root directory.
|
||||
return (CVSSourceDirectory *)NULL;
|
||||
}
|
||||
|
||||
// Check for a child named "first".
|
||||
Children::const_iterator ci;
|
||||
for (ci = _children.begin(); ci != _children.end(); ++ci) {
|
||||
if ((*ci)->get_dirname() == first) {
|
||||
return (*ci)->find_relpath(rest);
|
||||
}
|
||||
}
|
||||
|
||||
// No match.
|
||||
return (CVSSourceDirectory *)NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceDirectory::find_dirname
|
||||
// Access: Public
|
||||
// Description: Returns the source directory that corresponds to the
|
||||
// given local directory name, or NULL if there is no
|
||||
// match.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CVSSourceDirectory *CVSSourceDirectory::
|
||||
find_dirname(const string &dirname) {
|
||||
if (dirname == _dirname) {
|
||||
return this;
|
||||
}
|
||||
|
||||
Children::const_iterator ci;
|
||||
for (ci = _children.begin(); ci != _children.end(); ++ci) {
|
||||
CVSSourceDirectory *result = (*ci)->find_dirname(dirname);
|
||||
if (result != (CVSSourceDirectory *)NULL) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return (CVSSourceDirectory *)NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceDirectory::scan
|
||||
// Access: Public
|
||||
// Description: Recursively scans the contents of the source
|
||||
// directory. Fullpath is the full path name to the
|
||||
// directory; key_filename is the name of a file that
|
||||
// must exist in each subdirectory for it to be
|
||||
// considered part of the hierarchy. Returns true on
|
||||
// success, false on failure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool CVSSourceDirectory::
|
||||
scan(const string &fullpath, const string &key_filename) {
|
||||
DIR *root = opendir(fullpath.c_str());
|
||||
if (root == (DIR *)NULL) {
|
||||
cerr << "Unable to scan directory " << fullpath << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
struct dirent *d;
|
||||
d = readdir(root);
|
||||
while (d != (struct dirent *)NULL) {
|
||||
string filename = d->d_name;
|
||||
|
||||
if (!filename.empty() && filename[0] != '.') {
|
||||
// Is this possibly a subdirectory name?
|
||||
string next_path = fullpath + "/" + filename;
|
||||
string key = next_path + "/" + key_filename;
|
||||
if (access(key.c_str(), F_OK) == 0) {
|
||||
CVSSourceDirectory *subdir =
|
||||
new CVSSourceDirectory(_tree, this, filename);
|
||||
_children.push_back(subdir);
|
||||
|
||||
if (!subdir->scan(next_path, key_filename)) {
|
||||
closedir(root);
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
// It's not a subdirectory; call it a regular file.
|
||||
_tree->add_file(filename, this);
|
||||
}
|
||||
}
|
||||
|
||||
d = readdir(root);
|
||||
}
|
||||
closedir(root);
|
||||
return true;
|
||||
}
|
52
pandatool/src/cvscopy/cvsSourceDirectory.h
Normal file
52
pandatool/src/cvscopy/cvsSourceDirectory.h
Normal file
@ -0,0 +1,52 @@
|
||||
// Filename: cvsSourceDirectory.h
|
||||
// Created by: drose (31Oct00)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef CVSSOURCEDIRECTORY_H
|
||||
#define CVSSOURCEDIRECTORY_H
|
||||
|
||||
#include <pandatoolbase.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
class CVSSourceTree;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : CVSSourceDirectory
|
||||
// Description : This represents one particular directory in the
|
||||
// hierarchy of source directory files. We must scan
|
||||
// the source directory to identify where the related
|
||||
// files have previously been copied.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class CVSSourceDirectory {
|
||||
public:
|
||||
CVSSourceDirectory(CVSSourceTree *tree, CVSSourceDirectory *parent,
|
||||
const string &dirname);
|
||||
~CVSSourceDirectory();
|
||||
|
||||
string get_dirname() const;
|
||||
string get_fullpath() const;
|
||||
string get_path() const;
|
||||
string get_rel_to(const CVSSourceDirectory *other) const;
|
||||
|
||||
int get_num_children() const;
|
||||
CVSSourceDirectory *get_child(int n) const;
|
||||
|
||||
CVSSourceDirectory *find_relpath(const string &relpath);
|
||||
CVSSourceDirectory *find_dirname(const string &dirname);
|
||||
|
||||
public:
|
||||
bool scan(const string &prefix, const string &key_filename);
|
||||
|
||||
private:
|
||||
CVSSourceTree *_tree;
|
||||
CVSSourceDirectory *_parent;
|
||||
string _dirname;
|
||||
int _depth;
|
||||
|
||||
typedef vector<CVSSourceDirectory *> Children;
|
||||
Children _children;
|
||||
};
|
||||
|
||||
#endif
|
543
pandatool/src/cvscopy/cvsSourceTree.cxx
Normal file
543
pandatool/src/cvscopy/cvsSourceTree.cxx
Normal file
@ -0,0 +1,543 @@
|
||||
// Filename: cvsSourceTree.cxx
|
||||
// Created by: drose (31Oct00)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "cvsSourceTree.h"
|
||||
#include "cvsSourceDirectory.h"
|
||||
|
||||
#include <filename.h>
|
||||
#include <notify.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h> // for perror
|
||||
#include <errno.h>
|
||||
|
||||
bool CVSSourceTree::_got_start_fullpath = false;
|
||||
string CVSSourceTree::_start_fullpath;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceTree::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CVSSourceTree::
|
||||
CVSSourceTree() {
|
||||
_root = (CVSSourceDirectory *)NULL;
|
||||
_got_root_fullpath = false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceTree::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CVSSourceTree::
|
||||
~CVSSourceTree() {
|
||||
if (_root != (CVSSourceDirectory *)NULL) {
|
||||
delete _root;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceTree::set_root
|
||||
// Access: Public
|
||||
// Description: Sets the root of the source directory. This must be
|
||||
// called before scan(), and should not be called more
|
||||
// than once.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CVSSourceTree::
|
||||
set_root(const string &root_path) {
|
||||
nassertv(_path.empty());
|
||||
_path = root_path;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceTree::scan
|
||||
// Access: Public
|
||||
// Description: Scans the complete source directory starting at the
|
||||
// indicated pathname. It is an error to call this more
|
||||
// than once. Returns true on success, false if there
|
||||
// is an error.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool CVSSourceTree::
|
||||
scan(const string &key_filename) {
|
||||
nassertr(_root == (CVSSourceDirectory *)NULL, false);
|
||||
Filename root_fullpath = get_root_fullpath();
|
||||
_root = new CVSSourceDirectory(this, NULL, root_fullpath.get_basename());
|
||||
return _root->scan(_path, key_filename);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceTree::get_root
|
||||
// Access: Public
|
||||
// Description: Returns the root directory of the hierarchy.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CVSSourceDirectory *CVSSourceTree::
|
||||
get_root() const {
|
||||
return _root;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceTree::find_directory
|
||||
// Access: Public
|
||||
// Description: Returns the source directory that corresponds to the
|
||||
// given path, or NULL if there is no such directory in
|
||||
// the source tree.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CVSSourceDirectory *CVSSourceTree::
|
||||
find_directory(const string &path) {
|
||||
string root_fullpath = get_root_fullpath();
|
||||
string fullpath = get_actual_fullpath(path);
|
||||
|
||||
// path is a subdirectory within the source hierarchy if and only if
|
||||
// root_fullpath is an initial prefix of fullpath.
|
||||
if (root_fullpath.length() > fullpath.length() ||
|
||||
fullpath.substr(0, root_fullpath.length()) != root_fullpath) {
|
||||
// Nope!
|
||||
return (CVSSourceDirectory *)NULL;
|
||||
}
|
||||
|
||||
// The relative name is the part of fullpath not in root_fullpath.
|
||||
string relpath = fullpath.substr(root_fullpath.length());
|
||||
|
||||
return _root->find_relpath(relpath);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceTree::find_relpath
|
||||
// Access: Public
|
||||
// Description: Returns the source directory that corresponds to the
|
||||
// given relative path from the root, or NULL if there
|
||||
// is no match. The relative path may or may not
|
||||
// include the name of the root directory itself.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CVSSourceDirectory *CVSSourceTree::
|
||||
find_relpath(const string &relpath) {
|
||||
CVSSourceDirectory *result = _root->find_relpath(relpath);
|
||||
if (result != (CVSSourceDirectory *)NULL) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check for the root dirname at the front of the path, and remove
|
||||
// it if it's there.
|
||||
size_t slash = relpath.find('/');
|
||||
string first = relpath.substr(0, slash);
|
||||
string rest;
|
||||
if (slash != string::npos) {
|
||||
rest = relpath.substr(slash + 1);
|
||||
}
|
||||
|
||||
if (first == _root->get_dirname()) {
|
||||
return _root->find_relpath(rest);
|
||||
}
|
||||
|
||||
return (CVSSourceDirectory *)NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceTree::find_dirname
|
||||
// Access: Public
|
||||
// Description: Returns the source directory that corresponds to the
|
||||
// given local directory name, or NULL if there
|
||||
// is no match.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CVSSourceDirectory *CVSSourceTree::
|
||||
find_dirname(const string &dirname) {
|
||||
return _root->find_dirname(dirname);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceTree::choose_directory
|
||||
// Access: Public
|
||||
// Description: Determines where an externally referenced model file
|
||||
// of the indicated name should go. It does this by
|
||||
// looking for an existing model file of the same name;
|
||||
// if a matching model is not found, or if multiple
|
||||
// matching files are found, prompts the user for the
|
||||
// directory, or uses suggested_dir.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CVSSourceDirectory *CVSSourceTree::
|
||||
choose_directory(const string &filename, CVSSourceDirectory *suggested_dir,
|
||||
bool force, bool interactive) {
|
||||
static Directories empty_dirs;
|
||||
|
||||
Filenames::const_iterator fi;
|
||||
fi = _filenames.find(filename);
|
||||
if (fi != _filenames.end()) {
|
||||
// The filename already exists somewhere.
|
||||
const Directories &dirs = (*fi).second;
|
||||
|
||||
return prompt_user(filename, suggested_dir, dirs,
|
||||
force, interactive);
|
||||
}
|
||||
|
||||
// Now we have to prompt the user for a suitable place to put it.
|
||||
return prompt_user(filename, suggested_dir, empty_dirs,
|
||||
force, interactive);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceTree::get_root_fullpath
|
||||
// Access: Public
|
||||
// Description: Returns the full path from the root to the top of
|
||||
// the source hierarchy.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string CVSSourceTree::
|
||||
get_root_fullpath() {
|
||||
nassertr(!_path.empty(), string());
|
||||
if (!_got_root_fullpath) {
|
||||
_root_fullpath = get_actual_fullpath(_path);
|
||||
_got_root_fullpath = true;
|
||||
}
|
||||
return _root_fullpath;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceTree::get_root_dirname
|
||||
// Access: Public
|
||||
// Description: Returns the local directory name of the root of the
|
||||
// tree.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string CVSSourceTree::
|
||||
get_root_dirname() const {
|
||||
nassertr(_root != (CVSSourceDirectory *)NULL, string());
|
||||
return _root->get_dirname();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceTree::add_file
|
||||
// Access: Public
|
||||
// Description: Adds a new file to the set of known files. This is
|
||||
// normally called from CVSSourceDirectory::scan() and
|
||||
// should not be called directly by the user.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CVSSourceTree::
|
||||
add_file(const string &filename, CVSSourceDirectory *dir) {
|
||||
_filenames[filename].push_back(dir);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceTree::temp_chdir
|
||||
// Access: Public, Static
|
||||
// Description: Temporarily changes the current directory to the
|
||||
// named path. Returns true on success, false on
|
||||
// failure. Call restore_cwd() to restore to the
|
||||
// original directory later.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool CVSSourceTree::
|
||||
temp_chdir(const string &path) {
|
||||
// We have to call this first to guarantee that we have already
|
||||
// determined our starting directory.
|
||||
get_start_fullpath();
|
||||
|
||||
if (chdir(path.c_str()) < 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceTree::restore_cwd
|
||||
// Access: Public, Static
|
||||
// Description: Restores the current directory after changing it from
|
||||
// temp_chdir().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CVSSourceTree::
|
||||
restore_cwd() {
|
||||
string start_fullpath = get_start_fullpath();
|
||||
|
||||
if (chdir(start_fullpath.c_str()) < 0) {
|
||||
// Hey! We can't get back to the directory we started from!
|
||||
perror(start_fullpath.c_str());
|
||||
cerr << "Can't continue, aborting.\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceTree::prompt_user
|
||||
// Access: Private
|
||||
// Description: Prompts the user, if necessary, to choose a directory
|
||||
// to import the given file into.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CVSSourceDirectory *CVSSourceTree::
|
||||
prompt_user(const string &filename, CVSSourceDirectory *suggested_dir,
|
||||
const CVSSourceTree::Directories &dirs,
|
||||
bool force, bool interactive) {
|
||||
if (dirs.size() == 1) {
|
||||
// The file already exists in exactly one place.
|
||||
if (interactive) {
|
||||
return dirs[0];
|
||||
}
|
||||
CVSSourceDirectory *result = ask_existing(filename, dirs[0]);
|
||||
if (result != (CVSSourceDirectory *)NULL) {
|
||||
return result;
|
||||
}
|
||||
|
||||
} else if (dirs.size() > 1) {
|
||||
// The file already exists in multiple places.
|
||||
if (force && !interactive) {
|
||||
return dirs[0];
|
||||
}
|
||||
CVSSourceDirectory *result = ask_existing(filename, dirs, suggested_dir);
|
||||
if (result != (CVSSourceDirectory *)NULL) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// The file does not already exist, or the user declined to replace
|
||||
// an existing file.
|
||||
if (force && !interactive) {
|
||||
return suggested_dir;
|
||||
}
|
||||
|
||||
if (find(dirs.begin(), dirs.end(), suggested_dir) == dirs.end()) {
|
||||
CVSSourceDirectory *result = ask_new(filename, suggested_dir);
|
||||
if (result != (CVSSourceDirectory *)NULL) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Ask the user where the damn thing should go.
|
||||
return ask_any(filename);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceTree::ask_existing
|
||||
// Access: Private
|
||||
// Description: Asks the user if he wants to replace an existing
|
||||
// file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CVSSourceDirectory *CVSSourceTree::
|
||||
ask_existing(const string &filename, CVSSourceDirectory *dir) {
|
||||
while (true) {
|
||||
nout << filename << " found in tree at "
|
||||
<< dir->get_path() + "/" + filename << ".\n";
|
||||
string result = prompt("Overwrite this file (y/n)? ");
|
||||
nassertr(!result.empty(), (CVSSourceDirectory *)NULL);
|
||||
if (result.size() == 1) {
|
||||
if (tolower(result[0]) == 'y') {
|
||||
return dir;
|
||||
} else if (tolower(result[0]) == 'n') {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
nout << "*** Invalid response: " << result << "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceTree::ask_existing
|
||||
// Access: Private
|
||||
// Description: Asks the user which of several existing files he
|
||||
// wants to replace.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CVSSourceDirectory *CVSSourceTree::
|
||||
ask_existing(const string &filename, const CVSSourceTree::Directories &dirs,
|
||||
CVSSourceDirectory *suggested_dir) {
|
||||
while (true) {
|
||||
nout << filename << " found in tree at more than one place:\n";
|
||||
|
||||
bool any_suggested = false;
|
||||
for (int i = 0; i < (int)dirs.size(); i++) {
|
||||
nout << " " << (i + 1) << ". "
|
||||
<< dirs[i]->get_path() + "/" + filename << "\n";
|
||||
if (dirs[i] == suggested_dir) {
|
||||
any_suggested = true;
|
||||
}
|
||||
}
|
||||
|
||||
int next_option = dirs.size() + 1;
|
||||
int suggested_option = -1;
|
||||
|
||||
if (!any_suggested) {
|
||||
suggested_option = next_option;
|
||||
next_option++;
|
||||
nout << "\n" << suggested_option
|
||||
<< ". create "
|
||||
<< suggested_dir->get_path() + "/" + filename
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
int other_option = next_option;
|
||||
nout << other_option << ". Other\n";
|
||||
|
||||
string result = prompt("Choose an option: ");
|
||||
nassertr(!result.empty(), (CVSSourceDirectory *)NULL);
|
||||
const char *nptr = result.c_str();
|
||||
char *endptr;
|
||||
int option = strtol(nptr, &endptr, 10);
|
||||
if (*endptr == '\0') {
|
||||
if (option >= 1 && option <= (int)dirs.size()) {
|
||||
return dirs[option - 1];
|
||||
|
||||
} else if (option == suggested_option) {
|
||||
return suggested_dir;
|
||||
|
||||
} else if (option == other_option) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
nout << "*** Invalid response: " << result << "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceTree::ask_new
|
||||
// Access: Private
|
||||
// Description: Asks the user if he wants to replace an existing
|
||||
// file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CVSSourceDirectory *CVSSourceTree::
|
||||
ask_new(const string &filename, CVSSourceDirectory *dir) {
|
||||
while (true) {
|
||||
nout << filename << " will be created at "
|
||||
<< dir->get_path() + "/" + filename << ".\n";
|
||||
string result = prompt("Create this file (y/n)? ");
|
||||
nassertr(!result.empty(), (CVSSourceDirectory *)NULL);
|
||||
if (result.size() == 1) {
|
||||
if (tolower(result[0]) == 'y') {
|
||||
return dir;
|
||||
} else if (tolower(result[0]) == 'n') {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
nout << "*** Invalid response: " << result << "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceTree::ask_any
|
||||
// Access: Private
|
||||
// Description: Asks the user to type in the name of the directory in
|
||||
// which to store the file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CVSSourceDirectory *CVSSourceTree::
|
||||
ask_any(const string &filename) {
|
||||
while (true) {
|
||||
string result =
|
||||
prompt("Enter the name of the directory to copy " + filename + " to: ");
|
||||
nassertr(!result.empty(), (CVSSourceDirectory *)NULL);
|
||||
|
||||
// The user might enter a fully-qualified path to the directory,
|
||||
// or a relative path from the root (with or without the root's
|
||||
// dirname), or the dirname of the particular directory.
|
||||
CVSSourceDirectory *dir = find_directory(result);
|
||||
if (dir == (CVSSourceDirectory *)NULL) {
|
||||
dir = find_relpath(result);
|
||||
}
|
||||
if (dir == (CVSSourceDirectory *)NULL) {
|
||||
dir = find_dirname(result);
|
||||
}
|
||||
|
||||
if (dir != (CVSSourceDirectory *)NULL) {
|
||||
return dir;
|
||||
}
|
||||
|
||||
nout << "*** Not a valid directory name: " << result << "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceTree::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 CVSSourceTree::
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceTree::get_actual_fullpath
|
||||
// Access: Private, Static
|
||||
// Description: Determines the actual full path from the root to the
|
||||
// named directory. It does this essentially by cd'ing
|
||||
// to the directory and doing pwd, then cd'ing back.
|
||||
// Returns the empty string if the directory is invalid
|
||||
// or cannot be cd'ed into.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string CVSSourceTree::
|
||||
get_actual_fullpath(const string &path) {
|
||||
if (!temp_chdir(path)) {
|
||||
return string();
|
||||
}
|
||||
|
||||
string cwd = get_cwd();
|
||||
restore_cwd();
|
||||
|
||||
return cwd;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceTree::get_start_fullpath
|
||||
// Access: Private, Static
|
||||
// Description: Returns the full path from the root to the directory
|
||||
// in which the user started the program.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string CVSSourceTree::
|
||||
get_start_fullpath() {
|
||||
if (!_got_start_fullpath) {
|
||||
_start_fullpath = get_cwd();
|
||||
_got_start_fullpath = true;
|
||||
}
|
||||
return _start_fullpath;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CVSSourceTree::get_cwd
|
||||
// Access: Private, Static
|
||||
// Description: Calls the system getcwd(), automatically allocating a
|
||||
// large enough string.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string CVSSourceTree::
|
||||
get_cwd() {
|
||||
static size_t bufsize = 1024;
|
||||
static char *buffer = NULL;
|
||||
|
||||
if (buffer == (char *)NULL) {
|
||||
buffer = new char[bufsize];
|
||||
}
|
||||
|
||||
while (getcwd(buffer, bufsize) == (char *)NULL) {
|
||||
if (errno != ERANGE) {
|
||||
perror("getcwd");
|
||||
return string();
|
||||
}
|
||||
delete[] buffer;
|
||||
bufsize = bufsize * 2;
|
||||
buffer = new char[bufsize];
|
||||
nassertr(buffer != (char *)NULL, string());
|
||||
}
|
||||
|
||||
return string(buffer);
|
||||
}
|
81
pandatool/src/cvscopy/cvsSourceTree.h
Normal file
81
pandatool/src/cvscopy/cvsSourceTree.h
Normal file
@ -0,0 +1,81 @@
|
||||
// Filename: cvsSourceTree.h
|
||||
// Created by: drose (31Oct00)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef CVSSOURCETREE_H
|
||||
#define CVSSOURCETREE_H
|
||||
|
||||
#include <pandatoolbase.h>
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
class CVSSourceDirectory;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : CVSSourceTree
|
||||
// Description : This represents the root of the tree of source
|
||||
// directory files.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class CVSSourceTree {
|
||||
public:
|
||||
CVSSourceTree();
|
||||
~CVSSourceTree();
|
||||
|
||||
void set_root(const string &root_path);
|
||||
bool scan(const string &key_filename);
|
||||
|
||||
CVSSourceDirectory *get_root() const;
|
||||
CVSSourceDirectory *find_directory(const string &path);
|
||||
CVSSourceDirectory *find_relpath(const string &relpath);
|
||||
CVSSourceDirectory *find_dirname(const string &dirname);
|
||||
|
||||
CVSSourceDirectory *choose_directory(const string &filename,
|
||||
CVSSourceDirectory *suggested_dir,
|
||||
bool force, bool interactive);
|
||||
|
||||
string get_root_fullpath();
|
||||
string get_root_dirname() const;
|
||||
|
||||
static bool temp_chdir(const string &path);
|
||||
static void restore_cwd();
|
||||
|
||||
public:
|
||||
void add_file(const string &filename, CVSSourceDirectory *dir);
|
||||
|
||||
private:
|
||||
typedef vector<CVSSourceDirectory *> Directories;
|
||||
|
||||
CVSSourceDirectory *
|
||||
prompt_user(const string &filename, CVSSourceDirectory *suggested_dir,
|
||||
const Directories &dirs, bool force, bool interactive);
|
||||
|
||||
CVSSourceDirectory *ask_existing(const string &filename,
|
||||
CVSSourceDirectory *dir);
|
||||
CVSSourceDirectory *ask_existing(const string &filename,
|
||||
const Directories &dirs,
|
||||
CVSSourceDirectory *suggested_dir);
|
||||
CVSSourceDirectory *ask_new(const string &filename, CVSSourceDirectory *dir);
|
||||
CVSSourceDirectory *ask_any(const string &filename);
|
||||
|
||||
string prompt(const string &message);
|
||||
|
||||
static string get_actual_fullpath(const string &path);
|
||||
static string get_start_fullpath();
|
||||
static string get_cwd();
|
||||
|
||||
private:
|
||||
string _path;
|
||||
CVSSourceDirectory *_root;
|
||||
|
||||
typedef map<string, Directories> Filenames;
|
||||
Filenames _filenames;
|
||||
|
||||
static bool _got_start_fullpath;
|
||||
static string _start_fullpath;
|
||||
bool _got_root_fullpath;
|
||||
string _root_fullpath;
|
||||
};
|
||||
|
||||
#endif
|
94
pandatool/src/cvscopy/testCopy.cxx
Normal file
94
pandatool/src/cvscopy/testCopy.cxx
Normal file
@ -0,0 +1,94 @@
|
||||
// Filename: testCopy.cxx
|
||||
// Created by: drose (31Oct00)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "testCopy.h"
|
||||
#include "cvsSourceDirectory.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TestCopy::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
TestCopy::
|
||||
TestCopy() {
|
||||
set_program_description
|
||||
("This program copies one or more files into a CVS source hierarchy. "
|
||||
"Rather than copying the named files immediately into the current "
|
||||
"directory, it first scans the entire source hierarchy, identifying all "
|
||||
"the already-existing files. If the named file to copy matches the "
|
||||
"name of an already-existing file in the current directory or elsewhere "
|
||||
"in the hierarchy, that file is overwritten.\n\n"
|
||||
|
||||
"This is primarily useful as a test program for libcvscopy.");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TestCopy::run
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TestCopy::
|
||||
run() {
|
||||
SourceFiles::iterator fi;
|
||||
for (fi = _source_files.begin(); fi != _source_files.end(); ++fi) {
|
||||
CVSSourceDirectory *dest = import(*fi, 0, _model_dir);
|
||||
if (dest == (CVSSourceDirectory *)NULL) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TestCopy::copy_file
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called by import() if the timestamps indicate that a
|
||||
// file needs to be copied. This does the actual copy
|
||||
// of a file from source to destination. If new_file is
|
||||
// true, then dest does not already exist.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool TestCopy::
|
||||
copy_file(Filename source, Filename dest,
|
||||
CVSSourceDirectory *dir, int type, bool new_file) {
|
||||
source.set_binary();
|
||||
dest.set_binary();
|
||||
|
||||
ifstream in;
|
||||
ofstream out;
|
||||
if (!source.open_read(in)) {
|
||||
cerr << "Cannot read " << source << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!dest.open_write(out)) {
|
||||
cerr << "Cannot write " << dest << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
int c;
|
||||
c = in.get();
|
||||
while (!in.eof() && !in.fail() && !out.fail()) {
|
||||
out.put(c);
|
||||
c = in.get();
|
||||
}
|
||||
|
||||
if (in.fail()) {
|
||||
cerr << "Error reading " << source << "\n";
|
||||
return false;
|
||||
}
|
||||
if (out.fail()) {
|
||||
cerr << "Error writing " << dest << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
TestCopy prog;
|
||||
prog.parse_command_line(argc, argv);
|
||||
prog.run();
|
||||
return 0;
|
||||
}
|
29
pandatool/src/cvscopy/testCopy.h
Normal file
29
pandatool/src/cvscopy/testCopy.h
Normal file
@ -0,0 +1,29 @@
|
||||
// Filename: testCopy.h
|
||||
// Created by: drose (31Oct00)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef TESTCOPY_H
|
||||
#define TESTCOPY_H
|
||||
|
||||
#include <pandatoolbase.h>
|
||||
|
||||
#include "cvsCopy.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : TestCopy
|
||||
// Description : A program to copy ordinary files into the cvs tree.
|
||||
// Mainly to test CVSCopy.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class TestCopy : public CVSCopy {
|
||||
public:
|
||||
TestCopy();
|
||||
|
||||
void run();
|
||||
|
||||
protected:
|
||||
virtual bool copy_file(Filename source, Filename dest,
|
||||
CVSSourceDirectory *dir, int type, bool new_file);
|
||||
};
|
||||
|
||||
#endif
|
@ -73,6 +73,7 @@ ProgramBase() {
|
||||
|
||||
_next_sequence = 0;
|
||||
_sorted_options = false;
|
||||
_last_newline = false;
|
||||
_got_terminal_width = false;
|
||||
_got_option_indent = false;
|
||||
|
||||
@ -171,7 +172,8 @@ show_text(const string &prefix, int indent_width, string text) {
|
||||
// This is correct! It goes go to cerr, not to nout. Sending it to
|
||||
// nout would be cyclic, since nout is redefined to map back through
|
||||
// this function.
|
||||
format_text(cerr, prefix, indent_width, text, _terminal_width);
|
||||
format_text(cerr, _last_newline,
|
||||
prefix, indent_width, text, _terminal_width);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -679,12 +681,19 @@ handle_help_option(const string &, const string &, void *) {
|
||||
//
|
||||
// An embedded newline character ('\n') forces a line
|
||||
// break, while an embedded carriage-return character
|
||||
// ('\r') marks a paragraph break, which is usually
|
||||
// printed as a blank line. Redundant newline and
|
||||
// carriage-return characters are generally ignored.
|
||||
// ('\r'), or two or more consecutive newlines, marks a
|
||||
// paragraph break, which is usually printed as a blank
|
||||
// line. Redundant newline and carriage-return
|
||||
// characters are generally ignored.
|
||||
//
|
||||
// The flag last_newline should be initialized to false
|
||||
// for the first call to format_text, and then preserved
|
||||
// for future calls; it tracks the state of trailing
|
||||
// newline characters between calls so we can correctly
|
||||
// identify doubled newlines.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void ProgramBase::
|
||||
format_text(ostream &out,
|
||||
format_text(ostream &out, bool &last_newline,
|
||||
const string &prefix, int indent_width,
|
||||
const string &text, int line_width) {
|
||||
indent_width = min(indent_width, line_width - 20);
|
||||
@ -705,7 +714,9 @@ format_text(ostream &out,
|
||||
|
||||
// Skip any initial whitespace and newlines.
|
||||
while (p < text.length() && isspace(text[p])) {
|
||||
if (text[p] == '\r') {
|
||||
if (text[p] == '\r' ||
|
||||
(p > 0 && text[p] == '\n' && text[p - 1] == '\n') ||
|
||||
(p == 0 && text[p] == '\n' && last_newline)) {
|
||||
if (!initial_break) {
|
||||
// Here's an initial paragraph break, however.
|
||||
out << "\n";
|
||||
@ -724,6 +735,8 @@ format_text(ostream &out,
|
||||
p++;
|
||||
}
|
||||
|
||||
last_newline = (!text.empty() && text[text.length() - 1] == '\n');
|
||||
|
||||
while (p < text.length()) {
|
||||
// Look for the paragraph or line break--the next newline
|
||||
// character, if any.
|
||||
@ -731,8 +744,11 @@ format_text(ostream &out,
|
||||
bool is_paragraph_break = false;
|
||||
if (par == string::npos) {
|
||||
par = text.length();
|
||||
/*
|
||||
This shouldn't be necessary.
|
||||
} else {
|
||||
is_paragraph_break = (text[par] == '\r');
|
||||
*/
|
||||
}
|
||||
|
||||
indent(out, indent_amount);
|
||||
@ -771,7 +787,8 @@ format_text(ostream &out,
|
||||
|
||||
// Skip additional whitespace between the lines.
|
||||
while (p < text.length() && isspace(text[p])) {
|
||||
if (text[p] == '\r') {
|
||||
if (text[p] == '\r' ||
|
||||
(p > 0 && text[p] == '\n' && text[p - 1] == '\n')) {
|
||||
is_paragraph_break = true;
|
||||
}
|
||||
p++;
|
||||
@ -780,6 +797,11 @@ format_text(ostream &out,
|
||||
if (eol == par && is_paragraph_break) {
|
||||
// Print the paragraph break as a blank line.
|
||||
out << "\n";
|
||||
if (p >= text.length()) {
|
||||
// If we end on a paragraph break, don't try to insert a new
|
||||
// one in the next pass.
|
||||
last_newline = false;
|
||||
}
|
||||
}
|
||||
|
||||
indent_amount = indent_width;
|
||||
|
@ -68,7 +68,7 @@ protected:
|
||||
|
||||
bool handle_help_option(const string &opt, const string &arg, void *);
|
||||
|
||||
static void format_text(ostream &out,
|
||||
static void format_text(ostream &out, bool &last_newline,
|
||||
const string &prefix, int indent_width,
|
||||
const string &text, int line_width);
|
||||
|
||||
@ -107,6 +107,7 @@ private:
|
||||
typedef map<string, string> GotOptions;
|
||||
GotOptions _got_options;
|
||||
|
||||
bool _last_newline;
|
||||
int _terminal_width;
|
||||
bool _got_terminal_width;
|
||||
int _option_indent;
|
||||
|
Loading…
x
Reference in New Issue
Block a user