00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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
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
00090 if(VestaConfig::get("UserInterface", "ForeignParent", foreignsessdirpar))
00091 {
00092 foreignsessdirpar = ReposUI::canonicalize(foreignsessdirpar);
00093
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));
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;
00112 const Replicator::Flags rflags = (Replicator::Flags)
00113 (Replicator::attrNew | Replicator::attrOld | Replicator::attrAccess |
00114 Replicator::revive | Replicator::inclStubs | Replicator::latest);
00115
00116
00117
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
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
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
00239
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
00254 hints = hints + " " + defhints;
00255
00256
00257 if (!query && prompt_msg) {
00258 message = ReposUI::getMessage("checkout description");
00259 }
00260
00261
00262
00263
00264 Text cpkg = ReposUI::canonicalize(pkg, defpkgpar);
00265
00266
00267
00268
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
00277 if(foreign_sess_dir && !sessdir.Empty()) {
00278 foreign_not_default = true;
00279 foreign_sess_dir = false;
00280 }
00281
00282
00283
00284
00285 if (default_old || default_new) {
00286
00287
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
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
00310
00311 char valbuf[64];
00312 sprintf(valbuf, "%ld", (high < 0) ? 1 : high + 1);
00313 newver = valbuf;
00314 }
00315 }
00316
00317
00318
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
00331
00332 if (default_sess) {
00333 if (!omit_new) {
00334
00335
00336 sessdir = cnewverpar + "/checkout/" + newverarc;
00337 } else {
00338
00339
00340
00341 if (coldver.FindText("/checkout/") >= 0) {
00342
00343
00344
00345
00346 sessdir = coldverpar + "." + oldverarc + "." + uuser;
00347 } else {
00348
00349
00350
00351
00352
00353 sessdir = coldverpar + "/checkout/" + oldverarc + "." + uuser;
00354 }
00355 }
00356 }
00357
00358
00359
00360
00361 if(foreign_sess_dir) {
00362 assert(omit_new);
00363
00364
00365
00366
00367
00368
00369
00370 Text foreign_path_par;
00371 if(coldverpar.Sub(0, foreignsessdirpar.Length()) == foreignsessdirpar) {
00372
00373
00374
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
00393
00394 if(foreign_not_default) {
00395 assert(omit_new);
00396
00397
00398
00399
00400
00401
00402
00403
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
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
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
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
00438
00439
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
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 {
00463
00464
00465 csessdir = csessdirpar + "/" + sessdirarc + ".1";
00466 }
00467 }
00468 }
00469
00470
00471
00472
00473 if (default_work) {
00474
00475
00476 int i, j;
00477 j = cpkg.Length();
00478 for (;;) {
00479 i = cpkg.FindCharR('/', j-1);
00480 if (i == -1) {
00481
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
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
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
00533 vs_oldver = vs_roldver;
00534 } else if (!query) {
00535
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
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
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
00605 hint_dir = ReposUI::getMasterHintDir(vs_mnewverpar, cnewverpar);
00606 }
00607
00608
00609
00610
00611 Text sess_hint_dir;
00612 if (!omit_sess) {
00613
00614
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
00634 if(vs_msessdirpar) {
00635 sess_hint_dir = ReposUI::getMasterHintDir(vs_msessdirpar, csessdirpar);
00636 if(!omit_new && (sess_hint_dir == hint_dir))
00637
00638
00639 sess_hint_dir = "";
00640 }
00641 }
00642
00643
00644
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
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
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
00696
00697 if(!omit_sess) assert(vs_msessdirpar);
00698 if(!omit_new) assert(vs_mnewverpar);
00699 if(!omit_work) assert(vs_workdirpar);
00700
00701
00702
00703
00704
00705
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
00714
00715 VestaSource *vs_roldver1 = NULL, *vs_roldver2 = NULL;
00716 VestaSourceAtomic::VSIndex vsi_roldver1 = -1, vsi_roldver2 = -1;
00717
00718
00719
00720
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
00728 vs_newverpar = vs_mnewverpar;
00729 } else {
00730
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
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
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
00782
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
00790 vs_sessdirpar = vs_msessdirpar;
00791 } else {
00792
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
00800
00801
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
00814
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
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
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
00875
00876
00877
00878 signal(SIGINT, SIG_IGN);
00879
00880
00881
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
00915
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
00926
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
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
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
00978
00979
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
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
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
01012 vsa.setTarget("", VestaSource::notFound,
01013 VestaSource::notFound, VestaSource::nameInUse);
01014 vsa.lookup(cnewver, vsi_newverpar, newverarc);
01015 vsa.setTarget("");
01016 }
01017
01018
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
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
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
01055 vsa.setTarget("", VestaSource::notFound,
01056 VestaSource::notFound, VestaSource::nameInUse);
01057 vsa.lookup(csessdir, vsi_sessdirpar, sessdirarc);
01058 vsa.setTarget("setTarget");
01059 }
01060
01061
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
01089 vsa.setTarget("", VestaSource::notFound,
01090 VestaSource::notFound, VestaSource::nameInUse);
01091 vsa.lookup(cworkdir, vsi_workdirpar, workdirarc);
01092 vsa.setTarget("");
01093 }
01094
01095
01096
01097 if (!omit_new) {
01098 if (!vs_newver) {
01099
01100 vsi_newver =
01101 vsa.insertStub(cnewver, vsi_newverpar, newverarc,
01102 true, VestaSource::dontReplace);
01103 }
01104
01105
01106 if (!omit_old) {
01107 vsa.setAttrib(cnewver, vsi_newver, "old-version", coldver);
01108
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
01131 vsi_sessdir =
01132 vsa.insertAppendableDirectory(csessdir, vsi_sessdirpar, sessdirarc,
01133 true, VestaSource::dontReplace);
01134 }
01135
01136 if (!omit_old) {
01137 vsa.setAttrib(csessdir, vsi_sessdir, "old-version", coldver);
01138
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
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
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
01175
01176
01177 VestaSourceAtomic::VSIndex vsi_workdir =
01178 vsa.insertMutableDirectory(cworkdir, vsi_workdirpar, workdirarc,
01179 vsi_oldver, true, VestaSource::dontReplace);
01180
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
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
01213
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
01221
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
01233
01234 if(rvsa1 || rvsa2)
01235 cerr << " at " << lhost << ":" << lport;
01236 cerr << endl;
01237 }
01238 }
01239 }
01240
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
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 }