// // aegis - project change supervisor // Copyright (C) 2004-2008 Peter Miller // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see // . // // // add // // Add a file or directory. This uses any previous Argument, Directory, // Entry, or Modified requests, if they have been sent. The last // Directory sent specifies the working directory at the time of the // operation. // // Root required: yes. // Directory required: yes. // Response expected: yes. // // // Directory Example: // // To add a directory, send the directory to be added using Directory // and Argument requests. // // C: Root /u/cvsroot // . . . // C: Argument nsdir // C: Directory nsdir // C: /u/cvsroot/1dir/nsdir // C: Directory . // C: /u/cvsroot/1dir // C: add // S: M Directory /u/cvsroot/1dir/nsdir added to the repository // S: ok // // You will notice that the server does not signal to the client in any // particular way that the directory has been successfully added. The // client is supposed to just assume that the directory has been added and // update its records accordingly. Note also that adding a directory is // immediate; it does not wait until a "ci" request as files do. // // // File Example: // // To add a file, send the file to be added using a Modified request. // // C: Argument nfile // C: Directory . // C: /u/cvsroot/1dir // C: Is-modified nfile // C: add // S: E cvs server: scheduling file `nfile' for addition // S: Mode u=rw,g=r,o=r // S: Checked-in ./ // S: /u/cvsroot/1dir/nfile // S: /nfile/0/// // S: E cvs server: use 'cvs commit' to add this file permanently // S: ok // // Note that the file has not been added to the repository; the only // effect of a successful add request, for a file, is to supply the // client with a new entries line containing 0 to indicate an added file. // In fact, the client probably could perform this operation without // contacting the server, although using add does cause the server to // perform a few more checks. // // The client sends a subsequent "ci" to actually add the file to the // repository. // // Another quirk of the add request is that with CVS 1.9 and older, // a pathname specified in an Argument request cannot contain "/". // There is no good reason for this restriction, and in fact more // recent CVS servers don't have it. But the way to interoperate with // the older servers is to ensure that all Directory requests for "add" // (except those used to add directories, as described above), use "." for // . Specifying another string for // may not get an error, but it will get you strange Checked-in responses // from the buggy servers. // // // From the cvs(1) man page: // // cvs add file... // Use this command to enroll new files in cvs records of your working // directory. The files will be added to the repository the next time // you run cvs commit. Note: You should use the cvs import command // to bootstrap new sources into the source repository. The cvs add // comman is only used for adding new files to an already checked-out // module. // // add // Add a new file or directory to the repository, pending a cvs // commit on the same file. Can only be done from within sources // created by a previous cvs checkout invocation. Use cvs import // to place whole new hierarchies of sources under cvs control. // (Does not directly affect repository; changes working directory.) // // add [-k kflag] [-m message] files... // Use the add command to create a new file or directory in the // source repository. The files or directories specified with add // must already exist in the current directory (which must have been // created with the checkout command). To add a whole new directory // hierarchy to the source repository (for example, files received // from a third-party vendor), use the cvs import command instead. // // If the argument to cvs add refers to an immediate sub-directory, // the directory is created at the correct place in the source // repository, and the necessary cvs administration files are created // in your working directory. If the directory already exists in // the source repository, cvs add still creates the administration // files in your version of the directory. This allows you to use // cvs add to add a particular directory to your private sources // even if someone else created that directory after your checkout // of the sources. You can do the following: // // example% mkdir new_directory // example% cvs add new_directory // example% cvs update new_directory // // An alternate approach using cvs update might be: // // example% cvs update -d new_directory // // (To add any available new directories to your working directory, // it's probably simpler to use cvs checkout or cvs update -d.) // // The added files are not placed in the source repository until // you use cvs commit to make the change permanent. Doing a cvs // add on a file that was removed with the cvs remove command will // resurrect the file, if no cvs commit command intervened. // // You will have the opportunity to specify a logging message, as // usual, when you use cvs commit to make the new file permanent. // If you'd like to have another logging message associated with just // creation of the file (for example, to describe the file's purpose), // you can specify it with the -m message option to the add command. // // The -k kflag option specifies the default way that this file will // be checked out. The kflag argument is stored in the RCS file // and can be changed with cvs admin. Specifying -ko is useful for // checking in binaries that shouldn't have keywords expanded. // // // The user files or directories must already exist (on the client side). // // An "add" on a file that has been "remove"d but not committed will // cause the file to be resurrected. // // // Reverse Engineering Notes: // // The cvsclient.texi file has it wrong, it says that Modified is // sent, but only Is-modified is sent. // #include #include #include #include #include request_add::~request_add() { } request_add::request_add() { } void request_add::run_inner(server_ty *sp, string_ty *) const { if (server_root_required(sp, "add")) return; if (server_directory_required(sp, "add")) return; // // Process the options. // module_ty::options opt; size_t j = 0; for (j = 0; j < sp->np->argument_count(); ++j) { string_ty *arg = sp->np->argument_nth(j); if (arg->str_text[0] != '-') break; if (0 == strcmp(arg->str_text, "--")) { ++j; break; } switch (arg->str_text[1]) { case 'k': // // Use RCS kopt -k option on checkout. (is sticky) // opt.k = str_copy(sp->np->argument_nth(++j)); break; case 'm': // // Logging message associated with the file. // opt.m = str_copy(sp->np->argument_nth(++j)); break; default: server_e(sp, "add: unknown '%s' option", arg->str_text); break; } } // // Now process the rest of the arguments. // Each is a file or directory to be added. // bool ok = 1; directory_ty *dp = sp->np->get_curdir(); for (; j < sp->np->argument_count(); ++j) { string_ty *arg; string_ty *client_side; string_ty *server_side; // // Build the (more complete) name of the file on both the client // side and the server side. // arg = sp->np->argument_nth(j); client_side = os_path_cat(dp->client_side, arg); server_side = os_path_cat(dp->server_side, arg); // // If they have asked for a directory to be added, we politely // ignore the request, because Aegis doesn't track directory // existence, except as implied by file existence. // if (sp->np->directory_find_client_side(client_side)) { server_m ( sp, "Directory " ROOT_PATH "/%s added to the repository (ignored)", server_side->str_text ); str_free(client_side); str_free(server_side); continue; } // // Pass the add to the relevant module, one argument at a time. // // The CVS client is able to add files in more than one module // in a single command. This means we have to lookup the module // for every argument. // module mp = module::find_trim(server_side); if (!mp->add(sp, client_side, server_side, opt)) ok = 0; str_free(client_side); str_free(server_side); // // Bail if something went wrong. // if (!ok) break; } if (ok) { server_e(sp, "use 'cvs commit' to make the 'cvs add' permanent"); server_ok(sp); } } const char * request_add::name() const { return "add"; } bool request_add::reset() const { return true; }