Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

vadvance.C

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 // 
00003 // This file is part of Vesta.
00004 // 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 // 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 //
00020 // vadvance.C
00021 //
00022 
00023 // Advance to the next version in a Vesta checkout session.
00024 // See vadvance.1.mtex for documentation.
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 "ReposUI.H"
00033 #include <Units.H>
00034 
00035 #if !defined(__sun__)
00036 extern "C" {
00037 #include <getopt.h>
00038 }
00039 #endif
00040 
00041 using std::cout;
00042 using std::cerr;
00043 using std::endl;
00044 
00045 Text program_name;
00046 const unsigned long MAXUL = (0UL - 1UL);
00047 const Text default_junk = "*~ .*~ core";
00048 const unsigned long default_maxsize = 1024*1024;
00049 
00050 void
00051 usage()
00052 {
00053   cerr << "Usage: " << program_name << endl <<
00054     "        [-q] [-Q] [-f]" << endl <<
00055     "        [-F fp-content]" << endl <<
00056     "        [-j junk | -J]" << endl <<
00057     "        [-z maxsize | -Z]" << endl <<
00058     "        [-s session-dir]" << endl <<
00059     "        [-a session-ver-arc]" << endl <<
00060     "        [-R repos]" << endl <<
00061     "        [ [-w] work-dir]" << endl << endl;
00062   exit(1);
00063 }
00064 
00065 void fix_work_dir_attrib(const Text &cworkdir, const Text &ctarget,
00066                          VestaSource *vs_target)
00067 {
00068   // Get the current value of work-dir on the target
00069   char *workdir_val = vs_target->getAttrib("work-dir");
00070   // If it's unset or has a value other than cworkdir, set it to
00071   // cworkdir
00072   if((workdir_val == 0) || (cworkdir != workdir_val))
00073     {
00074       VestaSource::errorCode err =
00075         vs_target->setAttrib("work-dir", cworkdir.cchars());
00076       if(err != VestaSource::ok)
00077         {
00078           // Print a warning if we fail to set the attribute.
00079           cerr << program_name 
00080                << ": WARNING: the 'work-dir' attribute on " << ctarget
00081                << " seems incorrect (maybe you renamed ";
00082           if(workdir_val != 0)
00083             cerr << workdir_val << " to ";
00084           cerr << cworkdir << "?) and correcting it failed: "
00085                << ReposUI::errorCodeText(err) << endl;
00086         }
00087     }
00088   // If the attribute was non-empty, free its storage.
00089   if(workdir_val != 0)
00090     delete [] workdir_val;
00091 }
00092 
00093 void fix_work_dir_attrib(const Text &cworkdir, const Text &ctarget,
00094                          const Text &lhost, const Text &lport)
00095 {
00096   VestaSource *vs_target;
00097   try
00098     {
00099       vs_target = ReposUI::filenameToVS(ctarget, lhost, lport);
00100     }
00101   catch(ReposUI::failure)
00102     {
00103       // Maybe we're trying to chase a new-version attribute that's
00104       // invalid (points to something non-existent)?  Silently ignore
00105       // such an error.
00106       return;
00107     }
00108   fix_work_dir_attrib(cworkdir, ctarget, vs_target);
00109   delete vs_target;
00110 }
00111 
00112 int
00113 main(int argc, char* argv[])
00114 {
00115   program_name = argv[0];
00116   try {
00117     //
00118     // Read config file
00119     //
00120     Text defpkgpar, defworkpar;
00121     defpkgpar = VestaConfig::get_Text("UserInterface",
00122                                       "DefaultPackageParent");
00123     defworkpar = VestaConfig::get_Text("UserInterface",
00124                                        "DefaultWorkParent");
00125     Text lhost(VDirSurrogate::defaultHost());
00126     Text lport(VDirSurrogate::defaultPort());
00127     time_t now = time(NULL);
00128     Text cuser(AccessControl::self()->user());
00129     Text user(cuser.Sub(0, cuser.FindChar('@')));
00130     Text workdir, sessdir, sessverarc, repos;
00131     bool default_workdir = true, default_sessdir = true;
00132     bool default_sessverarc = true, default_repos = true;
00133     bool quiet = false, query = false, force = false;
00134     bool test = false;
00135     int c;
00136     VestaSource::errorCode err;
00137     unsigned int fp_content = VestaConfig::get_int("UserInterface",
00138                                                    "FpContent");
00139     Text junk = default_junk;
00140     VestaConfig::get("UserInterface", "vadvance_junk", junk);
00141     unsigned long maxsize = default_maxsize;
00142     Text t;
00143     if (VestaConfig::get("UserInterface", "vadvance_maxsize", t)) {
00144       try
00145         {
00146           maxsize = Basics::ParseUnitVal(t);
00147         }
00148       catch(Basics::ParseUnitValFailure f)
00149         {
00150           cerr << program_name << ": Error parsing [UserInterface]vadvance_maxsize setting: " << f.emsg << endl
00151                << "\tUsing default value (" + Basics::FormatUnitVal(maxsize) + ")" << endl;
00152         }
00153     }
00154 
00155     // 
00156     // Parse command line
00157     //
00158     opterr = 0;
00159     for (;;) {
00160       c = getopt(argc, argv, "tqQfF:j:Jz:Zw:s:a:R:");
00161       if (c == EOF) break;
00162       switch (c) {
00163       case 't':
00164         test = true;
00165         query = true;
00166         break;
00167       case 'q':
00168         quiet = true;
00169         break;
00170       case 'Q':
00171         query = true;
00172         break;
00173       case 'f':
00174         force = true;
00175         break;
00176       case 'F':
00177         fp_content = strtol(optarg, 0, 0);
00178         break;
00179       case 'j':
00180         junk = optarg;
00181         break;
00182       case 'J':
00183         junk = "";
00184         break;
00185       case 'z':
00186         maxsize = Basics::ParseUnitVal(optarg);
00187         break;
00188       case 'Z':
00189         maxsize = MAXUL;
00190         break;
00191       case 'w':
00192         workdir = optarg;
00193         default_workdir = false;
00194         break;
00195       case 's':
00196         sessdir = optarg;
00197         default_sessdir = false;
00198         break;
00199       case 'a':
00200         sessverarc = optarg;
00201         default_sessverarc = false;
00202         break;
00203       case 'R':
00204         repos = optarg;
00205         default_repos = false;
00206         break;
00207       case '?':
00208       default:
00209         usage();
00210       }
00211     }
00212         
00213     switch (argc - optind) {
00214     case 1:
00215       if (default_workdir) {
00216         workdir = argv[optind];
00217         default_workdir = false;
00218       }
00219       break;
00220     case 0:
00221       break;
00222     default:
00223       usage();
00224       /* not reached */
00225     }
00226         
00227     //
00228     // Use a nondefault repository if specified
00229     //
00230     if (!default_repos) {
00231       int colon = repos.FindCharR(':');
00232       if (colon == -1) {
00233         lhost = repos;
00234         repos = repos + ":" + lport;
00235       } else {
00236         lhost = repos.Sub(0, colon);
00237         lport = repos.Sub(colon+1);
00238       }
00239     }
00240 
00241     //
00242     // Canonicalize names, fill in defaults, and map names to
00243     // VestaSource objects as needed.
00244     //
00245     if (default_workdir) {
00246       workdir = ".";
00247     }
00248     Text cworkdir = ReposUI::canonicalize(workdir, defworkpar + "/" + user);
00249     VestaSource* vs_workdir = ReposUI::filenameToVS(cworkdir, lhost, lport);
00250 
00251     Text csessdir;
00252     if (default_sessdir) {
00253       // Defaults to the "session-dir" attribute of work-dir
00254       char* attribval = vs_workdir->getAttrib("session-dir");
00255       if (attribval == NULL) {
00256         cerr << program_name << ": " << cworkdir
00257              << " is not a session working directory" << endl;
00258         exit(2);
00259       }
00260       sessdir = attribval;
00261       csessdir = ReposUI::canonicalize(attribval); // just in case
00262       delete attribval;
00263     } else {
00264       csessdir = ReposUI::canonicalize(sessdir, defpkgpar);
00265     }
00266     VestaSource* vs_sessdir = ReposUI::filenameToVS(csessdir, lhost, lport);
00267         
00268     // Try to find previous version in session
00269     Text prev_sessverarc;
00270     long high = ReposUI::highver(vs_sessdir);
00271     if (high < 0) high = 0;  // skip 0; reserved for base version
00272     char buf[64];
00273     sprintf(buf, "%ld", high);
00274     prev_sessverarc = buf;
00275     if (default_sessverarc) {
00276       // Defaults to 1 + previous version in session 
00277       char buf[64];
00278       sprintf(buf, "%ld", high + 1);
00279       sessverarc = buf;
00280     }
00281     Text csessver = csessdir + "/" + sessverarc;
00282         
00283     // Sanity checking and cleanup
00284     if (!force) {
00285       if (!vs_sessdir->inAttribs("type", "session")) {
00286         cerr << program_name << ": " << csessdir
00287           << " is not a session directory" << endl;
00288         exit(2);
00289       }
00290     }
00291 
00292     if (!query && (junk != "" || maxsize != MAXUL)) {
00293       ReposUI::cleanup(vs_workdir, junk, maxsize, cworkdir);
00294     }
00295 
00296     if(!query)
00297       {
00298         // If the user happened to rename their working direcotry, fix
00299         // up the work-dir attributes on the session directory and
00300         // reservation stub (if any).
00301 
00302         fix_work_dir_attrib(cworkdir, csessdir, vs_sessdir);
00303         char *cnewver = vs_workdir->getAttrib("new-version");
00304         if(cnewver != 0)
00305           {
00306             fix_work_dir_attrib(cworkdir, cnewver, lhost,lport);
00307             delete [] cnewver;
00308           }
00309       }
00310 
00311     if (!force) {
00312       // Use the modified time of the session directory as the
00313       // time of last vadvance.
00314       if (!ReposUI::changed(vs_workdir, vs_sessdir->timestamp())) {
00315         if (!quiet) {
00316           cout << "Unchanged from "
00317                << csessdir << "/" << prev_sessverarc << endl;
00318           exit(0);
00319         }
00320       }
00321     }
00322 
00323     if (!quiet) {
00324       cout << "Advancing to " << csessver << endl;
00325     }
00326 
00327     if (query) {
00328       if (!quiet) {
00329          cerr << program_name << ": nothing done (-Q or -t flag given)" << endl;
00330       }
00331       if (test) {
00332          exit(255);
00333       } else {
00334          exit(0);
00335       }
00336     }
00337 
00338     if (fp_content) {
00339       // Fingerprint content of files below size fp_content
00340       err = vs_workdir->makeFilesImmutable(fp_content);
00341       if (err != VestaSource::ok) {
00342         cerr << program_name 
00343              << ": error in makeFilesImmutable: "
00344              << ReposUI::errorCodeText(err) << endl;
00345         exit(2);
00346       }
00347     }
00348 
00349     //
00350     // Do the advance, with failure atomicity
00351     //
00352     VestaSourceAtomic vsa(lhost, lport);
00353 
00354     // Declare session directory and make sure it is master
00355     VestaSourceAtomic::VSIndex vsi_sessdir = vsa.decl(csessdir, vs_sessdir);
00356     vsa.testMaster(csessdir, vsi_sessdir, true, VestaSource::notMaster);
00357 
00358     // Declare workdir and check that we have write permission
00359     // so that attribs can be set.
00360     VestaSourceAtomic::VSIndex vsi_workdir = vsa.decl(cworkdir, vs_workdir);
00361     vsa.accessCheck(cworkdir, vsi_workdir, AccessControl::write,
00362                     true, VestaSource::noPermission);
00363 
00364     // All is well; we can start making changes.
00365 
00366     // Insert snapshot of workdir into sessdir
00367     vsa.insertImmutableDirectory(csessver, vsi_sessdir, sessverarc,
00368                                  vsi_workdir, true, VestaSource::dontReplace);
00369                                      
00370     // Set attribs
00371     vsa.setAttrib(cworkdir, vsi_workdir, "session-ver-arc", sessverarc);
00372 
00373     // Commit
00374     if (!vsa.run()) {
00375       VestaSource::errorCode err;
00376       if (vsa.lasterr == VestaSource::ok) {
00377         err = vsa.okreplace;
00378       } else {
00379         err = vsa.lasterr;
00380       }
00381       cerr << program_name << ": " << vsa.name(vsa.ndone) << ": "
00382            << ReposUI::errorCodeText(err) << endl;
00383       exit(2);
00384     }
00385 
00386   } catch (VestaConfig::failure f) {
00387     cerr << program_name << ": " << f.msg << endl;
00388     exit(2);
00389   } catch (SRPC::failure f) {
00390     cerr << program_name
00391          << ": SRPC failure; " << f.msg << " (" << f.r << ")" << endl;
00392     exit(2);
00393   } catch (ReposUI::failure f) {
00394     cerr << program_name << ": " << f.msg << endl;
00395     if(f.msg.FindText("max file size") > 0)
00396       {
00397         cerr << "\tUse '-z maxsize' to override or '-Z' to disable" << endl;
00398       }
00399     exit(2);
00400   } catch(Basics::ParseUnitValFailure f) {
00401     cerr << program_name << ": " << f.emsg << endl;
00402     exit(2);
00403   }
00404     
00405   return 0;
00406 }

Generated on Mon May 8 00:48:55 2006 for Vesta by  doxygen 1.4.2