// // 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 // . // // // update // // Actually do a cvs update command. 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. // // The -I option is not used -- files which the client can decide whether // to ignore are not mentioned and the client sends the Questionable // request for others. // // Root required: yes. // Directory required: yes. // Response expected: yes. // // // From cvs(1)... // // Bring your working directory up to date with changes from the // repository. Merges are performed automatically when possible; a // warning is issued if manual resolution is required for conflicting // changes. (Does not change repository.) // // update [ -ACdflPpQqR ][ -d ][ -r tag | -D date ] files... // // After you've run checkout to create your private copy of source // from the common repository, other developers will continue changing // the central source. From time to time, when it is convenient in your // development process, you can use the update command from within your // working directory to reconcile your work with any revisions applied // to the source repository since your last checkout or update. // // update keeps you informed of its progress by printing a line for // each file, prefaced with one of the characters U P A R M C ? // to indicate the status of the file: // // U file // The file was brought up to date with respect to the // repository. This is done for any file that exists in the // repository but not in your source, and for files that you // haven't changed but are not the most recent versions available // in the repository. // // P file // Like U, but the CVS server sends a patch instead of an // entire file. This accomplishes the same thing as U using // less bandwidth. // // A file // The file has been added to your private copy of the sources, // and will be added to the source repository when you run cvs // commit on the file. This is a reminder to you that the file // needs to be committed. // // R file // The file has been removed from your private copy of the // sources, and will be removed from the source repository when // you run cvs commit on the file. This is a reminder to you // that the file needs to be committed. // // M file // The file is modified in your working directory. The M can // indicate one of two states for a file you are working on: // either there were no modifications to the same file in the // repository, so that your file remains as you last saw it; or // there were modifications in the repository as well as in your // copy, but they were merged successfully, without conflict, // in your working directory. // // C file // A conflict was detected while trying to merge your changes to // file with changes from the source repository. file (the copy // in your working directory) is now the result of merging the // two versions; an unmodified copy of your file is also in your // working directory, with the name .#file.version, where // version is the revision that your modified file started from. // (Note that some systems automatically purge files that begin // with .# if they have not been accessed for a few days. // If you intend to keep a copy of your original file, it is a // very good idea to rename it.) // // ? file // file is in your working directory, but does not correspond to // anything in the source repository, and is not in the list of // files for cvs to ignore (see the description of the -I option). // // Use the -A option to reset any sticky tags, dates, or -k options. // (If you get a working copy of a file by using one of the -r, -D, // or -k options, cvs remembers the corresponding tag, date, or kflag // and continues using it on future updates; use the -A option to // make cvs forget these specifications, and retrieve the head // version of the file). // // The -jbranch option merges the changes made between the resulting // revision and the revision that it is based on (e.g., if the tag // refers to a branch, cvs will merge all changes made in that branch // into your working file). // // With two -j options, cvs will merge in the changes between the two // respective revisions. This can be used to remove a certain // delta from your working file. E.g., If the file foo.c is based on // revision 1.6 and I want to remove the changes made between 1.3 and // 1.5, I might do: // // example% cvs update -j1.5 -j1.3 foo.c # note the order... // // In addition, each -j option can contain on optional date specification // which, when used with branches, can limit the chosen revision to one // within a specific date. An optional date is specified by adding a // colon (:) to the tag. // // -jSymbolic_Tag:Date_Specifier // // Use the -d option to create any directories that exist in the // repository if they're missing from the working directory. (Normally, // update acts only on directories and files that were already enrolled // in your working directory.) This is useful for updating directories // that were created in the repository since the initial checkout; but it // has an unfortunate side effect. If you deliberately avoided certain // directories in the repository when you created your working directory // (either through use of a module name or by listing explicitly the // files and directories you wanted on the command line), then updating // with -d will create those directories, which may not be what you want. // // Use -I name to ignore files whose names match name (in your working // directory) during the update. You can specify -I more than once on // the command line to specify several files to ignore. By default, // update ignores files whose names match certain patterns; for an up // to date list of ignored file names, see the Cederqvist manual (as // described in the SEE ALSO section of this manpage). // // Use -I ! to avoid ignoring any files at all. // // Use the -C option to overwrite locally modified files with // clean copies from the repository (the modified file is saved in // .#file.revision, however). // // The standard cvs command options -f, -k, -l, -P, -p, and -r are // also available with update. // // // From src/update.c // -A Reset any sticky tags/date/kopts. // -P Prune empty directories. // -C Overwrite locally modified files with clean repository copies. // -d Build directories, like checkout does. // -f Force a head revision match if tag/date not found. // -l Local directory only, no recursion. // -R Process directories recursively. // -p Send updates to standard output (avoids stickiness). // -k kopt Use RCS kopt -k option on checkout. (is sticky) // -r rev Update using specified revision/tag (is sticky). // -D date Set date to update from (is sticky). // -j rev Merge in changes made between current revision and rev. // -I ign More files to ignore (! to reset). // -W spec Wrappers specification line. // // // Reverse Engineering Notes: // // 1. You can tell that files exist on the client side because the // client sent Entry or Modified or Questionable or Unchanged requests // for each of them. // // 2. You can tell if directories exist on the client side because // the client sent Directory requests for each of them. // // 3. Directories must exist before you create new files in them, or // create new directories in them, otherwise the client will give // the user an error. Create directories using the Clear-sticky // and Clear-static-directory responses. // // 4. You must create new files using the Created response. Do not send // this for existing client-side files, or the client will give the // user an error. // // 5. You must update existing files using the Update-existing or Merged // responses. Do not send these responses for files which do not exist // on the client-side, or the client will give the user an error. // // 6. The client can update more than one module in the one request. // This is because the client recursively walks the client side // directory tree without regard for modules. Modules would appear // to be simple directory name aliases. // #include #include #include #include #include request_update::~request_update() { } request_update::request_update() { } void request_update::run_inner(server_ty *sp, string_ty *) const { size_t j; if (server_root_required(sp, "update")) return; if (server_directory_required(sp, "update")) return; // // Process the options. // module_ty::options opt; 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 'A': // // Reset any sticky tags/date/kopts. // opt.A++; break; case 'C': // // Overwrite locally modified files with clean repository // copies. // opt.C++; break; case 'D': // // Set date to update from (is sticky). // opt.D = str_copy(sp->np->argument_nth(++j)); break; case 'd': // // Build directories, like checkout does. // opt.d++; break; case 'f': // // Force a head revision match if tag/date not found. // opt.f++; break; case 'I': // // More files to ignore (! to reset). // opt.I = str_copy(sp->np->argument_nth(++j)); break; case 'j': // // Merge in changes made between current revision and rev. // opt.j = str_copy(sp->np->argument_nth(++j)); break; case 'k': // // Use RCS kopt -k option on checkout. (is sticky) // opt.k = str_copy(sp->np->argument_nth(++j)); break; case 'l': // // Local directory only, no recursion. // opt.l++; break; case 'P': // // Prune empty directories. // opt.P++; break; case 'p': // // Send updates to standard output (avoids stickiness). // opt.p++; break; case 'R': // // Process directories recursively. // opt.R++; break; case 'r': // // Update using specified revision/tag (is sticky). // opt.r = str_copy(sp->np->argument_nth(++j)); break; case 'W': // // Wrappers specification line. // opt.W = str_copy(sp->np->argument_nth(++j)); break; default: server_e(sp, "update: unknown '%s' option", arg->str_text); break; } } // // Now process the rest of the arguments. // Each is a file or directory to be updated. // bool ok = true; 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); // // Pass the update to the relevant module, one argument at a time. // // The CVS client is able to update 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->update(sp, client_side, server_side, opt)) ok = false; str_free(client_side); str_free(server_side); // // Bail if something went wrong. // if (!ok) break; } if (ok) server_ok(sp); } const char * request_update::name() const { return "update"; } bool request_update::reset() const { return true; }