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 #include "ReposUI.H"
00036
00037 #if !defined(__sun__)
00038 extern "C" {
00039 #include <getopt.h>
00040 }
00041 #endif
00042
00043 using std::cout;
00044 using std::cerr;
00045 using std::endl;
00046
00047 enum Recursion {
00048 r_none, r_pkg, r_branch, r_checkout
00049 };
00050
00051 Text program_name, defpkgpar;
00052 int errcount = 0;
00053
00054 void
00055 Usage()
00056 {
00057 cerr << "Usage: " << program_name
00058 << " [-n | -p | -b | -c] [-m] [-t] [-v] [-R repos] [package]" << endl;
00059 exit(1);
00060 }
00061
00062 struct verclosure {
00063 VestaSource* parent;
00064 Text prefix;
00065 Recursion recurse;
00066 bool mast;
00067 int elide;
00068 int high;
00069 bool comment;
00070 Text highText;
00071 VestaSource* highvervs;
00072 Text lhost, lport;
00073 };
00074
00075 static bool
00076 vercallback(void* closure, VestaSource::typeTag type, Arc arc,
00077 unsigned int index, Bit32 pseudoInode, ShortId filesid,
00078 bool master);
00079
00080 static void
00081 printlatest(VestaSource* vs, Text prefix, Recursion recurse,
00082 bool mast, int elide, bool comment, Text lhost, Text lport)
00083 {
00084 verclosure cl;
00085 cl.parent = vs;
00086 cl.prefix = prefix;
00087 cl.recurse = recurse;
00088 cl.mast = mast;
00089 cl.elide = elide;
00090 cl.high = -1;
00091 cl.comment = comment;
00092 cl.highvervs = NULL;
00093 cl.lhost = lhost;
00094 cl.lport = lport;
00095 VestaSource::errorCode err = vs->list(0, vercallback, &cl);
00096 if (err != VestaSource::ok) {
00097 cerr << program_name
00098 << ": error listing directory " << cl.prefix << ": "
00099 << ReposUI::errorCodeText(err) << endl;
00100 errcount++;
00101 }
00102 if (cl.high != -1) {
00103 cout << prefix.Sub(elide) << cl.highText << endl;
00104 }
00105 if(cl.comment && cl.highvervs) {
00106 char* msg = cl.highvervs->getAttrib("message");
00107 if(msg) {
00108 cout << "\t" << msg << endl;
00109 delete msg;
00110 }
00111 delete cl.highvervs;
00112 cl.highvervs = NULL;
00113 }
00114 }
00115
00116 static bool
00117 vercallback(void* closure, VestaSource::typeTag type, Arc arc,
00118 unsigned int index, Bit32 pseudoInode, ShortId filesid,
00119 bool master)
00120 {
00121 verclosure* cl = (verclosure*) closure;
00122 char* endptr;
00123 VestaSource* vs;
00124
00125 if (cl->mast && !master &&
00126 type != VestaSource::immutableDirectory &&
00127 type != VestaSource::immutableFile) {
00128 try {
00129 vs = ReposUI::filenameToMasterVS(cl->prefix + arc,
00130 cl->parent->host() + ":" +
00131 cl->parent->port() + " " +
00132 cl->lhost + ":" + cl->lport);
00133 } catch (ReposUI::failure f) {
00134 cerr << program_name << ": " << f.msg << endl;
00135 errcount++;
00136 return true;
00137 }
00138 } else {
00139 VestaSource::errorCode err = cl->parent->lookupIndex(index, vs);
00140 if (err != VestaSource::ok) {
00141 cerr << program_name << ": error on lookupIndex: "
00142 << ReposUI::errorCodeText(err) << endl;
00143 errcount++;
00144 return true;
00145 }
00146 }
00147
00148 bool delete_vs = true;
00149 if (vs->type == VestaSource::immutableDirectory) {
00150 char* endptr;
00151 if (arc[0] != '0' || arc[1] == '\0') {
00152 long val = strtol(arc, &endptr, 10);
00153 if (*endptr == '\0' && val > cl->high) {
00154 cl->high = val;
00155 cl->highText = arc;
00156 if(cl->comment) {
00157 if(cl->highvervs) {
00158 delete cl->highvervs;
00159 }
00160 cl->highvervs = vs;
00161 delete_vs = false;
00162 }
00163 }
00164 }
00165 } else if (vs->type == VestaSource::appendableDirectory) {
00166 if (cl->recurse == r_none) return true;
00167 if ((cl->recurse >= r_checkout ||
00168 !vs->inAttribs("type", "checkout")) &&
00169 (cl->recurse >= r_branch ||
00170 !vs->inAttribs("type", "branch"))) {
00171
00172 printlatest(vs, cl->prefix + arc + "/", cl->recurse, cl->mast,
00173 cl->elide, cl->comment, cl->lhost, cl->lport);
00174 }
00175 }
00176 if(delete_vs)
00177 delete vs;
00178
00179 return true;
00180 }
00181
00182 void
00183 doit(Text pkg, Recursion recurse, bool mast, bool fullpath,
00184 bool comment, Text lhost, Text lport)
00185 {
00186 Text cpkg = ReposUI::canonicalize(pkg, defpkgpar);
00187 VestaSource* vs_pkg;
00188 if (mast) {
00189 vs_pkg = ReposUI::filenameToMasterVS(cpkg, lhost + ":" + lport);
00190 } else {
00191 vs_pkg = ReposUI::filenameToVS(cpkg, lhost, lport);
00192 }
00193
00194
00195 if (vs_pkg->type != VestaSource::appendableDirectory) {
00196
00197 return;
00198 }
00199 if (recurse == r_none && !vs_pkg->inAttribs("type", "package")) {
00200 cerr << program_name << ": " << cpkg << " is not a package" << endl;
00201 errcount++;
00202 return;
00203 }
00204 printlatest(vs_pkg, cpkg + "/", recurse, mast,
00205 fullpath ? 0 : (cpkg.Length() + 1), comment, lhost, lport);
00206 }
00207
00208 int
00209 main(int argc, char* argv[])
00210 {
00211 program_name = argv[0];
00212 try {
00213
00214
00215
00216 defpkgpar = VestaConfig::get_Text("UserInterface",
00217 "DefaultPackageParent");
00218
00219 Recursion recurse = r_pkg;
00220 bool mast = false;
00221 bool fullpath = true;
00222 bool comment = false;
00223 Text repos;
00224
00225
00226
00227
00228 opterr = 0;
00229 for (;;) {
00230 char* slash;
00231 int c = getopt(argc, argv, "npbcmtvR:");
00232 if (c == EOF) break;
00233 switch (c) {
00234 case 'n':
00235 recurse = r_none;
00236 break;
00237 case 'p':
00238 recurse = r_pkg;
00239 break;
00240 case 'b':
00241 recurse = r_branch;
00242 break;
00243 case 'c':
00244 recurse = r_checkout;
00245 break;
00246 case 'm':
00247 mast = true;
00248 break;
00249 case 't':
00250 fullpath = false;
00251 break;
00252 case 'v':
00253 comment = true;
00254 break;
00255 case 'R':
00256 repos = optarg;
00257 break;
00258 case '?':
00259 default:
00260 Usage();
00261 }
00262 }
00263
00264 Text lhost(VDirSurrogate::defaultHost());
00265 Text lport(VDirSurrogate::defaultPort());
00266 if (repos != "") {
00267 int colon = repos.FindCharR(':');
00268 if (colon == -1) {
00269 lhost = repos;
00270 repos = repos + ":" + lport;
00271 } else {
00272 lhost = repos.Sub(0, colon);
00273 lport = repos.Sub(colon+1);
00274 }
00275 }
00276
00277 if (optind > argc) {
00278 Usage();
00279
00280 } else if (optind == argc) {
00281 doit("/vesta", recurse, mast, fullpath, comment, lhost, lport);
00282 } else {
00283 if (argc - optind > 1 && !fullpath) {
00284 cerr << program_name <<
00285 ": only one package allowed with -t flag" << endl;
00286 exit(errcount+1);
00287 }
00288 while (optind < argc) {
00289 doit(argv[optind++], recurse, mast, fullpath,
00290 comment, lhost, lport);
00291 }
00292 }
00293
00294 } catch (VestaConfig::failure f) {
00295 cerr << program_name << ": " << f.msg << endl;
00296 exit(errcount+1);
00297 } catch (SRPC::failure f) {
00298 cerr << program_name
00299 << ": SRPC failure; " << f.msg << " (" << f.r << ")" << endl;
00300 exit(errcount+1);
00301 } catch (ReposUI::failure f) {
00302 cerr << program_name << ": " << f.msg << endl;
00303 exit(errcount+1);
00304 }
00305 return errcount;
00306 }
00307
00308
00309