Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

vcheckout.C

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 // 
00003 // This file is part of Vesta.
00004 // 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 // 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 //
00020 // vcheckout.C
00021 //
00022 
00023 // Check out a package from the Vesta repository.
00024 // See documentation in vcheckout.1.mtex
00025 
00026 #include <Basics.H>
00027 #include <Text.H>
00028 #include <VestaConfig.H>
00029 #include <VestaSource.H>
00030 #include <VDirSurrogate.H>
00031 #include <VestaSourceAtomic.H>
00032 #include <Replicator.H>
00033 #include <signal.h>
00034 #include "ReposUI.H"
00035 
00036 #if !defined(__sun__)
00037 extern "C" {
00038 #include <getopt.h>
00039 }
00040 #endif
00041 
00042 using std::cout;
00043 using std::cerr;
00044 using std::endl;
00045 
00046 Text program_name;
00047 
00048 void
00049 usage()
00050 {
00051   cerr << "Usage: " << program_name << endl <<
00052     "        [-q] [-Q] [-f] [-F]" << endl <<
00053     "        [-o old-version | -O]" << endl <<
00054     "        [-n new-version | -N]" << endl <<
00055     "        [-s session-dir | -S]" << endl <<
00056     "        [-w work-dir | -W]" << endl <<
00057     "        [-m message | -M]" << endl <<
00058     "        [-h hints]" << endl <<
00059     "        [-R repos]" << endl <<
00060     "        package" << endl << endl;
00061   exit(1);
00062 }
00063 
00064 
00065 int
00066 main(int argc, char* argv[])
00067 {
00068   program_name = argv[0];
00069   try {
00070     //
00071     // Read config file
00072     //
00073     Text defpkgpar, defworkpar, timefmt, defhints, foreignsessdirpar;
00074     defpkgpar = VestaConfig::get_Text("UserInterface",
00075                                       "DefaultPackageParent");
00076     defworkpar = VestaConfig::get_Text("UserInterface",
00077                                        "DefaultWorkParent");
00078     timefmt = VestaConfig::get_Text("UserInterface", "TimeFormat");
00079     (void) VestaConfig::get("UserInterface", "DefaultHints", defhints);
00080 
00081     bool prompt_msg = true, omit_msg = false;
00082     if(VestaConfig::is_set("UserInterface", "vcheckout_message")) {
00083       if(!VestaConfig::get_bool("UserInterface", "vcheckout_message")) {
00084         prompt_msg = false;
00085         omit_msg = true;
00086       }
00087     }
00088 
00089     // get foreign session dir parent
00090     if(VestaConfig::get("UserInterface", "ForeignParent", foreignsessdirpar))
00091       {
00092         foreignsessdirpar = ReposUI::canonicalize(foreignsessdirpar);
00093         // add last "/" if it is not present
00094         if(foreignsessdirpar[foreignsessdirpar.Length()-1] != '/')
00095           foreignsessdirpar += "/";
00096       }
00097 
00098     time_t now = time(NULL);
00099     char timebuf[256];
00100     strftime(timebuf, sizeof(timebuf), timefmt.cchars(), localtime(&now));
00101     Text cuser(AccessControl::self()->user());
00102     int atpos = cuser.FindChar('@');
00103     Text user(cuser.Sub(0, atpos));
00104     Text uuser(user + "_" + cuser.Sub(atpos+1)); // cuser with @ replaced by _
00105     char mode[8];
00106     mode_t oumask;
00107     umask(oumask = umask(0));
00108     sprintf(mode, "%03o", 0777 & ~oumask);
00109     Text lhost(VDirSurrogate::defaultHost());
00110     Text lport(VDirSurrogate::defaultPort());
00111     const int vlen = 7; // ==strlen("/vesta/")
00112     const Replicator::Flags rflags = (Replicator::Flags) 
00113       (Replicator::attrNew | Replicator::attrOld | Replicator::attrAccess |
00114        Replicator::revive | Replicator::inclStubs | Replicator::latest);
00115         
00116     // 
00117     // Parse command line
00118     //
00119     Text oldver, newver, sessdir, workdir, pkg, hints, repos, message;
00120     bool default_old = true, default_new = true, default_sess = true;
00121     bool uniquify_nondefault_sess = false;
00122     bool default_work = true, default_repos = true;
00123     bool omit_old = false, omit_new = false, omit_sess = false;
00124     bool omit_work = false;
00125     bool quiet = false, query = false, force = false;
00126     bool foreign_sess_dir = false, foreign_not_default = false;
00127 
00128     opterr = 0;
00129     for (;;) {
00130       char* slash;
00131       int c = getopt(argc, argv, "qQfo:On:NFs:Suw:Wm:Mh:R:");
00132       if (c == EOF) break;
00133       switch (c) {
00134       case 'q':
00135         quiet = true;
00136         break;
00137       case 'Q':
00138         query = true;
00139         break;
00140       case 'f':
00141         force = true;
00142         break;
00143       case 'o':
00144         oldver = optarg;
00145         default_old = false;
00146         break;
00147       case 'O':
00148         omit_old = true;
00149         oldver = "0";
00150         default_old = false;
00151         break;
00152       case 'n':
00153         newver = optarg;
00154         default_new = false;
00155         omit_new = false;
00156         foreign_sess_dir = false;
00157         break;
00158       case 'N':
00159         omit_new = true;
00160         newver = "1";
00161         default_new = false;
00162         foreign_sess_dir = false;
00163         break;
00164       case 'F':
00165         foreign_sess_dir = true;
00166         omit_new = true;
00167         newver = "1";
00168         default_new = false;
00169         default_sess = false;
00170         break;
00171       case 's':
00172         sessdir = optarg;
00173         default_sess = false;
00174         break;
00175       case 'S':
00176         omit_sess = true;
00177         break;
00178       case 'u':
00179         uniquify_nondefault_sess = true;
00180         break;
00181       case 'w':
00182         workdir = optarg;
00183         default_work = false;
00184         break;
00185       case 'W':
00186         omit_work = true;
00187         break;
00188       case 'm':
00189         message = optarg;
00190         omit_msg = false;
00191         if(message == "-") {
00192           message = "";
00193           prompt_msg = true;
00194         }
00195         else 
00196           prompt_msg = false;
00197         break;
00198       case 'M':
00199         omit_msg = true;
00200         prompt_msg = false;
00201         break;
00202       case 'h':
00203         hints = optarg;
00204         break;
00205       case 'R':
00206         repos = optarg;
00207         default_repos = false;
00208         break;
00209       case '?':
00210       default:
00211         usage();
00212         /* not reached */
00213       }
00214     }
00215         
00216     switch (argc - optind) {
00217     case 1:
00218       pkg = argv[optind];
00219       break;
00220     case 0:
00221       pkg = ".";
00222       break;
00223     default:
00224       usage();
00225       /* not reached */
00226     }
00227 
00228     if(foreign_sess_dir && foreignsessdirpar.Empty())
00229       {
00230         cerr << program_name
00231              << (": [UserInterface]ForeignParent not set; "
00232                  "-F flag requires config setting") << endl;
00233         exit(1);
00234       }
00235 
00236     
00237     //
00238     // Use a nondefault repository if specified, and automatically
00239     // add it to the hints if not already present.
00240     //
00241     if (!default_repos) {
00242       int colon = repos.FindCharR(':');
00243       if (colon == -1) {
00244         lhost = repos;
00245         repos = repos + ":" + lport;
00246       } else {
00247         lhost = repos.Sub(0, colon);
00248         lport = repos.Sub(colon+1);
00249       }
00250       hints = hints + " " + repos;
00251     }
00252 
00253     // add to hints default repositories from vesta.cfg 
00254     hints = hints + " " + defhints;
00255     
00256     // get change history message
00257     if (!query && prompt_msg) {  
00258       message = ReposUI::getMessage("checkout description");
00259     }
00260 
00261     //
00262     // Canonicalize pkg
00263     //
00264     Text cpkg = ReposUI::canonicalize(pkg, defpkgpar);
00265 
00266     // in a case of making a checkout -F of a foreign branch the -F flag 
00267     // should not be set since it will cause creation of multiple 
00268     // foreign dirs  
00269     if((foreign_sess_dir) && 
00270        (cpkg.Sub(0, foreignsessdirpar.Length()) == foreignsessdirpar)) {
00271       foreign_sess_dir = false;
00272       if(sessdir.Empty())
00273         default_sess = true;
00274     }
00275 
00276     // set special flag for foreign checkout to a not default derectory 
00277     if(foreign_sess_dir && !sessdir.Empty()) {
00278       foreign_not_default = true;
00279       foreign_sess_dir = false;
00280     }
00281 
00282     //
00283     // Compute defaults for oldver and/or newver
00284     //
00285     if (default_old || default_new) {
00286       // Search for the highest version number in use (counting
00287       // ghosts, but not counting stubs)
00288       long high;
00289       if(foreign_sess_dir || foreign_not_default) {
00290         VestaSource* vs_pkg = ReposUI::filenameToVS(cpkg, lhost, lport);
00291         high = ReposUI::highver(vs_pkg);
00292       }
00293       else {
00294         VestaSource* vs_mpkg = ReposUI::filenameToMasterVS(cpkg, hints);
00295         high = ReposUI::highver(vs_mpkg, hints, cpkg);
00296       }
00297       if (default_old) {
00298         if (high == -1) {
00299           // No existing versions, pretend old was version 0
00300           omit_old = true;
00301           oldver = "0";
00302         } else {
00303           char valbuf[64];
00304           sprintf(valbuf, "%ld", high);
00305           oldver = valbuf;
00306         }
00307       }
00308       if (default_new) {
00309         // Set newver to next version after highest in use,
00310         // minimum 1.
00311         char valbuf[64];
00312         sprintf(valbuf, "%ld", (high < 0) ? 1 : high + 1);
00313         newver = valbuf;
00314       }
00315     }
00316 
00317     //
00318     // Canonicalize oldver and newver
00319     //
00320     Text coldver, coldverpar, oldverarc;
00321     Text cnewver, cnewverpar, newverarc;
00322     coldver = ReposUI::canonicalize(oldver, cpkg);
00323     ReposUI::split(coldver, coldverpar, oldverarc, "old-version");
00324     if (!omit_new) {
00325       cnewver = ReposUI::canonicalize(newver, cpkg);
00326       ReposUI::split(cnewver, cnewverpar, newverarc, "new-version");
00327     }
00328   
00329     //
00330     // Compute default for sessdir
00331     //
00332     if (default_sess) {
00333       if (!omit_new) {
00334         // Set sessdir to newver with "checkout/" inserted before
00335         // last component.
00336         sessdir = cnewverpar + "/checkout/" + newverarc;
00337       } else {
00338         // Need to make up a unique name, since newver is
00339         // meaningless.  First, test whether oldver comes from a
00340         // checkout session.
00341         if (coldver.FindText("/checkout/") >= 0) {
00342           // Oldver is from a checkout session, so set sessdir to
00343           // oldver with the last "/" changed to a ".", and "." +
00344           // uuser appended.  Later we will further append a
00345           // uniquifying integer ".u" (starting at 1) to this.
00346           sessdir = coldverpar + "." + oldverarc + "." + uuser;
00347         } else {
00348           // Oldver is not from a checkout session, so set sessdir
00349           // to oldver with "checkout/" inserted before the last
00350           // component and "." + uuser appended.  Later we will
00351           // further append a uniquifying integer ".u" (starting
00352           // at 1) to this.
00353           sessdir = coldverpar + "/checkout/" + oldverarc + "." + uuser;
00354         }                        
00355       }
00356     }
00357 
00358     //  
00359     // Compute default for foreign session directory
00360     //
00361     if(foreign_sess_dir) {
00362       assert(omit_new);
00363       // all foreign checkout session directories are placed in the 
00364       // foreignsessdirpar directory that is defined in vesta.cfg 
00365       // (usually /vesta/<current site>/foreign/). 
00366       // foreign_path_par in a case of default foreign sessdir
00367       // is the oldverpar without root, so sessdir
00368       // will contain following path:
00369       // /vesta/<current site>/foreign/<foreign site>/....
00370       Text foreign_path_par;
00371       if(coldverpar.Sub(0, foreignsessdirpar.Length()) == foreignsessdirpar) {
00372         // if oldver is under foreignsessdirpar we need to strip the 
00373         // foreignsessdirpar path in otder to avoid creation of mutiple 
00374         // foreign dirs
00375         foreign_path_par = coldverpar.Sub(foreignsessdirpar.Length());
00376       }
00377       else {
00378         foreign_path_par = 
00379           ReposUI::stripSpecificRoot(coldverpar, ReposUI::VESTA, true);
00380       }
00381       if(coldver.FindText("/checkout/") >= 0) {
00382         sessdir = foreignsessdirpar + foreign_path_par + "." 
00383           + oldverarc + "." + uuser;
00384       }
00385       else {
00386         sessdir = foreignsessdirpar + foreign_path_par + "/checkout/" 
00387           + oldverarc + "." + uuser;
00388       } 
00389     }
00390 
00391     //
00392     // compute foreign session directory using path given by -s 
00393     //
00394     if(foreign_not_default) {
00395       assert(omit_new);
00396       // all foreign checkout session directories are placed in the 
00397       // foreignsessdirpar directory that is defined in vesta.cfg 
00398       // (usually /vesta/<current site>/foreign/). 
00399       // foreign_path_par in a case of not default foreign sessdir
00400       // is the sessdir defined by user in the -s option of command line,
00401       // qualified according to the package path and without the root, 
00402       // so sessdir will contain the following path:
00403       // /vesta/<current site>/foreign/<foreign site>/<pkg>/....
00404       Text csessdir = ReposUI::canonicalize(sessdir, cpkg);
00405       Text foreign_path_par = 
00406         ReposUI::stripSpecificRoot(csessdir, ReposUI::VESTA, true);
00407       sessdir = foreignsessdirpar + foreign_path_par;
00408     }
00409 
00410     //
00411     // Uniquify and canonicalize sessdir
00412     //
00413     Text csessdir, csessdirpar, sessdirarc, cslatest;
00414     VestaSource* vs_msessdirpar = NULL;
00415     if (!omit_sess) {
00416       if(foreign_sess_dir || foreign_not_default) {
00417         // just in case foreignsessdirpar is not properly defined in vesta.cfg
00418         csessdir = ReposUI::canonicalize(sessdir);
00419       }
00420       else {
00421         csessdir = ReposUI::canonicalize(sessdir, cpkg);
00422       }
00423 
00424       ReposUI::split(csessdir, csessdirpar, sessdirarc, "session-dir");
00425       cslatest = csessdirpar + "/latest";
00426 
00427       // find master of sessdir parent
00428       try {
00429          vs_msessdirpar = ReposUI::filenameToMasterVS(csessdirpar, hints);
00430       }
00431       catch (ReposUI::failure f) {
00432         if(foreign_sess_dir || foreign_not_default) {
00433           if(!query) {
00434             Text pathname = csessdirpar.Sub(foreignsessdirpar.Length());
00435             vs_msessdirpar = 
00436               ReposUI::lookupCreatePath(foreignsessdirpar, pathname, hints);
00437             // This directory might have just been created and have no
00438             // type attribute.  Since it's going to be a session directory
00439             // parent, it should have type checkout.
00440             if(!vs_msessdirpar->inAttribs("type", "checkout")) {
00441               vs_msessdirpar->addAttrib("type", "checkout");
00442             }
00443           }
00444         }
00445         else {
00446           throw(f);
00447         }
00448       }
00449 
00450       // uniquify the session dir if needed
00451       if((default_sess && omit_new) ||
00452          (!default_sess && uniquify_nondefault_sess) ||
00453          (foreign_not_default && uniquify_nondefault_sess) ||
00454          foreign_sess_dir) 
00455         {
00456           if(vs_msessdirpar) 
00457             {
00458               sessdirarc = ReposUI::uniquify(vs_msessdirpar, sessdirarc);
00459               csessdir = csessdirpar + "/" + sessdirarc;
00460             }
00461           else 
00462             { // Can happen only in "-Q -F" case, when session parent dir 
00463               // does not exist and should be created but was not because of 
00464               // the Query flag.
00465               csessdir = csessdirpar + "/" + sessdirarc + ".1";
00466             }
00467         }
00468     }
00469 
00470     //
00471     // Compute default for workdir
00472     //
00473     if (default_work) {
00474       // Get last arc of absolute package name that does not
00475       // begin with a digit
00476       int i, j;
00477       j = cpkg.Length();
00478       for (;;) {
00479         i = cpkg.FindCharR('/', j-1);
00480         if (i == -1) {
00481           // Should not happen
00482           cerr << program_name
00483                << ": can't find base package name in " << cpkg << endl;
00484           exit(2);
00485         }
00486         if (!isdigit(cpkg[i+1])) {
00487           workdir = cpkg.Sub(i+1, j-i-1);
00488           break;
00489         }
00490         j = i;
00491       }
00492     }
00493 
00494     //
00495     // Canonicalize workdir
00496     //
00497     Text cworkdir, cworkdirpar, workdirarc;
00498     if (!omit_work) {
00499       cworkdir = ReposUI::canonicalize(workdir, defworkpar + "/" + user);
00500       ReposUI::split(cworkdir, cworkdirpar, workdirarc, "work-dir");
00501     }
00502 
00503     //
00504     // Look up oldver, first replicating here if needed
00505     //
00506     VestaSource* vs_oldver = NULL;
00507     if (!omit_old) {
00508       VestaSource* vs_roldver = ReposUI::filenameToRealVS(coldver, hints);
00509       if (vs_roldver->type == VestaSource::stub) {
00510         cerr << program_name << ": " << coldver
00511              << " is still checked out";
00512         char *owner = vs_roldver->getAttrib("checkout-by");
00513         if(owner)
00514           {
00515             cerr << " by " << owner;
00516             delete owner;
00517           }
00518         char *dest = vs_roldver->getAttrib("checkout-to");
00519         if(dest)
00520           {
00521             cerr << " at " << dest;
00522             delete dest;
00523           }
00524         cerr << endl;
00525         exit(2);
00526       } else if (vs_roldver->type == VestaSource::ghost) {
00527         cerr << program_name << ": " << coldver
00528              << " has been deleted" << endl;
00529         exit(2);
00530       }
00531       if (vs_roldver->host() == lhost && vs_roldver->port() == lport) {
00532         // A local replica exists
00533         vs_oldver = vs_roldver;
00534       } else if (!query) {
00535         // Get a local replica
00536         if (!quiet) {
00537           cout << "Replicating " << coldver << " from "
00538                << vs_roldver->host() << ":" << vs_roldver->port() << endl;
00539         }
00540         Replicator repl(vs_roldver->host(), vs_roldver->port(), lhost, lport);
00541         Replicator::DirectiveSeq direcs;
00542         Replicator::Directive d('+', coldver.Sub(vlen));
00543         direcs.addhi(d);
00544         repl.replicate(&direcs, rflags);
00545         vs_oldver = ReposUI::filenameToVS(coldver, lhost, lport);
00546       }
00547     }
00548 
00549     //
00550     // Look up master of newverpar and sanity check
00551     //
00552     VestaSource* vs_mnewverpar = NULL;
00553     Text hint_dir;
00554     if (!omit_new) {
00555       vs_mnewverpar = ReposUI::filenameToMasterVS(cnewverpar, hints);
00556       if (!force && !vs_mnewverpar->inAttribs("type", "package")) {
00557         cerr << program_name << ": " << cnewverpar << " at "
00558              << vs_mnewverpar->host() << ":" << vs_mnewverpar->port()
00559              << " is not a package or branch" << endl;
00560         exit(2);
00561       }
00562       // check if the cnewver is not reserved by someone else 
00563       VestaSource* vs_newver = NULL;
00564       VestaSource::errorCode err =
00565         vs_mnewverpar->lookup(newverarc.chars(), vs_newver);
00566       if(err == VestaSource::ok) {
00567         assert(vs_newver->type == VestaSource::stub);
00568         cerr << program_name << ": error: " << cnewver 
00569              << " is already reserved";
00570         char* owner = vs_newver->getAttrib("checkout-by");
00571         if (owner) {
00572           cerr << " by " << owner;
00573           delete owner;
00574         }
00575         char* dest = vs_newver->getAttrib("checkout-to");
00576         if (dest) {
00577           cerr << " at " << dest;
00578           delete dest;
00579         }
00580         char* time = vs_newver->getAttrib("checkout-time");
00581         if(time) {
00582           cerr << " on " << time;
00583           delete time;
00584         }
00585         char* msg = vs_newver->getAttrib("message");
00586         if(msg) {
00587           cerr << " comment: " << msg;
00588           delete msg;
00589         }
00590         cerr << endl;
00591         exit(2);
00592       } 
00593 
00594       if (!quiet) {
00595         cout << "Reserving version " << cnewver;
00596         if (vs_mnewverpar->host() != lhost ||
00597             vs_mnewverpar->port() != lport) {
00598           cout << " at "
00599                << vs_mnewverpar->host() << ":" << vs_mnewverpar->port();
00600         }
00601         cout << endl;
00602       }
00603       
00604       // find directory whose master-repository attribute needs to be updated
00605       hint_dir = ReposUI::getMasterHintDir(vs_mnewverpar, cnewverpar);
00606     }
00607 
00608     //
00609     // Look up master of sessdirpar and sanity check
00610     //
00611     Text sess_hint_dir;
00612     if (!omit_sess) {
00613       // master of sessdir parent should be found in previous step
00614       // unless -Q -F flags are set and session dir parent does not exist
00615 
00616       if(vs_msessdirpar && !force && 
00617          !vs_msessdirpar->inAttribs("type", "checkout")) {
00618         cerr << program_name << ": " << csessdirpar << " at "
00619              << vs_msessdirpar->host() << ":" << vs_msessdirpar->port()
00620              << " is not a checkout directory" << endl;
00621         exit(2);
00622       }
00623       if(!quiet) {
00624         cout << "Creating session " << csessdir;
00625         if(vs_msessdirpar && (
00626            vs_msessdirpar->host() != lhost ||
00627            vs_msessdirpar->port() != lport)) {
00628           cout << " at "
00629                << vs_msessdirpar->host() << ":" << vs_msessdirpar->port();
00630         }
00631         cout << endl;
00632       }
00633       // find directory whose master-repository attribute needs to be updated
00634       if(vs_msessdirpar) {
00635         sess_hint_dir = ReposUI::getMasterHintDir(vs_msessdirpar, csessdirpar);
00636         if(!omit_new && (sess_hint_dir == hint_dir))
00637           // Don't try to update the master-repository attribute on the
00638           // same directory twice.
00639           sess_hint_dir = "";
00640       }
00641     }
00642 
00643     //
00644     // Look up workdirpar, creating it if necessary
00645     //
00646     VestaSource* vs_workdirpar = NULL;
00647     if (!omit_work) {
00648       try {
00649         vs_workdirpar = ReposUI::filenameToVS(cworkdirpar, lhost, lport);
00650       } catch (ReposUI::failure f) {
00651         // Try to auto-create workdirpar if it does not exist
00652         if (!query &&
00653             (f.uerrno == ENOENT || f.code == VestaSource::notFound)) {
00654           Text cworkdirparpar, workdirpararc;
00655           ReposUI::split(cworkdirpar, cworkdirparpar, workdirpararc,
00656                          "work-dir parent");
00657           VestaSource* vs_workdirparpar =
00658             ReposUI::filenameToVS(cworkdirparpar, lhost, lport);
00659           VestaSource::errorCode err = vs_workdirparpar->
00660             insertMutableDirectory(workdirpararc.cchars(), NULL, true,
00661                                    NULL, VestaSource::dontReplace,
00662                                    &vs_workdirpar);
00663           if (err != VestaSource::ok) {
00664             cerr << program_name << ": error creating "
00665                  << cworkdirpar << ": "
00666                  << ReposUI::errorCodeText(err) << endl;
00667             exit(2);
00668           }
00669           err = vs_workdirpar->setAttrib("#mode", mode);
00670           assert(err == VestaSource::ok);
00671         } else {
00672           throw;
00673         }
00674       }
00675       if (vs_workdirpar && default_work) {
00676         // Make name unique by adding numeric suffix if needed
00677         VestaSource* vs_dummy;
00678         VestaSource::errorCode err = 
00679           vs_workdirpar->lookup(workdirarc.cchars(), vs_dummy);
00680         if (err != VestaSource::notFound) {
00681           workdirarc = ReposUI::uniquify(vs_workdirpar, workdirarc);
00682         }
00683         cworkdir = cworkdirpar + "/" + workdirarc;
00684       }
00685       if (!quiet) {
00686         cout << "Making working directory " << cworkdir << endl;
00687       }
00688     }
00689 
00690     if (query) {
00691       cerr << program_name << ": nothing done (-Q flag given)" << endl;
00692       exit(0);
00693     }
00694 
00695     // Make sure we have the parent directories where we're going to
00696     // create things.
00697     if(!omit_sess) assert(vs_msessdirpar);
00698     if(!omit_new) assert(vs_mnewverpar);
00699     if(!omit_work) assert(vs_workdirpar);
00700 
00701     //
00702     // Ready to construct the remote atomic action(s) and replicate
00703     // the results here.  May need to reference zero, one, or two
00704     // remote hosts.  If only one host is involved, we arrange to use
00705     // only one action and one call to the replicator.
00706     //
00707     VestaSourceAtomic* rvsa1 = NULL;
00708     VestaSourceAtomic* rvsa2 = NULL;
00709     Replicator* repl1 = NULL;
00710     Replicator* repl2 = NULL;
00711     Replicator::DirectiveSeq* direcs1 = NULL;
00712     Replicator::DirectiveSeq* direcs2 = NULL;
00713     // VS pointers and VSIndex for old version copies in each one of
00714     // two remote repositories
00715     VestaSource *vs_roldver1 = NULL, *vs_roldver2 = NULL;
00716     VestaSourceAtomic::VSIndex vsi_roldver1 = -1, vsi_roldver2 = -1;
00717 
00718     //
00719     // If needed, construct action to create newver remotely
00720     // and replicator directives to replicate it here.
00721     //
00722     VestaSource* vs_newverpar = NULL;
00723     VestaSource* vs_newver = NULL;
00724     if (!omit_new) {
00725       if (vs_mnewverpar->host() == lhost &&
00726           vs_mnewverpar->port() == lport) {
00727         // Master is local
00728         vs_newverpar = vs_mnewverpar;
00729       } else {
00730         // Master is remote
00731         rvsa1 = NEW_CONSTR(VestaSourceAtomic, (vs_mnewverpar->host(),
00732                                                vs_mnewverpar->port()));
00733         VestaSourceAtomic::VSIndex vsi_mnewverpar =
00734           rvsa1->decl(cnewverpar, vs_mnewverpar);
00735         VestaSourceAtomic::VSIndex vsi_mnewver =
00736           rvsa1->insertStub(cnewver, vsi_mnewverpar, newverarc,
00737                             true, VestaSource::dontReplace);
00738         if (!omit_old) {
00739           rvsa1->setAttrib(cnewver, vsi_mnewver, "old-version", coldver);
00740 
00741           // add next-versions attribute to the old version (newverpar repos)
00742           try {
00743             vs_roldver1 = ReposUI::filenameToVS(coldver, vs_mnewverpar->host(),
00744                                                 vs_mnewverpar->port());
00745             vsi_roldver1 = rvsa1->decl(coldver, vs_roldver1);
00746             rvsa1->setTarget("", VestaSource::ok, VestaSource::noPermission);
00747             rvsa1->addAttrib(coldver + ": adding to next-versions",
00748                              vsi_roldver1, 
00749                              "next-versions", cnewver);
00750             rvsa1->setTarget("");
00751           }
00752           catch(ReposUI::failure){
00753             // there is no old version copy in newverpar repos
00754             vs_roldver1 = NULL;
00755           }
00756         }
00757         if (!omit_sess) {
00758           rvsa1->setAttrib(cnewver, vsi_mnewver, "session-dir", csessdir);
00759         }
00760         if(!omit_msg && !message.Empty()){
00761           rvsa1->setAttrib(cnewver, vsi_mnewver, "message", message);
00762         }
00763         rvsa1->setAttrib(cnewver, vsi_mnewver, "checkout-time", timebuf);
00764         rvsa1->setAttrib(cnewver, vsi_mnewver, "checkout-by", cuser);
00765         rvsa1->setAttrib(cnewver, vsi_mnewver, "checkout-from",
00766                          vs_mnewverpar->host() + ":" + vs_mnewverpar->port());
00767         rvsa1->setAttrib(cnewver, vsi_mnewver, "checkout-to",
00768                          lhost + ":" + lport);
00769         rvsa1->setAttrib(cnewver, vsi_mnewver, "#mode", mode);
00770 
00771         repl1 = NEW_CONSTR(Replicator, (vs_mnewverpar->host(),
00772                                         vs_mnewverpar->port(),
00773                                         lhost, lport));
00774         direcs1 = NEW(Replicator::DirectiveSeq);
00775         Replicator::Directive d('+', cnewver.Sub(vlen));
00776         direcs1->addhi(d);
00777       }
00778     }
00779 
00780     //
00781     // If needed, construct action to create sessdir remotely
00782     // and replicator directives to replicate it here.
00783     //
00784     VestaSource* vs_sessdirpar = NULL;
00785     VestaSource* vs_sessdir = NULL;
00786     if (!omit_sess) {
00787       if (vs_msessdirpar->host() == lhost &&
00788           vs_msessdirpar->port() == lport) {
00789         // Master is local
00790         vs_sessdirpar = vs_msessdirpar;
00791       } else {
00792         // Master is remote
00793         if (rvsa1 != NULL &&
00794             vs_msessdirpar->host() == vs_mnewverpar->host() &&
00795             vs_msessdirpar->port() == vs_mnewverpar->port()) {
00796           rvsa2 = rvsa1;
00797           repl2 = repl1;
00798           direcs2 = direcs1;
00799           // In this case we can re-use the VestaSource and VSIndex
00800           // for the old-version, since the repository and atomic
00801           // action are the same.
00802           vs_roldver2 = vs_roldver1;
00803           vsi_roldver2 = vsi_roldver1;
00804         } else {
00805           rvsa2 = NEW_CONSTR(VestaSourceAtomic, (vs_msessdirpar->host(),
00806                                                  vs_msessdirpar->port()));
00807           repl2 = NEW_CONSTR(Replicator, (vs_msessdirpar->host(),
00808                                           vs_msessdirpar->port(),
00809                                           lhost, lport));
00810           direcs2 = NEW(Replicator::DirectiveSeq);
00811           if(!omit_old)
00812             {
00813               // Look up old version in session directory parent
00814               // master.
00815               try
00816                 {
00817                   vs_roldver2 =
00818                     ReposUI::filenameToVS(coldver, 
00819                                           vs_msessdirpar->host(),
00820                                           vs_msessdirpar->port());
00821                 }
00822               catch(ReposUI::failure)
00823                 {
00824                   // there is no old version copy in sessdirpar repos
00825                   vs_roldver2 = NULL;
00826                 }
00827             }
00828         }
00829         VestaSourceAtomic::VSIndex vsi_msessdirpar =
00830           rvsa2->decl(csessdirpar, vs_msessdirpar);
00831         VestaSourceAtomic::VSIndex vsi_msessdir =
00832           rvsa2->insertAppendableDirectory(csessdir, vsi_msessdirpar,
00833                                            sessdirarc, true,
00834                                            VestaSource::dontReplace);
00835         if (!omit_old) {
00836           rvsa2->setAttrib(csessdir, vsi_msessdir, "old-version", coldver);
00837           // add next-sessions attribute to the old version (sessdirpar repos)
00838           if(vs_roldver2)
00839             {
00840               if(vsi_roldver2 == -1)
00841                 vsi_roldver2 = rvsa2->decl(coldver, vs_roldver2);
00842               rvsa2->setTarget("", VestaSource::ok, VestaSource::noPermission);
00843               rvsa2->addAttrib(coldver + ": adding to next-sessions",
00844                                vsi_roldver2, 
00845                                "next-sessions", csessdir);
00846               rvsa2->setTarget("");
00847             }
00848         }
00849         if (!omit_new) {
00850           rvsa2->setAttrib(csessdir, vsi_msessdir, "new-version", cnewver);
00851         }
00852         if(!omit_msg && !message.Empty()) {
00853           rvsa2->setAttrib(csessdir, vsi_msessdir, "message", message);
00854         }
00855 
00856         rvsa2->setAttrib(csessdir, vsi_msessdir, "checkout-time", timebuf);
00857         rvsa2->setAttrib(csessdir, vsi_msessdir, "checkout-by", cuser);
00858         rvsa2->setAttrib(csessdir, vsi_msessdir, "checkout-from",
00859                          (vs_msessdirpar->host() + ":" +
00860                           vs_msessdirpar->port()));
00861         rvsa2->setAttrib(csessdir, vsi_msessdir, "checkout-to",
00862                          (lhost + ":" + lport));
00863         rvsa2->setAttrib(csessdir, vsi_msessdir, "type", "session");
00864         rvsa2->setAttrib(csessdir, vsi_msessdir, "#mode", mode);
00865 
00866         Replicator::Directive d1('+', csessdir.Sub(vlen));
00867         Replicator::Directive d2('+', cslatest.Sub(vlen));
00868         direcs2->addhi(d1);
00869         direcs2->addhi(d2);
00870       }
00871     }
00872 
00873     //
00874     // Disable ^C signal to make it less likely that we will be
00875     // killed after having done one or more remote actions but
00876     // before having finished the whole job.
00877     //
00878     signal(SIGINT, SIG_IGN);
00879 
00880     //
00881     // Run the remote action(s) and replication(s)
00882     //
00883     if (rvsa1) {
00884       if (!rvsa1->run()) {
00885         VestaSource::errorCode err;
00886         if (rvsa1->lasterr == VestaSource::ok) {
00887           err = rvsa1->okreplace;
00888         } else {
00889           err = rvsa1->lasterr;
00890         }
00891         cerr << program_name << ": " << rvsa1->name(rvsa1->ndone) << " at "
00892              << vs_mnewverpar->host() << ":" << vs_mnewverpar->port()
00893              << ": " << ReposUI::errorCodeText(err) << endl;
00894         exit(2);
00895       }
00896       repl1->replicate(direcs1, rflags);
00897     }
00898     if (rvsa2 && rvsa2 != rvsa1) {
00899       if (!rvsa2->run()) {
00900         VestaSource::errorCode err;
00901         if (rvsa2->lasterr == VestaSource::ok) {
00902           err = rvsa2->okreplace;
00903         } else {
00904           err = rvsa2->lasterr;
00905         }
00906         cerr << program_name << ": " << rvsa2->name(rvsa2->ndone) << " at "
00907              << vs_msessdirpar->host() << ":" << vs_msessdirpar->port()
00908              << ": " << ReposUI::errorCodeText(err) << endl;
00909         exit(2);
00910       }
00911       repl2->replicate(direcs2, rflags);
00912     }
00913 
00914     // check if the next_versions attribute was added to the old
00915     // version(newverpar repos)
00916     if(vs_roldver1 && !quiet) {
00917       assert(!omit_new);
00918       if(!vs_roldver1->inAttribs("next-versions", cnewver.cchars())) {
00919         cerr << program_name << ": warning: "
00920           "next-versions attribute couldn't be added to version: "
00921              << coldver << " at " << vs_mnewverpar->host() << ":" 
00922              << vs_mnewverpar->port() << endl;
00923       }
00924     }
00925     // check if the next_sessions attribute was added to the old
00926     // version(sessdirpar repos)
00927     if(vs_roldver2 && !quiet) {
00928       assert(!omit_sess);
00929       if(!vs_roldver2->inAttribs("next-sessions", csessdir.cchars())) {
00930         cerr << program_name << ": warning: " 
00931           "next-sessions attribute couldn't be added to version: " << coldver
00932              << " at " << vs_msessdirpar->host() << ":" 
00933              << vs_msessdirpar->port() << endl;
00934       }
00935     }
00936 
00937     //
00938     // Do the mastership transfer(s)
00939     //
00940     if (!omit_new && vs_newverpar == NULL) {
00941       VestaSource::errorCode err =
00942         VDirSurrogate::acquireMastership(cnewver.Sub(vlen).cchars(),
00943                                          lhost, lport,
00944                                          vs_mnewverpar->host(),
00945                                          vs_mnewverpar->port());
00946       if (err != VestaSource::ok) {
00947         cerr << program_name << ": error acquiring mastership of "
00948              << cnewver << ": " << ReposUI::errorCodeText(err) << endl;
00949         exit(2);
00950       }
00951       vs_newverpar = ReposUI::filenameToVS(cnewverpar, lhost, lport);
00952       vs_newver = ReposUI::filenameToVS(cnewver, lhost, lport);
00953     }
00954     if (!omit_sess && vs_sessdirpar == NULL) {
00955       VestaSource::errorCode err =
00956         VDirSurrogate::acquireMastership(csessdir.Sub(vlen).cchars(),
00957                                          lhost, lport,
00958                                          vs_msessdirpar->host(),
00959                                          vs_msessdirpar->port());
00960       if (err != VestaSource::ok) {
00961         cerr << program_name << ": error acquiring mastership of "
00962              << csessdir << ": " << ReposUI::errorCodeText(err) << endl;
00963         exit(2);
00964       }
00965       vs_sessdirpar = ReposUI::filenameToVS(csessdirpar, lhost, lport);
00966       vs_sessdir = ReposUI::filenameToVS(csessdir, lhost, lport);
00967     }
00968 
00969     //
00970     // Construct the local atomic action
00971     //
00972     VestaSourceAtomic vsa(lhost, lport);
00973     VestaSourceAtomic::VSIndex vsi_oldver = -1, vsi_newverpar = -1,
00974       vsi_sessdirpar = -1, vsi_workdirpar = -1,
00975       vsi_newver = -1, vsi_sessdir = -1;
00976 
00977     // Do all error checking first, because once the atomic program
00978     // starts making changes, it can't roll back unless the
00979     // repository crashes.
00980     if (!omit_old) {
00981       vsi_oldver = vsa.decl(coldver, vs_oldver);
00982       vsa.typeCheck(coldver, vsi_oldver, VestaSourceAtomic::
00983                     typebit(VestaSource::immutableDirectory),
00984                     VestaSource::inappropriateOp);
00985       vsa.accessCheck(coldver, vsi_oldver, AccessControl::read,
00986                       true, VestaSource::noPermission);
00987     }
00988 
00989     Text master_hint;
00990     VestaSource* vs_hint = NULL;
00991     if (!omit_new) {
00992       vsi_newverpar = vsa.decl(cnewverpar, vs_newverpar);
00993       if (vs_newver) {
00994         // newver already exists
00995         vsi_newver = vsa.decl(cnewver, vs_newver);
00996         vsa.typeCheck(cnewver, vsi_newver, VestaSourceAtomic::
00997                       typebit(VestaSource::stub),
00998                       VestaSource::inappropriateOp);
00999         vsa.testMaster(cnewver, vsi_newver, true, VestaSource::notMaster);
01000         vsa.accessCheck(cnewver, vsi_newver, AccessControl::write, true,
01001                         VestaSource::noPermission);
01002       } else {
01003         // newver will be created in newverpar
01004         vsa.typeCheck(cnewverpar, vsi_newverpar, VestaSourceAtomic::
01005                       typebit(VestaSource::appendableDirectory),
01006                       VestaSource::inappropriateOp);
01007         vsa.testMaster(cnewverpar, vsi_newverpar, true,
01008                        VestaSource::notMaster);
01009         vsa.accessCheck(cnewverpar, vsi_newverpar, AccessControl::write, true,
01010                         VestaSource::noPermission);
01011         // Be sure new version doesn't already exist
01012         vsa.setTarget("", VestaSource::notFound,
01013                       VestaSource::notFound, VestaSource::nameInUse);
01014         vsa.lookup(cnewver, vsi_newverpar, newverarc);
01015         vsa.setTarget("");
01016       }
01017 
01018       // Update master-repository hint of newverpar or its ancestor
01019       master_hint = vs_mnewverpar->host() + ":" + vs_mnewverpar->port();
01020       vs_hint = ReposUI::filenameToVS(hint_dir, lhost, lport);
01021       if(!vs_hint->inAttribs("master-repository", master_hint.cchars())) {
01022         VestaSourceAtomic::VSIndex vsi_hint = 
01023           vsa.decl("update master hint on " + hint_dir, vs_hint);
01024         vsa.setTarget("", VestaSource::ok, VestaSource::noPermission);
01025         vsa.setAttrib("update master hint on " + hint_dir, vsi_hint,
01026                       "master-repository", master_hint);
01027         vsa.setTarget("");
01028       }
01029     }
01030 
01031     Text sessdir_master_hint; 
01032     VestaSource* vs_sess_hint = NULL;
01033     if (!omit_sess) {
01034       vsi_sessdirpar = vsa.decl(csessdirpar, vs_sessdirpar);
01035       if (vs_sessdir) {
01036         // sessdir already exists
01037         vsi_sessdir = vsa.decl(csessdir, vs_sessdir);
01038         vsa.typeCheck(csessdir, vsi_sessdir, VestaSourceAtomic::
01039                       typebit(VestaSource::appendableDirectory),
01040                       VestaSource::inappropriateOp);
01041         vsa.testMaster(csessdir, vsi_sessdir, true, VestaSource::notMaster);
01042         vsa.accessCheck(csessdir, vsi_sessdir, AccessControl::write, true,
01043                         VestaSource::noPermission);
01044 
01045       } else {
01046         // sessdir will be created in sessdirpar
01047         vsa.typeCheck(csessdirpar, vsi_sessdirpar, VestaSourceAtomic::
01048                       typebit(VestaSource::appendableDirectory),
01049                       VestaSource::inappropriateOp);
01050         vsa.testMaster(csessdirpar, vsi_sessdirpar, true,
01051                        VestaSource::notMaster);
01052         vsa.accessCheck(csessdirpar, vsi_sessdirpar, AccessControl::write,
01053                         true, VestaSource::noPermission);
01054         // Be sure sessdir doesn't already exist
01055         vsa.setTarget("", VestaSource::notFound,
01056                       VestaSource::notFound, VestaSource::nameInUse);
01057         vsa.lookup(csessdir, vsi_sessdirpar, sessdirarc);
01058         vsa.setTarget("setTarget");
01059       }
01060 
01061       // Update master-repository hint of sessdirpar or its ancestor
01062       if(!sess_hint_dir.Empty())
01063         {
01064           sessdir_master_hint = 
01065             vs_msessdirpar->host() + ":" + vs_msessdirpar->port();
01066           vs_sess_hint = ReposUI::filenameToVS(sess_hint_dir, lhost, lport);
01067           if(!vs_sess_hint->inAttribs("master-repository", 
01068                                       sessdir_master_hint.cchars())) {
01069             VestaSourceAtomic::VSIndex vsi_sesshint = 
01070               vsa.decl("update master hint on " + sess_hint_dir, vs_sess_hint);
01071             vsa.setTarget("", VestaSource::ok, VestaSource::noPermission);
01072             vsa.setAttrib("update master hint on " + sess_hint_dir,
01073                           vsi_sesshint,
01074                           "master-repository", sessdir_master_hint);
01075             vsa.setTarget("");
01076           }
01077         }
01078     }
01079     
01080 
01081     if (!omit_work) {
01082       vsi_workdirpar = vsa.decl(cworkdirpar, vs_workdirpar);
01083       vsa.typeCheck(cworkdirpar, vsi_workdirpar, VestaSourceAtomic::
01084                     typebit(VestaSource::mutableDirectory),
01085                     VestaSource::inappropriateOp);
01086       vsa.accessCheck(cworkdirpar, vsi_workdirpar, AccessControl::write, true,
01087                       VestaSource::noPermission);
01088       // Be sure workdir doesn't already exist
01089       vsa.setTarget("", VestaSource::notFound,
01090                     VestaSource::notFound, VestaSource::nameInUse);
01091       vsa.lookup(cworkdir, vsi_workdirpar, workdirarc);
01092       vsa.setTarget("");
01093     }
01094         
01095     // All is well if atomic program runs up to this step; start
01096     // making the changes.
01097     if (!omit_new) {
01098       if (!vs_newver) {
01099         // Insert reservation stub for newver
01100         vsi_newver =
01101           vsa.insertStub(cnewver, vsi_newverpar, newverarc,
01102                          true, VestaSource::dontReplace);
01103       }
01104 
01105       // Set attributes on newver stub
01106       if (!omit_old) {
01107         vsa.setAttrib(cnewver, vsi_newver, "old-version", coldver);
01108         // add next-versions attribute to the old version (local)
01109         vsa.setTarget("", VestaSource::ok, VestaSource::noPermission);
01110         vsa.addAttrib(coldver + ": adding to next-versions", vsi_oldver, 
01111                       "next-versions", cnewver);
01112         vsa.setTarget("");
01113       }
01114       if (!omit_sess) {
01115         vsa.setAttrib(cnewver, vsi_newver, "session-dir", csessdir);
01116       }
01117       if (!omit_work) {
01118         vsa.setAttrib(cnewver, vsi_newver, "work-dir", cworkdir);
01119       }
01120       if(!omit_msg && !message.Empty()) {
01121         vsa.setAttrib(cnewver, vsi_newver, "message", message);
01122       }
01123       vsa.setAttrib(cnewver, vsi_newver, "checkout-time", timebuf);
01124       vsa.setAttrib(cnewver, vsi_newver, "checkout-by", cuser);
01125       vsa.setAttrib(cnewver, vsi_newver, "#mode", mode);
01126     }
01127 
01128     if (!omit_sess) {
01129       if (!vs_sessdir) {
01130         // Insert session directory
01131         vsi_sessdir =
01132           vsa.insertAppendableDirectory(csessdir, vsi_sessdirpar, sessdirarc,
01133                                         true, VestaSource::dontReplace);
01134       }
01135       // Set attribs on session directory
01136       if (!omit_old) {
01137         vsa.setAttrib(csessdir, vsi_sessdir, "old-version", coldver);
01138         // add next-sessions attribute to the old version (local)
01139         vsa.setTarget("", VestaSource::ok, VestaSource::noPermission);
01140         vsa.addAttrib(coldver + ": adding to next-sessions", vsi_oldver, 
01141                       "next-sessions", csessdir);
01142         vsa.setTarget("");
01143       }
01144       if (!omit_new) {
01145         vsa.setAttrib(csessdir, vsi_sessdir, "new-version", cnewver);
01146       }
01147       if(!omit_msg && !message.Empty()) {
01148         vsa.setAttrib(csessdir, vsi_sessdir, "message", message);
01149       }
01150       if (!omit_work) {
01151         vsa.setAttrib(csessdir, vsi_sessdir, "work-dir", cworkdir);
01152       }
01153       vsa.setAttrib(csessdir, vsi_sessdir, "checkout-time", timebuf);
01154       vsa.setAttrib(csessdir, vsi_sessdir, "checkout-by", cuser);
01155       vsa.setAttrib(csessdir, vsi_sessdir, "type", "session");
01156       vsa.setAttrib(csessdir, vsi_sessdir, "#mode", mode);
01157 
01158       // Insert session version 0
01159       Text csessver0 = csessdir + "/0";
01160       if (!omit_old) {
01161         vsa.insertImmutableDirectory(csessver0, vsi_sessdir, "0", vsi_oldver,
01162                                      true, VestaSource::dontReplace);
01163       }
01164 
01165       // Insert "latest" link in session
01166       Text clatest = csessdir + "/latest";
01167       VestaSourceAtomic::VSIndex vsi_latest =
01168         vsa.insertStub(clatest, vsi_sessdir, "latest", true,
01169                        VestaSource::dontReplace);
01170       vsa.setAttrib(clatest, vsi_latest, "symlink-to", "$LAST");
01171     }
01172 
01173     if (!omit_work) {
01174       // Insert working directory
01175       // Note: okay for vsi_oldver to be -1 here;
01176       // this makes workdir empty.
01177       VestaSourceAtomic::VSIndex vsi_workdir =
01178         vsa.insertMutableDirectory(cworkdir, vsi_workdirpar, workdirarc,
01179                                    vsi_oldver, true, VestaSource::dontReplace);
01180       // Set attribs on workdir
01181       if (!omit_old) {
01182         vsa.setAttrib(cworkdir, vsi_workdir, "old-version", coldver);
01183       }
01184       if (!omit_new) {
01185         vsa.setAttrib(cworkdir, vsi_workdir, "new-version", cnewver);
01186       }
01187       if (!omit_sess) {
01188         vsa.setAttrib(cworkdir, vsi_workdir, "session-dir", csessdir);
01189         if (!omit_old) {
01190           vsa.setAttrib(cworkdir, vsi_workdir, "session-ver-arc", "0");
01191         }
01192       }
01193       vsa.setAttrib(cworkdir, vsi_workdir, "checkout-time", timebuf);
01194       vsa.setAttrib(cworkdir, vsi_workdir, "checkout-by", cuser);
01195     }
01196 
01197     //
01198     // Run the local action
01199     //
01200     if (!vsa.run()) {
01201       VestaSource::errorCode err;
01202       if (vsa.lasterr == VestaSource::ok) {
01203         err = vsa.okreplace;
01204       } else {
01205         err = vsa.lasterr;
01206       }
01207       cerr << program_name << ": " << vsa.name(vsa.ndone) << ": "
01208            << ReposUI::errorCodeText(err) << endl;
01209       exit(2);
01210     }
01211 
01212     // check if next-versions and/or next-sessions attributes were added 
01213     // to the old version (local)
01214     if(!omit_old && !quiet) {
01215       if(!omit_new) {
01216         if(!vs_oldver->inAttribs("next-versions", cnewver.cchars())) {
01217           cerr << program_name << ": warning: " 
01218             "next-versions attribute couldn't be added to version: "
01219                << coldver;
01220           // Only include the local repository host/port if we're
01221           // doing operations in multiple repositories.
01222           if(rvsa1 || rvsa2)
01223             cerr << " at " << lhost << ":" << lport;
01224           cerr << endl;
01225         }
01226       }
01227       if(!omit_sess) {
01228         if(!vs_oldver->inAttribs("next-sessions", csessdir.cchars())) {
01229           cerr << program_name << ": warning: "
01230             "next-sessions attribute couldn't be added to version: "
01231                << coldver;
01232           // Only include the local repository host/port if we're
01233           // doing operations in multiple repositories.
01234           if(rvsa1 || rvsa2)
01235             cerr << " at " << lhost << ":" << lport;
01236           cerr << endl;
01237         }
01238       }
01239     }
01240     //check if master-repository hint was updated on newverpar or its ancestor
01241     if(!omit_new && !quiet) {
01242       assert(vs_hint != 0);
01243       if(!vs_hint->inAttribs("master-repository", master_hint.cchars()))
01244         cerr << program_name 
01245              << ": warning: incorrect master-repository attribute of " 
01246              << hint_dir << " couldn't be updated (should be "
01247              << master_hint << ")" << endl;
01248     }
01249     //check if master-repository hint was updated on sessdirpar or its ancestor
01250     if(!omit_sess && !quiet && !sess_hint_dir.Empty()) {
01251       assert(vs_sess_hint != 0);
01252       if(!vs_sess_hint->inAttribs("master-repository", 
01253                                   sessdir_master_hint.cchars()))
01254         cerr << program_name 
01255              << ": warning: incorrect master-repository attribute of " 
01256              << sess_hint_dir << " couldn't be updated (should be "
01257              << sessdir_master_hint << ")" << endl;
01258     }
01259 
01260   } catch (VestaConfig::failure f) {
01261     cerr << program_name << ": " << f.msg << endl;
01262     exit(2);
01263   } catch (SRPC::failure f) {
01264     cerr << program_name
01265          << ": SRPC failure; " << f.msg << " (" << f.r << ")" << endl;
01266     exit(2);
01267   } catch (ReposUI::failure f) {
01268     cerr << program_name << ": " << f.msg << endl;
01269     exit(2);
01270   } catch (Replicator::Failure f) {
01271     if (f.code == (VestaSource::errorCode) -1) {
01272       cerr << program_name << ": " << f.msg << endl;
01273     } else {
01274       cerr << program_name << ": " << ReposUI::errorCodeText(f.code)
01275            << ", " << f.msg << endl;
01276     }
01277     exit(2);
01278   } catch(FS::Failure f) {
01279     cerr << program_name << ": " << f << endl;
01280     exit(2);
01281   }
01282   return 0;
01283 }

Generated on Mon May 8 00:48:55 2006 for Vesta by  doxygen 1.4.2