16 #include "cvsSourceDirectory.h"
29 _key_filename =
"Sources.pp";
31 _user_aborted =
false;
36 add_runline(
"[opts] file [file ... ]");
40 "Force the copy to happen without any input from the user. If a file "
41 "with the same name exists anywhere in the source hierarchy, it will "
42 "be overwritten without prompting; if a file does not yet exist, it "
43 "will be created in the directory named by -d or by -m, as appropriate.",
44 &CVSCopy::dispatch_none, &_force);
48 "The opposite of -f, this will prompt the user before each action. "
49 "The default is only to prompt the user when an action is ambiguous "
51 &CVSCopy::dispatch_none, &_interactive);
55 "Copy model files that are not already present somewhere in the tree "
56 "to the indicated directory. The default is the current directory.",
57 &CVSCopy::dispatch_filename, &_got_model_dirname, &_model_dirname);
61 "Copy texture map files to the indicated directory. The default "
62 "is src/maps from the root directory.",
63 &CVSCopy::dispatch_filename, &_got_map_dirname, &_map_dirname);
66 (
"root",
"dirname", 80,
67 "Specify the root of the CVS source hierarchy. The default is to "
68 "use the ppremake convention of locating the directory above the -d "
69 "directory that contains a file called Package.pp.",
70 &CVSCopy::dispatch_filename, &_got_root_dirname, &_root_dirname);
73 (
"key",
"filename", 80,
74 "Specify the name of the file that must exist in each directory for "
75 "it to be considered part of the CVS source hierarchy. The default "
76 "is the ppremake convention, \"Sources.pp\". Other likely candidates "
77 "are \"CVS\" to search a CVS hierarchy, or \".\" to include "
78 "all subdirectories indiscriminately.",
79 &CVSCopy::dispatch_filename, NULL, &_key_filename);
83 "Do not attempt to add newly-created files to CVS. The default "
85 &CVSCopy::dispatch_none, &_no_cvs);
88 (
"cvs",
"cvs_binary", 80,
89 "Specify how to run the cvs program for adding newly-created files. "
90 "The default is simply \"cvs\".",
91 &CVSCopy::dispatch_string, NULL, &_cvs_binary);
115 CopiedFiles::const_iterator ci;
116 ci = _copied_files.find(source);
117 if (ci != _copied_files.end()) {
123 nout <<
"Source filename " << source <<
" does not exist!\n";
127 string basename = filter_filename(source.
get_basename());
131 nassertr(path.is_valid(), path);
133 _copied_files[source] = path;
136 bool new_file = !dest.
exists();
137 if (!new_file && verify_file(source, dest, path._dir, extra_data)) {
139 nout << path.get_path() <<
" is unchanged.\n";
143 nout <<
"Copying " << basename <<
" to " << path.get_path() <<
"\n";
145 if (!copy_file(source, dest, path._dir, extra_data, new_file)) {
177 string result = prompt(
"Error occurred during copy! Continue (y/n)? ");
178 nassertr(!result.empty(),
false);
179 if (result.size() == 1) {
180 if (tolower(result[0]) ==
'y') {
182 }
else if (tolower(result[0]) ==
'n') {
183 _user_aborted =
true;
188 nout <<
"*** Invalid response: " << result <<
"\n\n";
202 handle_args(Args &args) {
204 nout <<
"You must specify the file(s) to copy from on the command line.\n";
208 for (Args::const_iterator ai = args.begin();
227 post_command_line() {
228 if (!scan_hierarchy()) {
234 if (_got_model_dirname) {
235 nout <<
"Warning: model directory " << _model_dirname
236 <<
" is not within the source hierarchy.\n";
240 if (_got_map_dirname) {
244 nout <<
"Warning: map directory " << _map_dirname
245 <<
" is not within the source hierarchy.\n";
254 _map_dir = _model_dir;
284 if (source == dest) {
302 while (!s.eof() && !s.fail() && !d.eof() && !d.fail()) {
310 if (s.fail() || d.fail()) {
318 if (!s.eof() || !d.eof()) {
338 if (source == dest) {
348 nout <<
"Cannot read " << source <<
"\n";
354 nout <<
"Cannot write " << dest <<
"\n";
360 while (!in.eof() && !in.fail() && !out.fail()) {
365 if (!in.eof() && in.fail()) {
366 nout <<
"Error reading " << source <<
"\n";
370 nout <<
"Error writing " << dest <<
"\n";
391 nout <<
"Invalid directory: " << filename.
get_dirname() <<
"\n";
395 string command = _cvs_binary +
" add -kb " +
397 nout << command <<
"\n";
398 int result = system(command.c_str());
403 nout <<
"Failure invoking cvs.\n";
418 protect_from_shell(
const string &source) {
421 for (string::const_iterator pi = source.begin(); pi != source.end(); ++pi) {
462 filter_filename(
const string &source) {
477 if (!_got_root_dirname) {
480 if (!scan_for_root(_model_dirname)) {
488 return _tree.
scan(_key_filename);
500 scan_for_root(
const string &dirname) {
501 Filename sources = dirname +
"/Sources.pp";
503 nout <<
"Couldn't find " << sources <<
" in source directory.\n";
506 Filename package = dirname + "/Package.pp";
507 if (package.exists()) {
509 _root_dirname = dirname;
513 return scan_for_root(dirname +
"/..");
524 prompt(
const string &message) {
527 cerr << message << flush;
529 getline(cin, response);
533 while (p < response.length() && isspace(response[p])) {
537 size_t q = response.
length();
538 while (q > p && isspace(response[q - 1])) {
543 return response.substr(p, q - p);
string get_fullpath() const
Returns the entire filename: directory, basename, extension.
CVSSourceTree::FilePath import(const Filename &source, void *extra_data, CVSSourceDirectory *suggested_dir)
Checks for the given filename somewhere in the directory hierarchy, and chooses a place to import it...
bool unlink() const
Permanently deletes the file associated with the filename, if possible.
FilePath choose_directory(const string &basename, CVSSourceDirectory *suggested_dir, bool force, bool interactive)
Determines where an externally referenced model file of the indicated name should go...
void set_binary()
Indicates that the filename represents a binary file.
void set_root(const Filename &root_path)
Sets the root of the source directory.
Filename get_root_fullpath()
Returns the full path from the root to the top of the source hierarchy.
bool open_read(ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
string get_dirname() const
Returns the directory part of the filename.
CVSSourceDirectory * find_directory(const Filename &path)
Returns the source directory that corresponds to the given path, or NULL if there is no such director...
float length() const
Returns the length of the vector, by the Pythagorean theorem.
CVSSourceDirectory * find_relpath(const string &relpath)
Returns the source directory that corresponds to the given relative path from the root...
This represents one particular directory in the hierarchy of source directory files.
The name of a file, such as a texture file or an Egg file.
static bool temp_chdir(const Filename &path)
Temporarily changes the current directory to the named path.
Filename get_root_dirname() const
Returns the local directory name of the root of the tree.
bool continue_after_error()
Prompts the user (unless -f was specified) if he wants to continue the copy operation after some erro...
bool exists() const
Returns true if the filename exists on the disk, false otherwise.
bool scan(const Filename &key_filename)
Scans the complete source directory starting at the indicated pathname.
string get_basename() const
Returns the basename part of the filename.
bool open_write(ofstream &stream, bool truncate=true) const
Opens the indicated ifstream for writing the file, if possible.
static void restore_cwd()
Restores the current directory after changing it from temp_chdir().
static Filename from_os_specific(const string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes, and no drive letter) based on the supplied filename string that describes a filename in the local system conventions (for instance, on Windows, it may use backslashes or begin with a drive letter and a colon).