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
00027
00028
00029
00030
00031
00032
00033 #include <Basics.H>
00034 #include <Text.H>
00035 #include <VestaConfig.H>
00036 #include <VestaSource.H>
00037 #include <VDirSurrogate.H>
00038 #include <VestaSourceAtomic.H>
00039 #include <Replicator.H>
00040 #include <signal.h>
00041 #include "ReposUI.H"
00042
00043 #if !defined(__sun__)
00044 extern "C" {
00045 #include <getopt.h>
00046 }
00047 #endif
00048
00049 using std::cout;
00050 using std::cerr;
00051 using std::endl;
00052
00053 Text program_name;
00054
00055 void usage()
00056 {
00057 cerr << "Usage: " << program_name << endl <<
00058 " [-q] [-Q] [-a | -A] [-f]" << endl <<
00059 " [-o old-version | -O]" << endl <<
00060 " [-m message | -M]" << endl <<
00061 " [-h hints]" << endl <<
00062 " [-R repos]" << endl <<
00063 " package" << endl << endl;
00064 exit(1);
00065 }
00066
00067 int
00068 main(int argc, char* argv[])
00069 {
00070 program_name = argv[0];
00071 try {
00072
00073
00074
00075 Text defpkgpar, timefmt, repos, defhints;
00076 bool default_repos = true;
00077
00078
00079
00080
00081 bool acquire_mastership = false;
00082
00083 defpkgpar = VestaConfig::get_Text("UserInterface",
00084 "DefaultPackageParent");
00085 timefmt = VestaConfig::get_Text("UserInterface", "TimeFormat");
00086 (void) VestaConfig::get("UserInterface", "DefaultHints", defhints);
00087
00088 bool prompt_msg = true, omit_msg = false;
00089 if(VestaConfig::is_set("UserInterface", "vcreate_message")) {
00090 if(!VestaConfig::get_bool("UserInterface", "vcreate_message")) {
00091 prompt_msg = false;
00092 omit_msg = true;
00093 }
00094 }
00095
00096 time_t now = time(NULL);
00097 char timebuf[256];
00098 strftime(timebuf, sizeof(timebuf), timefmt.cchars(), localtime(&now));
00099 Text cuser(AccessControl::self()->user());
00100 Text user(cuser.Sub(0, cuser.FindChar('@')));
00101 Text lhost(VDirSurrogate::defaultHost());
00102 Text lport(VDirSurrogate::defaultPort());
00103 const int vlen = 7;
00104 const Replicator::Flags rflags = (Replicator::Flags)
00105 (Replicator::attrNew | Replicator::attrOld | Replicator::attrAccess |
00106 Replicator::revive | Replicator::inclStubs | Replicator::latest);
00107
00108 if(VestaConfig::is_set("UserInterface", "vcreate_acquires"))
00109 {
00110 acquire_mastership = VestaConfig::get_bool("UserInterface",
00111 "vcreate_acquires");
00112 }
00113
00114
00115
00116
00117 bool quiet = false;
00118 bool query = false;
00119 bool force = false;
00120 bool omit_old = true;
00121
00122 Text pkg, oldver, hints, message;
00123
00124 opterr = 0;
00125 for (;;) {
00126 int c = getopt(argc, argv, "qQaAfo:Om:Mh:R:");
00127 if (c == EOF) break;
00128 switch (c) {
00129 case 'q':
00130 quiet = true;
00131 break;
00132 case 'Q':
00133 query = true;
00134 break;
00135 case 'a':
00136 acquire_mastership = true;
00137 break;
00138 case 'A':
00139 acquire_mastership = false;
00140 break;
00141 case 'f':
00142 force = true;
00143 break;
00144 case 'o':
00145 oldver = optarg;
00146 omit_old = false;
00147 break;
00148 case 'O':
00149 omit_old = true;
00150 break;
00151 case 'm':
00152 message = optarg;
00153 omit_msg = false;
00154 if(message == "-") {
00155 message = "";
00156 prompt_msg = true;
00157 }
00158 else
00159 prompt_msg = false;
00160 break;
00161 case 'M':
00162 omit_msg = true;
00163 prompt_msg = false;
00164 break;
00165 case 'h':
00166 hints = optarg;
00167 break;
00168 case 'R':
00169 repos = optarg;
00170 default_repos = false;
00171 break;
00172 case '?':
00173 default:
00174 usage();
00175 }
00176 }
00177 if (argc != optind + 1) {
00178 usage();
00179 }
00180 pkg = Text(argv[optind]);
00181
00182
00183
00184
00185
00186 if (!default_repos) {
00187 int colon = repos.FindCharR(':');
00188 if (colon == -1) {
00189 lhost = repos;
00190 repos = repos + ":" + lport;
00191 } else {
00192 lhost = repos.Sub(0, colon);
00193 lport = repos.Sub(colon+1);
00194 }
00195 hints = hints + " " + repos;
00196 }
00197 hints = hints + " " + defhints;
00198
00199
00200 if (!query && prompt_msg) {
00201 message = ReposUI::getMessage("package description");
00202 }
00203
00204
00205
00206
00207 Text cpkg, cparent, newpart, coldver, ccheckout, clatest, cslatest, cver0;
00208 cpkg = ReposUI::canonicalize(pkg, defpkgpar);
00209 ReposUI::split(cpkg, cparent, newpart, "package name");
00210 if (!omit_old) {
00211 coldver = ReposUI::canonicalize(oldver, defpkgpar);
00212 }
00213 ccheckout = cpkg + "/checkout";
00214 clatest = cpkg + "/latest";
00215 cslatest = cpkg + "/checkout/latest";
00216 cver0 = cpkg + "/0";
00217
00218
00219
00220
00221 VestaSource* vs_mparent =
00222 ReposUI::filenameToMasterVS(cparent, hints);
00223 if (!force && !vs_mparent->inAttribs("type", "package-parent")) {
00224 cerr << program_name << ": " << cparent << " at "
00225 << vs_mparent->host() << ":" << vs_mparent->port()
00226 << " does not have type package-parent" << endl;
00227 exit(2);
00228 }
00229 Text mhost(vs_mparent->host());
00230 Text mport(vs_mparent->port());
00231 bool remote = (mhost != lhost || mport != lport);
00232 Text hint_dir;
00233 if(remote) {
00234
00235 hint_dir = ReposUI::getMasterHintDir(vs_mparent, cparent);
00236 }
00237
00238
00239
00240
00241
00242 VestaSource* vs_moldver = NULL;
00243 VestaSource* vs_roldver = NULL;
00244 if (!omit_old) {
00245 vs_roldver = ReposUI::filenameToRealVS(coldver, hints);
00246 if (vs_roldver->type == VestaSource::stub) {
00247 cerr << program_name << ": " << coldver
00248 << " is not checked in yet" << endl;
00249 exit(2);
00250 } else if (vs_roldver->type == VestaSource::ghost) {
00251 cerr << program_name << ": " << coldver
00252 << " has been deleted" << endl;
00253 exit(2);
00254 }
00255
00256
00257 if(vs_roldver->host() == mhost && vs_roldver->port() == mport) {
00258 vs_moldver = vs_roldver;
00259 }
00260 else {
00261 try {
00262 vs_moldver = ReposUI::filenameToVS(coldver, mhost, mport);
00263
00264
00265 if(vs_moldver->type != vs_roldver->type) {
00266 delete vs_moldver;
00267 vs_moldver = NULL;
00268 }
00269 }
00270 catch(...){
00271
00272 }
00273 if(!vs_moldver && !query){
00274
00275 if (!quiet) {
00276 cout << "Replicating " << coldver << " from "
00277 << vs_roldver->host() << ":" << vs_roldver->port()
00278 << " to " << mhost << ":" << mport << endl;
00279 }
00280 Replicator repl(vs_roldver->host(), vs_roldver->port(),
00281 mhost, mport);
00282 Replicator::DirectiveSeq direcs;
00283 Replicator::Directive d('+', coldver.Sub(vlen));
00284 direcs.addhi(d);
00285 repl.replicate(&direcs, rflags);
00286 vs_moldver = ReposUI::filenameToVS(coldver, mhost, mport);
00287 }
00288 }
00289 }
00290
00291
00292
00293
00294 VestaSource* vs_mpkg = 0;
00295 VestaSource::errorCode err = vs_mparent->lookupPathname(newpart.cchars(),
00296 vs_mpkg);
00297 bool pkg_exists = (err != VestaSource::notFound);
00298
00299 if (!quiet) {
00300 cout << "Creating package " << cpkg;
00301 if (remote) {
00302 cout << " at " << mhost << ":" << mport;
00303 }
00304 cout << endl;
00305 }
00306
00307 if (query) {
00308 cerr << program_name << ": nothing done (-Q flag given)" << endl;
00309 exit(0);
00310 }
00311
00312
00313
00314
00315 VestaSourceAtomic vsa(mhost, mport);
00316
00317
00318 VestaSourceAtomic::VSIndex vsi_parent =
00319 vsa.decl(cparent, vs_mparent);
00320 vsa.testMaster(cparent, vsi_parent, true,
00321 VestaSource::notMaster);
00322
00323
00324 VestaSourceAtomic::VSIndex vsi_oldver = -1;
00325 if(!omit_old) {
00326 assert(vs_moldver != 0);
00327 vsi_oldver = vsa.decl(coldver, vs_moldver);
00328
00329 vsa.typeCheck(coldver, vsi_oldver, VestaSourceAtomic::
00330 typebit(VestaSource::immutableDirectory),
00331 VestaSource::inappropriateOp);
00332 }
00333
00334
00335
00336
00337 VestaSourceAtomic::VSIndex vsi_pkg = -1;
00338 if(pkg_exists)
00339 {
00340
00341 vsi_pkg = vsa.lookupPathname(cpkg, vsi_parent, newpart);
00342
00343 vsa.typeCheck(cpkg, vsi_parent,
00344 VestaSourceAtomic::
00345 typebit(VestaSource::appendableDirectory),
00346 VestaSource::inappropriateOp);
00347
00348 vsa.setTarget(cpkg,
00349 VestaSource::notFound, VestaSource::notFound,
00350 VestaSource::nameInUse);
00351 vsa.lookupIndex(cpkg, vsi_pkg, 1);
00352
00353 vsa.setTarget(cpkg);
00354 }
00355 else
00356 {
00357 vsi_pkg = vsa.insertAppendableDirectory(cpkg, vsi_parent,
00358 newpart, true,
00359 VestaSource::dontReplace);
00360 }
00361
00362
00363 VestaSourceAtomic::VSIndex vsi_ver0 = -1;
00364 if (!omit_old) {
00365 vsi_ver0 =
00366 vsa.insertImmutableDirectory(cver0, vsi_pkg, "0", vsi_oldver, true,
00367 VestaSource::dontReplace);
00368 }
00369
00370
00371 VestaSourceAtomic::VSIndex vsi_checkout =
00372 vsa.insertAppendableDirectory(ccheckout, vsi_pkg, "checkout", true,
00373 VestaSource::dontReplace);
00374
00375
00376 VestaSourceAtomic::VSIndex vsi_latest =
00377 vsa.insertStub(clatest, vsi_pkg, "latest", true,
00378 VestaSource::dontReplace);
00379 VestaSourceAtomic::VSIndex vsi_latest2 =
00380 vsa.insertStub(cslatest, vsi_checkout, "latest", true,
00381 VestaSource::dontReplace);
00382
00383
00384 vsa.setAttrib(cpkg, vsi_pkg, "created-by", cuser);
00385 vsa.setAttrib(cpkg, vsi_pkg, "creation-time", timebuf);
00386 vsa.setAttrib(cpkg, vsi_pkg, "type", "package");
00387 if (!omit_old) {
00388 vsa.setAttrib(cpkg, vsi_pkg, "old-version", coldver);
00389 }
00390
00391 if(!omit_msg && !message.Empty()) {
00392 vsa.setAttrib(cpkg, vsi_pkg, "message", message);
00393 }
00394 if (vsi_ver0 != -1) {
00395 vsa.setAttrib(cver0, vsi_ver0, "old-version", coldver);
00396 }
00397 vsa.setAttrib(ccheckout, vsi_checkout, "type", "checkout");
00398 vsa.setAttrib(clatest, vsi_latest, "symlink-to", "$LAST");
00399 vsa.setAttrib(cslatest, vsi_latest2, "symlink-to", "$LAST");
00400
00401 if(!omit_old) {
00402 vsa.setTarget("", VestaSource::ok, VestaSource::noPermission);
00403 vsa.addAttrib(coldver + ": adding to next-packages", vsi_oldver,
00404 "next-packages", cpkg);
00405 vsa.setTarget("");
00406 }
00407
00408
00409
00410
00411
00412
00413 signal(SIGINT, SIG_IGN);
00414
00415
00416 if (!vsa.run()) {
00417 VestaSource::errorCode err;
00418 if (vsa.lasterr == VestaSource::ok) {
00419 err = vsa.okreplace;
00420 } else {
00421 err = vsa.lasterr;
00422 }
00423 cerr << program_name << ": " << vsa.name(vsa.ndone) << ": "
00424 << ReposUI::errorCodeText(err) << endl;
00425 exit(2);
00426 }
00427
00428
00429
00430 if(!omit_old && !quiet) {
00431 if(!vs_moldver->inAttribs("next-packages", cpkg.cchars())) {
00432 cerr << program_name << ": warning: "
00433 "next-packages attribute couldn't be added to version: "
00434 << coldver << " at " << mhost << ":" << mport << endl;
00435 }
00436 }
00437
00438
00439 if (!remote) exit(0);
00440
00441
00442
00443
00444 Replicator repl(mhost, mport, lhost, lport);
00445 Replicator::DirectiveSeq direcs;
00446 Replicator::Directive d('+', cpkg.Sub(vlen));
00447 direcs.addhi(d);
00448 repl.replicate(&direcs, rflags);
00449
00450
00451
00452
00453
00454
00455 if(acquire_mastership)
00456 {
00457 err = VDirSurrogate::acquireMastership(cpkg.Sub(vlen).cchars(),
00458 lhost, lport, mhost, mport);
00459 if (err != VestaSource::ok) {
00460 cerr << program_name << ": error acquiring mastership of "
00461 << cpkg << ": " << ReposUI::errorCodeText(err) << endl;
00462 exit(2);
00463 }
00464 err = VDirSurrogate::acquireMastership(ccheckout.Sub(vlen).cchars(),
00465 lhost, lport, mhost, mport);
00466 if (err != VestaSource::ok) {
00467 cerr << program_name << ": error acquiring mastership of "
00468 << ccheckout << ": " << ReposUI::errorCodeText(err) << endl;
00469 exit(2);
00470 }
00471 }
00472
00473
00474 if(!omit_old && !query) {
00475 VestaSource* vs_oldver = NULL;
00476 if(vs_roldver->host() == lhost && vs_roldver->port() == lport)
00477 {
00478 vs_oldver = vs_roldver;
00479 }
00480 else
00481 {
00482 try
00483 {
00484 vs_oldver = ReposUI::filenameToVS(coldver, lhost, lport);
00485 }
00486 catch(ReposUI::failure)
00487 {
00488
00489 vs_oldver = NULL;
00490 }
00491 }
00492
00493
00494 if(vs_oldver) {
00495 err = vs_oldver->addAttrib("next-packages", cpkg.cchars());
00496 if(!quiet && (err != VestaSource::ok)) {
00497 cerr << program_name << ": warning: "
00498 "next-packages attribute couldn't be added to version: "
00499 << coldver << endl;
00500 }
00501 }
00502 }
00503
00504
00505 Text master_hint = mhost + ":" + mport;
00506 VestaSource* vs_hint = NULL;
00507 vs_hint = ReposUI::filenameToVS(hint_dir, lhost, lport);
00508 if(!vs_hint->inAttribs("master-repository", master_hint.cchars())) {
00509 VestaSource::errorCode err =
00510 vs_hint->setAttrib("master-repository", master_hint.cchars());
00511 if(!quiet && (err != VestaSource::ok)) {
00512 cerr << program_name
00513 << ": warning: incorrect master-repository attribute of "
00514 << hint_dir << " couldn't be updated (should be "
00515 << master_hint << ")" << endl;
00516 }
00517 }
00518
00519 } catch (VestaConfig::failure f) {
00520 cerr << program_name << ": " << f.msg << endl;
00521 exit(2);
00522 } catch (SRPC::failure f) {
00523 cerr << program_name
00524 << ": SRPC failure; " << f.msg << " (" << f.r << ")" << endl;
00525 exit(2);
00526 } catch (ReposUI::failure f) {
00527 cerr << program_name << ": " << f.msg << endl;
00528 exit(2);
00529 } catch(FS::Failure f) {
00530 cerr << program_name << ": " << f << endl;
00531 exit(2);
00532 }
00533
00534 return 0;
00535 }