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 #include <Basics.H>
00031 #include <Text.H>
00032 #include <VestaConfig.H>
00033 #include <VestaSource.H>
00034 #include <VDirSurrogate.H>
00035 #if !defined(__sun__)
00036 extern "C" {
00037 #include <getopt.h>
00038 }
00039 #endif
00040 #include "ReposUI.H"
00041
00042 #include <iomanip>
00043
00044 using std::cout;
00045 using std::cerr;
00046 using std::endl;
00047 using std::setw;
00048 Text program_name;
00049 bool multiple;
00050 Text timefmt;
00051
00052 void
00053 Usage()
00054 {
00055 cerr << "Usage: " << program_name <<
00056 " [-q] [-t timestamp] [-m] [-T] [-L] [-R repos] [-M] [-H hints]"
00057 << endl <<
00058 " { -x |" << endl <<
00059 " -i attrib value |" << endl <<
00060 " -g attrib |" << endl <<
00061 " -G attrib |" << endl <<
00062 " -n | [-l] | -h |" << endl <<
00063 " -s attrib value |" << endl <<
00064 " -c attrib |" << endl <<
00065 " -a attrib value |" << endl <<
00066 " -r attrib value |" << endl <<
00067 " -C value }" << endl <<
00068 " [source...]" << endl << endl;
00069 exit(3);
00070 }
00071
00072 bool
00073 coutValueCallback(void* closure, const char* value)
00074 {
00075 if(closure != 0)
00076 {
00077 Text *indent = (Text *) closure;
00078 cout << *indent;
00079 }
00080 cout << value << endl;
00081 return true;
00082 }
00083
00084 struct listAllClosure {
00085 VestaSource* sourceVS;
00086 Text indent;
00087 };
00088
00089 bool
00090 listAllCallback(void* closure, const char* value)
00091 {
00092 listAllClosure* cl = (listAllClosure*) closure;
00093 cout << cl->indent << value << endl;
00094 Text indent = cl->indent + "\t";
00095 cl->sourceVS->getAttrib(value, coutValueCallback, (void *) &indent);
00096 return true;
00097 }
00098
00099 bool
00100 coutHistoryCallback(void* closure, VestaSource::attribOp op,
00101 const char* name, const char* value,
00102 time_t timestamp)
00103 {
00104 char timebuf[256];
00105 strftime(timebuf, sizeof(timebuf), timefmt.cchars(), localtime(×tamp));
00106 const char *op_string = VestaSource::attribOpString(op);
00107
00108 if((op_string[0] == 'o') && (op_string[0] == 'p'))
00109 {
00110 op_string += 2;
00111 }
00112 cout << ' ' << timebuf << ' '
00113 << setw(6) << op_string +2 << ' '
00114 << name << '\t' << value << endl;
00115 return true;
00116 }
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128 typedef struct ActionFlags {
00129 int quiet_flag;
00130 int exist_flag;
00131 int in_flag;
00132 int get_flag;
00133 int getone_flag;
00134 int list_flag;
00135 int listall_flag;
00136 int history_flag;
00137 int set_flag;
00138 int clear_flag;
00139 int add_flag;
00140 int remove_flag;
00141 int type_flag;
00142 int master_flag;
00143 int compare_flag;
00144 int last_modified_flag;
00145 } ActionFlags;
00146
00147
00148 typedef struct Action {
00149 ActionFlags flags;
00150 time_t timestamp;
00151 Text attrib;
00152 Text value;
00153 Text csource;
00154 VestaSource* sourceVS;
00155
00156 Action();
00157 ~Action() {}
00158 } Action;
00159
00160 Action::Action()
00161 : timestamp(0), sourceVS(0)
00162 {
00163 memset(&flags, 0, sizeof(ActionFlags));
00164 }
00165
00166 void
00167 commandLineParsing(int argc, char* argv[], Sequence<Action*>& list,
00168 Text& lhost, Text& lport) throw()
00169 {
00170 int new_action_ind = 1;
00171 multiple = false;
00172
00173 bool done = false;
00174 if((optind < argc) && (argv[optind][0] != '-'))
00175 done = true;
00176
00177 Text repos, hints;
00178 bool at_master = false;
00179 Action* current = NEW(Action);
00180
00181
00182 Text defhints;
00183 (void) VestaConfig::get("UserInterface", "DefaultHints", defhints);
00184
00185 while(new_action_ind) {
00186 int c;
00187 new_action_ind = 0;
00188
00189 while(!done) {
00190 int args = 0;
00191
00192 c = getopt(argc, argv, "qt:xigGnlhscarCTLmR:MH:");
00193 if(c == EOF) break;
00194 switch (c) {
00195 case 'q': current->flags.quiet_flag++; continue;
00196 case 't':
00197 current->timestamp = strtol(optarg, NULL, 0);
00198 continue;
00199
00200 case 'x': current->flags.exist_flag++; break;
00201 case 'i': current->flags.in_flag++; args = 2; break;
00202 case 'g': current->flags.get_flag++; args = 1; break;
00203 case 'G': current->flags.getone_flag++; args = 1; break;
00204 case 'n': current->flags.list_flag++; break;
00205 case 'l': current->flags.listall_flag++; break;
00206 case 'h': current->flags.history_flag++; break;
00207 case 's': current->flags.set_flag++; args = 2; break;
00208 case 'c': current->flags.clear_flag++; args = 1; break;
00209 case 'a': current->flags.add_flag++; args = 2; break;
00210 case 'r': current->flags.remove_flag++; args = 2; break;
00211 case 'C': current->flags.compare_flag++; args = 1; break;
00212
00213 case 'T': current->flags.type_flag++; break;
00214 case 'm': current->flags.master_flag++; break;
00215 case 'L': current->flags.last_modified_flag++; break;
00216 case 'R': repos = optarg; break;
00217 case 'M': at_master = true; break;
00218 case 'H': hints = optarg; break;
00219
00220 case '?':
00221 default:
00222 Usage();
00223 }
00224
00225
00226 if(current->attrib == "" && current->value == ""){
00227 switch(args) {
00228 case 2:
00229 if(optind + 2 > argc)
00230 Usage();
00231 current->attrib = argv[optind++];
00232 current->value = argv[optind++];
00233 break;
00234 case 1:
00235 if(optind + 1 > argc)
00236 Usage();
00237 current->attrib = argv[optind];
00238 current->value = argv[optind];
00239 optind++;
00240 break;
00241 default: break;
00242 }
00243 }
00244
00245
00246 if((optind >= argc) || ((optind < argc) && (argv[optind][0] != '-'))) {
00247 done = true;
00248 }
00249
00250 }
00251 done = false;
00252
00253
00254 Text source;
00255 if(optind < argc){
00256 source = argv[optind];
00257 if(optind + 1 < argc) {
00258 if(!multiple)
00259 multiple = true;
00260 new_action_ind = optind + 1;
00261 }
00262 else
00263 new_action_ind = 0;
00264 }
00265 else
00266 source = ".";
00267
00268
00269
00270 if(current->flags.master_flag && current->flags.quiet_flag &&
00271 (current->flags.last_modified_flag || current->flags.type_flag)) {
00272 cerr << program_name
00273 << ": flags -q -m can not be used with other flags" << endl;
00274 Usage();
00275 }
00276
00277 if(current->flags.quiet_flag &&
00278 !(current->flags.exist_flag || current->flags.in_flag ||
00279 current->flags.getone_flag || current->flags.compare_flag ||
00280 current->flags.master_flag)) {
00281 cerr << program_name
00282 << ": -q flag is meaningful only with -m, -x, -i, -G or -C"
00283 << endl;
00284 Usage();
00285 }
00286
00287 switch (current->flags.exist_flag + current->flags.in_flag +
00288 current->flags.get_flag + current->flags.getone_flag +
00289 current->flags.list_flag + current->flags.listall_flag +
00290 current->flags.history_flag + current->flags.set_flag +
00291 current->flags.clear_flag + current->flags.add_flag +
00292 current->flags.remove_flag + current->flags.compare_flag){
00293 case 0:
00294 if(!current->flags.master_flag && !current->flags.type_flag &&
00295 !current->flags.last_modified_flag){
00296 current->flags.listall_flag++;
00297 current->flags.type_flag++;
00298 current->flags.master_flag++;
00299 }
00300 break;
00301 case 1:
00302
00303
00304 if(current->flags.master_flag && current->flags.quiet_flag) {
00305 cerr << program_name
00306 << ": flags -q -m can not be used with other flags" << endl;
00307 Usage();
00308 }
00309 break;
00310 default:
00311 cerr << program_name
00312 << ": flags -x, -i, -g, -G, -n, -l, -h, -s, -c, -a, -r, -C "
00313 << endl << "are mutually exclusive" << endl;
00314 Usage();
00315 }
00316
00317 if(current->timestamp != 0 &&
00318 !(current->flags.set_flag || current->flags.clear_flag ||
00319 current->flags.add_flag || current->flags.remove_flag)) {
00320 cerr << program_name
00321 << ": -t flag is meaningful only with -s, -c, -a, or -r"
00322 << endl;
00323 Usage();
00324 }
00325
00326
00327 if(multiple) {
00328 if(current->flags.in_flag) {
00329 cerr << program_name
00330 << ": -i flag cannot be used with multiple objects" << endl;
00331 Usage();
00332 }
00333 else if(current->flags.compare_flag){
00334 cerr << program_name
00335 << ": -C flag cannot be used with multiple objects" << endl;
00336 Usage();
00337 }
00338 else if(current->flags.exist_flag) {
00339 cerr << program_name
00340 << ": -x flag cannot be used with multiple objects" << endl;
00341 Usage();
00342 }
00343 else if(current->flags.master_flag && current->flags.quiet_flag) {
00344 cerr << program_name
00345 << ": -q -m flag cannot be used with multiple objects" << endl;
00346 Usage();
00347 }
00348 }
00349
00350
00351 Text host, port;
00352 if (repos != "") {
00353 int colon = repos.FindCharR(':');
00354 if (colon == -1) {
00355 host = repos;
00356 port = lport;
00357 repos = repos + ":" + lport;
00358 } else {
00359 host = repos.Sub(0, colon);
00360 port = repos.Sub(colon+1);
00361 }
00362 hints = hints + " " + repos;
00363 }
00364 else {
00365 host = lhost;
00366 port = lport;
00367 }
00368 hints = hints + " " + defhints;
00369
00370 bool got_next_source;
00371 do {
00372 got_next_source = false;
00373 try {
00374 current->csource = ReposUI::canonicalize(source);
00375 if(at_master) {
00376 current->sourceVS =
00377 ReposUI::filenameToMasterVS(current->csource, hints);
00378 } else {
00379 current->sourceVS =
00380 ReposUI::filenameToVS(current->csource, host, port);
00381 }
00382 }
00383 catch (ReposUI::failure f) {
00384 cerr << program_name << ": " << f.msg << endl;
00385 exit(2);
00386 }
00387 list.addhi(current);
00388
00389
00390 if(new_action_ind && new_action_ind < argc) {
00391 Action* new_act = NEW(Action);
00392
00393 if(argv[new_action_ind][0] != '-') {
00394 new_act->flags = current->flags;
00395 new_act->timestamp = current->timestamp;
00396 new_act->attrib = current->attrib;
00397 new_act->value = current->value;
00398 source = argv[new_action_ind];
00399 new_action_ind++;
00400 got_next_source = true;
00401 }
00402 current = new_act;
00403 }
00404 } while(got_next_source);
00405
00406
00407 if(new_action_ind == argc)
00408 new_action_ind = 0;
00409 }
00410
00411 }
00412
00413
00414
00415 int
00416 main(int argc, char* argv[])
00417 {
00418 program_name = argv[0];
00419
00420 Sequence<Action*> list;
00421
00422 try {
00423 timefmt = VestaConfig::get_Text("UserInterface", "TimeFormat");
00424 Text lhost(VDirSurrogate::defaultHost());
00425 Text lport(VDirSurrogate::defaultPort());
00426 Text lrepos = lhost + ":" + lport;
00427 commandLineParsing(argc, argv, list, lhost, lport);
00428 int actions_num = list.size();
00429
00430 for(int i = 0; i < actions_num; i++) {
00431 Action* current = list.remlo();
00432
00433 Text source = current->csource;
00434 Text repos = current->sourceVS->host() + ":" +
00435 current->sourceVS->port();
00436
00437 if(multiple && !current->flags.quiet_flag &&
00438 (current->flags.master_flag || current->flags.type_flag ||
00439 current->flags.last_modified_flag || current->flags.get_flag ||
00440 current->flags.list_flag || current->flags.listall_flag ||
00441 current->flags.history_flag || current->flags.getone_flag)) {
00442 cout << source.cchars() << " ";
00443 if(repos != lrepos)
00444 cout << "(" << repos << ") ";
00445 if(!current->flags.master_flag && !current->flags.type_flag)
00446 cout << endl;
00447 }
00448 if(current->flags.master_flag) {
00449 if(current->sourceVS->master)
00450 if(current->flags.quiet_flag) exit(0);
00451 else cout << "master";
00452 else
00453 if(current->flags.quiet_flag) exit(1);
00454 else cout << "nonmaster";
00455 if (current->flags.type_flag)
00456 cout << " ";
00457 else
00458 cout << endl;
00459 }
00460
00461 if(current->flags.type_flag) {
00462 cout << VestaSource::typeTagString(current->sourceVS->type)
00463 << endl;
00464 }
00465
00466 if (current->flags.last_modified_flag){
00467 time_t time = current->sourceVS->timestamp();
00468 switch(int(time)) {
00469 case 2:
00470 case -1:
00471 cerr << source << ": no timestamp" << endl;
00472 break;
00473 default:
00474 char timebuf[256];
00475 strftime(timebuf, sizeof(timebuf), timefmt.cchars(),
00476 localtime(&time));
00477 if(multiple)
00478 cout << '\t';
00479 cout << timebuf << endl;
00480 break;
00481 }
00482 }
00483
00484 if(current->flags.exist_flag) {
00485 if(current->sourceVS->hasAttribs()) {
00486 if(!current->flags.quiet_flag)
00487 cout << "true" << endl;
00488 exit(0);
00489 } else {
00490 if (!current->flags.quiet_flag)
00491 cout << "false" << endl;
00492 exit(1);
00493 }
00494 }
00495
00496 bool require_attribs_flags = current->flags.in_flag ||
00497 current->flags.get_flag || current->flags.getone_flag ||
00498 current->flags.list_flag || current->flags.listall_flag ||
00499 current->flags.history_flag || current->flags.set_flag ||
00500 current->flags.clear_flag || current->flags.add_flag ||
00501 current->flags.remove_flag;
00502
00503 if(require_attribs_flags && !current->sourceVS->hasAttribs()) {
00504 if(!current->flags.quiet_flag) {
00505 cerr << program_name << ": " << source.cchars()
00506 << " does not have attributes" << endl;
00507 }
00508 exit(2);
00509 }
00510
00511 if (current->flags.in_flag) {
00512 if(current->sourceVS->inAttribs(current->attrib.cchars(),
00513 current->value.cchars())){
00514 if(!current->flags.quiet_flag)
00515 cout << "true" << endl;
00516 exit(0);
00517 } else {
00518 if(!current->flags.quiet_flag)
00519 cout << "false" << endl;
00520 exit(1);
00521 }
00522 }
00523 else if(current->flags.compare_flag) {
00524 const char* typestr = current->value.cchars();
00525 if(strcmp(VestaSource::typeTagString(current->sourceVS->type),
00526 typestr) == 0) {
00527 if(!current->flags.quiet_flag)
00528 cout << "true" << endl;
00529 exit(0);
00530 }
00531 else {
00532 if(strcmp(typestr, "immutableFile") !=0 &&
00533 strcmp(typestr, "mutableFile") !=0 &&
00534 strcmp(typestr, "immutableDirectory") !=0 &&
00535 strcmp(typestr, "appendableDirectory") !=0 &&
00536 strcmp(typestr, "mutableDirectory") !=0 &&
00537 strcmp(typestr, "ghost") !=0 &&
00538 strcmp(typestr, "stub")!=0) {
00539 cerr << program_name << ": " << typestr
00540 << ": invalid type string" << endl;
00541 exit (2);
00542 }
00543 else {
00544 if(!current->flags.quiet_flag)
00545 cout << "false" << endl;
00546 exit(1);
00547 }
00548 }
00549 }
00550 else if(current->flags.get_flag) {
00551 Text indent = multiple ? "\t" : "";
00552 current->sourceVS->getAttrib(current->attrib.cchars(),
00553 coutValueCallback, (void *) &indent);
00554 } else if(current->flags.getone_flag) {
00555 char* val = current->sourceVS->getAttrib(current->attrib.cchars());
00556 if(val == NULL) {
00557 if(!current->flags.quiet_flag) {
00558 cerr << program_name
00559 << ": no value for attribute " << current->attrib << endl;
00560 }
00561 exit(1);
00562 }
00563 if(multiple)
00564 cout << '\t';
00565 cout << val << endl;
00566 delete val;
00567 } else if(current->flags.list_flag) {
00568 Text indent = multiple ? "\t" : "";
00569 current->sourceVS->listAttribs(coutValueCallback, (void *) &indent);
00570 } else if(current->flags.listall_flag) {
00571 listAllClosure cl;
00572 cl.sourceVS = current->sourceVS;
00573 cl.indent = multiple ? "\t" : "";
00574 current->sourceVS->listAttribs(listAllCallback, &cl);
00575 } else if(current->flags.history_flag) {
00576 current->sourceVS->getAttribHistory(coutHistoryCallback, NULL);
00577 } else if (current->flags.set_flag || current->flags.clear_flag ||
00578 current->flags.add_flag || current->flags.remove_flag){
00579 VestaSource::attribOp op;
00580 if(current->flags.set_flag) {
00581 op = VestaSource::opSet;
00582 } else if(current->flags.clear_flag) {
00583 op = VestaSource::opClear;
00584 current->value = "";
00585 } else if(current->flags.add_flag) {
00586 op = VestaSource::opAdd;
00587 } else {
00588 assert(current->flags.remove_flag);
00589 op = VestaSource::opRemove;
00590 }
00591 VestaSource::errorCode err =
00592 current->sourceVS->writeAttrib(op, current->attrib.cchars(),
00593 current->value.cchars(), NULL,
00594 current->timestamp);
00595 if (err != VestaSource::ok) {
00596 Text msg = program_name + ":";
00597 if(multiple) {
00598 msg = msg + " " + source;
00599 if(repos != lrepos)
00600 msg = msg + " at " + repos;
00601 }
00602 msg = msg + " on writeAttrib: " + ReposUI::errorCodeText(err);
00603 cerr << msg << endl;
00604 exit(2);
00605 }
00606 }
00607
00608 delete current;
00609 }
00610
00611 } catch (VestaConfig::failure f) {
00612 cerr << program_name << ": " << f.msg << endl;
00613 exit(2);
00614 } catch (SRPC::failure f) {
00615 cerr << program_name
00616 << ": SRPC failure; " << f.msg << " (" << f.r << ")" << endl;
00617 exit(2);
00618 } catch (ReposUI::failure f) {
00619 cerr << program_name << ": " << f.msg << endl;
00620 exit(2);
00621 }
00622
00623 return 0;
00624 }
00625
00626
00627
00628