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::cin;
00051 using std::cerr;
00052 using std::endl;
00053 using std::flush;
00054
00055 Text program_name;
00056
00057 void usage()
00058 {
00059 cerr << "Usage: " << program_name << endl <<
00060 " [-q] [-Q] [-a | -A] [-p] [-f]" << endl <<
00061 " [-h hints]" << endl <<
00062 " [-R repos]" << endl <<
00063 " directory" << 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 repos;
00076 bool default_repos = true;
00077
00078
00079
00080
00081 bool acquire_mastership = false;
00082
00083 Text cuser(AccessControl::self()->user());
00084 Text user(cuser.Sub(0, cuser.FindChar('@')));
00085 Text lhost(VDirSurrogate::defaultHost());
00086 Text lport(VDirSurrogate::defaultPort());
00087 const int vlen = 7;
00088 const Replicator::Flags rflags = (Replicator::Flags)
00089 (Replicator::attrNew | Replicator::attrOld | Replicator::attrAccess |
00090 Replicator::revive | Replicator::inclStubs | Replicator::latest);
00091
00092 if(VestaConfig::is_set("UserInterface", "vmkdir_acquires"))
00093 {
00094 acquire_mastership = VestaConfig::get_bool("UserInterface",
00095 "vmkdir_acquires");
00096 }
00097 Text defhints;
00098 (void) VestaConfig::get("UserInterface", "DefaultHints", defhints);
00099
00100
00101
00102
00103 bool quiet = false;
00104 bool query = false;
00105 bool force = false;
00106
00107
00108
00109 bool set_package_parent = false;
00110
00111 Text dir, oldver, hints;
00112
00113 opterr = 0;
00114 for (;;) {
00115 int c = getopt(argc, argv, "qQaApfh:R:");
00116 if (c == EOF) break;
00117 switch (c) {
00118 case 'q':
00119 quiet = true;
00120 break;
00121 case 'Q':
00122 query = true;
00123 break;
00124 case 'a':
00125 acquire_mastership = true;
00126 break;
00127 case 'A':
00128 acquire_mastership = false;
00129 break;
00130 case 'p':
00131 set_package_parent = true;
00132 break;
00133 case 'f':
00134 force = true;
00135 break;
00136 case 'h':
00137 hints = optarg;
00138 break;
00139 case 'R':
00140 repos = optarg;
00141 default_repos = false;
00142 break;
00143 case '?':
00144 default:
00145 usage();
00146 }
00147 }
00148 if (argc != optind + 1) {
00149 usage();
00150 }
00151 dir = Text(argv[optind]);
00152
00153
00154
00155
00156
00157 if (!default_repos) {
00158 int colon = repos.FindCharR(':');
00159 if (colon == -1) {
00160 lhost = repos;
00161 repos = repos + ":" + lport;
00162 } else {
00163 lhost = repos.Sub(0, colon);
00164 lport = repos.Sub(colon+1);
00165 }
00166 hints = hints + " " + repos;
00167 }
00168 hints = hints + " " + defhints;
00169
00170
00171
00172
00173 Text cdir, cparent, newpart;
00174 cdir = ReposUI::canonicalize(dir);
00175 ReposUI::split(cdir, cparent, newpart, "directory name");
00176
00177
00178 bool parent_is_app_root =
00179 (strcmp(cparent.cchars(), "/vesta") == 0);
00180
00181
00182 bool in_mutable_root =
00183 (strncmp(cdir.cchars(), "/vesta-work/", 12) == 0);
00184
00185
00186
00187
00188 Text volatileRoot = VestaConfig::get_Text("Run_Tool", "VolatileRootName");
00189 if(volatileRoot[volatileRoot.Length()-1] != '/')
00190 {
00191 volatileRoot += "/";
00192 }
00193 if(strncmp(dir.cchars(),
00194 volatileRoot.cchars(), volatileRoot.Length()) == 0)
00195 {
00196 cerr << program_name << ": " << dir
00197 << " is inside the volatile root ("
00198 << volatileRoot << ")" << endl;
00199 exit(2);
00200 }
00201
00202
00203
00204
00205 VestaSource* vs_mparent;
00206 if(parent_is_app_root)
00207 {
00208
00209
00210 vs_mparent = VDirSurrogate::repositoryRoot(lhost, lport);
00211 }
00212 else if(in_mutable_root)
00213 {
00214
00215 vs_mparent = ReposUI::filenameToVS(cparent, lhost, lport);
00216 }
00217 else
00218 {
00219
00220
00221 vs_mparent = ReposUI::filenameToMasterVS(cparent, hints);
00222 if (!force)
00223 {
00224
00225
00226
00227 if(vs_mparent->inAttribs("type", "package"))
00228 {
00229 cerr << program_name << ": " << cparent
00230 << " has type package" << endl;
00231 exit(2);
00232 }
00233
00234
00235
00236 else if(vs_mparent->inAttribs("type", "branch"))
00237 {
00238 cerr << program_name << ": " << cparent
00239 << " has type branch" << endl;
00240 exit(2);
00241 }
00242 else if(vs_mparent->inAttribs("type", "checkout"))
00243 {
00244 cerr << program_name << ": " << cparent
00245 << " has type checkout" << endl;
00246 exit(2);
00247 }
00248 else if(vs_mparent->inAttribs("type", "session"))
00249 {
00250 cerr << program_name << ": " << cparent
00251 << " has type session" << endl;
00252 exit(2);
00253 }
00254 }
00255 }
00256 Text mhost(vs_mparent->host());
00257 Text mport(vs_mparent->port());
00258 bool remote = (mhost != lhost || mport != lport);
00259 Text hint_dir;
00260 if(remote) {
00261
00262 hint_dir = ReposUI::getMasterHintDir(vs_mparent, cparent);
00263 }
00264
00265
00266
00267
00268 assert(!remote || (!parent_is_app_root && !in_mutable_root));
00269
00270 if (!quiet) {
00271 cout << "Creating directory " << cdir;
00272 if (remote) {
00273 cout << " at " << mhost << ":" << mport;
00274 }
00275 cout << endl;
00276 }
00277
00278 if (query) {
00279 cerr << program_name << ": nothing done (-Q flag given)" << endl;
00280 exit(0);
00281 }
00282
00283
00284
00285
00286 if(parent_is_app_root)
00287 {
00288 cout << endl
00289 << "Warning: Top-level directories must be unique. (If they"
00290 << endl
00291 << " aren't, you can can violate the replication"
00292 << endl
00293 << " invariant.)" << endl << endl
00294 << " The recommend method is to base top-level" << endl
00295 << " directory names on a domain or e-mail address that"
00296 << endl
00297 << " you own." << endl << endl
00298 << "Are you sure you want to proceed (y/n)? " << flush;
00299
00300 const int BuffLen = 20; char buff[BuffLen];
00301 cin.getline(buff, BuffLen);
00302 if (buff[0] != 'y')
00303 {
00304 cout << "Not creating " << cdir << endl;
00305 exit(0);
00306 }
00307 }
00308
00309
00310
00311
00312
00313
00314 VestaSourceAtomic vsa(mhost, mport);
00315
00316
00317 VestaSourceAtomic::VSIndex vsi_parent =
00318 vsa.decl(cparent, vs_mparent);
00319 if(!parent_is_app_root)
00320 {
00321 vsa.testMaster(cparent, vsi_parent, true,
00322 VestaSource::notMaster);
00323 }
00324
00325
00326
00327 VestaSourceAtomic::VSIndex vsi_dir;
00328 if(in_mutable_root)
00329 {
00330 vsi_dir =
00331 vsa.insertMutableDirectory(cdir, vsi_parent,
00332 newpart, -1, true,
00333 VestaSource::dontReplace);
00334 }
00335 else
00336 {
00337 vsi_dir =
00338 vsa.insertAppendableDirectory(cdir, vsi_parent,
00339 newpart, true,
00340 VestaSource::dontReplace);
00341 }
00342
00343
00344 if(set_package_parent && !in_mutable_root)
00345 {
00346 vsa.setAttrib(cdir, vsi_dir, "type", "package-parent");
00347 }
00348
00349
00350
00351
00352
00353
00354 signal(SIGINT, SIG_IGN);
00355
00356
00357 if (!vsa.run()) {
00358 VestaSource::errorCode err;
00359 if (vsa.lasterr == VestaSource::ok) {
00360 err = vsa.okreplace;
00361 } else {
00362 err = vsa.lasterr;
00363 }
00364 cerr << program_name << ": " << vsa.name(vsa.ndone) << ": "
00365 << ReposUI::errorCodeText(err) << endl;
00366 if((err == VestaSource::noPermission) && parent_is_app_root)
00367 {
00368 cerr << "(Maybe you need to be "
00369 << VestaConfig::get_Text("Repository", "vwizard_user")
00370 << "?)" << endl;
00371 }
00372 exit(2);
00373 }
00374
00375
00376
00377 if (!remote || parent_is_app_root || in_mutable_root) exit(0);
00378
00379
00380
00381
00382 Replicator repl(mhost, mport, lhost, lport);
00383 Replicator::DirectiveSeq direcs;
00384 Replicator::Directive d('+', cdir.Sub(vlen));
00385 direcs.addhi(d);
00386 repl.replicate(&direcs, rflags);
00387
00388
00389
00390
00391 if(acquire_mastership)
00392 {
00393 VestaSource::errorCode err =
00394 VDirSurrogate::acquireMastership(cdir.Sub(vlen).cchars(),
00395 lhost, lport, mhost, mport);
00396 if (err != VestaSource::ok) {
00397 cerr << program_name << ": error acquiring mastership of "
00398 << cdir << ": " << ReposUI::errorCodeText(err) << endl;
00399 exit(2);
00400 }
00401 }
00402
00403
00404 Text master_hint = mhost + ":" + mport;
00405 VestaSource* vs_hint = NULL;
00406 vs_hint = ReposUI::filenameToVS(hint_dir, lhost, lport);
00407 if(!vs_hint->inAttribs("master-repository", master_hint.cchars())) {
00408 VestaSource::errorCode err =
00409 vs_hint->setAttrib("master-repository", master_hint.cchars());
00410 if(!quiet && (err != VestaSource::ok)) {
00411 cerr << program_name
00412 << ": warning: incorrect master-repository attribute of "
00413 << hint_dir << " couldn't be updated (should be "
00414 << master_hint << ")" << endl;
00415 }
00416 }
00417
00418 } catch (VestaConfig::failure f) {
00419 cerr << program_name << ": " << f.msg << endl;
00420 exit(2);
00421 } catch (SRPC::failure f) {
00422 cerr << program_name
00423 << ": SRPC failure; " << f.msg << " (" << f.r << ")" << endl;
00424 exit(2);
00425 } catch (ReposUI::failure f) {
00426 cerr << program_name << ": " << f.msg << endl;
00427 exit(2);
00428 }
00429
00430 return 0;
00431 }