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 // ReposUI.H 00021 // Helper functions for repository UI tools 00022 00023 #ifndef _REPOSUI_H_ 00024 #define _REPOSUI_H_ 00025 00026 #include <VestaSource.H> 00027 #include <VestaConfig.H> 00028 #include <FS.H> 00029 00030 class ReposUI { 00031 public: 00032 class failure { 00033 public: 00034 Text msg; 00035 int uerrno; // -1 if none 00036 VestaSource::errorCode code; // VestaSource::ok if none 00037 failure(const Text& msg = "", 00038 int uerrno = -1, 00039 VestaSource::errorCode code = VestaSource::ok) throw() 00040 : uerrno(uerrno), code(code), msg(msg) { }; 00041 }; 00042 00043 // 00044 // Name processing methods that do not access the repository 00045 // 00046 00047 // Return true if name has "/", ".", or ".." as its first component. 00048 static bool qualified(const Text& name) throw (); 00049 00050 // If name is not qualified, prepend the given default directory. 00051 static Text qualify(const Text& name, const Text& dir) throw (); 00052 00053 // Convert a name to canonical form, as follows: 00054 // 00055 // 1) If the name does not begin with "/", prepend the current 00056 // directory name (inserting a "/" separator if needed). The 00057 // current directory name is obtained by calling getcwd(). 00058 // 00059 // 2) Scan the name from left to right for ".", empty, and ".." 00060 // components. If a "." or empty component appears, delete it. 00061 // If a ".." appears, delete it and the preceding (not already 00062 // deleted) component. We do not expand symbolic links or check 00063 // whether components cancelled out by ".." actually exist in the 00064 // repository. 00065 // 00066 // 3) If the first component of the name is now 00067 // [UserInterface]AppendableRootName, replace it by "/vesta"; 00068 // else if the first component of the name is now 00069 // [UserInterface]MutableRootName, replace it by "/vesta-work"; 00070 // else if the first component of the name is now 00071 // "/vesta" or "/vesta-work", return the name unchanged; else 00072 // throw failure. 00073 // 00074 static Text canonicalize(const Text& name) 00075 throw (VestaConfig::failure, ReposUI::failure); 00076 00077 // Convenience procedure, equivalent to 00078 // canonicalize(qualify(name, root)) 00079 static Text canonicalize(const Text& name, const Text& root) 00080 throw (VestaConfig::failure, ReposUI::failure); 00081 00082 // Split name into parent name and final arc. 00083 // name must not be empty or end with "/". 00084 // errtext is incorported in the failure exception message on errors. 00085 // 00086 static void split(const Text& name, Text& par, Text& arc, 00087 const Text& errtext) throw (failure); 00088 00089 00090 // strip root name "/vesta" or [UserInterface]AppendableRootName, 00091 // or similarly for "/vesta-work", [UserInterface]MutableRootName, 00092 // or leaves the name unchanged if those were not found. 00093 // RootLoc indcates type of vesta root. 00094 enum RootLoc { VESTA, VESTAWORK, NOWHERE}; 00095 static Text stripRoot(const Text& name, /*OUT*/RootLoc& loc) 00096 throw (VestaConfig::failure); 00097 00098 // Remove the specified root from "name". If "name" doesn't start with 00099 // the specified root, throw ReposUI::failure. 00100 // If " require_canonical" is true, "name" must begin with the 00101 // canonical root (i.e. "/vesta" for ReposUI::VESTA, 00102 // "/vesta-work" for ReposUI::VESTAWORK). 00103 static Text stripSpecificRoot(const Text& name, RootLoc which_root, 00104 bool require_canonical = false) 00105 throw (ReposUI::failure, VestaConfig::failure); 00106 00107 // 00108 // Lookup and inverse lookup methods 00109 // 00110 00111 // Interpret a name as the name as of a source provided by the 00112 // Vesta repository. Return a VestaSource object for the source 00113 // found. The name is first converted to canonical form; see the 00114 // canonicalize() method below. Then if it begins with "/vesta", 00115 // it is looked up under the appendable root, if with 00116 // "/vesta-work", under the mutable root; otherwise an error is 00117 // reported. 00118 // 00119 // The first form looks in the default (local) repository; the 00120 // second and third forms allow you to specify a repository. 00121 // In the third form, hostport is host + ":" + port, or "" to 00122 // signify the default repository. 00123 // 00124 static VestaSource* filenameToVS(Text name) 00125 throw (failure, VestaConfig::failure, SRPC::failure); 00126 static VestaSource* filenameToVS(Text name, Text host, Text port) 00127 throw (failure, VestaConfig::failure, SRPC::failure); 00128 static VestaSource* filenameToVS(Text name, Text hostport) 00129 throw (failure, VestaConfig::failure, SRPC::failure); 00130 00131 // Like filenameToVS, but try to find the master copy, possibly on 00132 // a remote repository. Fail if the master copy can't be found. 00133 // The "hints" argument is a space-separated list of additional 00134 // host:port pairs to try besides those found as master-repository 00135 // attributes on the given name or its ancestors. 00136 static VestaSource* filenameToMasterVS(Text name, Text hints ="") 00137 throw (failure, VestaConfig::failure, SRPC::failure); 00138 00139 // Like filenameToVS, but try to find a copy that is not a 00140 // nonmaster ghost or nonmaster stub, possibly on a remote 00141 // repository. Fail if such a copy can't be found. The "hints" 00142 // argument is a space-separated list of additional host:port 00143 // pairs to try besides those found as master-repository 00144 // attributes on the given name or its ancestors. 00145 static VestaSource* filenameToRealVS(Text name, Text hints ="") 00146 throw (failure, VestaConfig::failure, SRPC::failure); 00147 00148 // Given a VestaSource, return a canonical pathname (starting with 00149 // "/") that will work with filenameToVS. The hardwired prefixes 00150 // "/vesta" and "/vesta-work" are used, not 00151 // [UserInterface]AppendableRootName and MutableRootName, in order 00152 // to make the returned name more suitable for use in attributes 00153 // that may be replicated, vrepl directives, the evaluator, etc. 00154 // 00155 static Text vsToFilename(VestaSource* vs) 00156 throw (failure, VestaConfig::failure, SRPC::failure); 00157 00158 // lookupCreatePath looks up or creates an appendable directory 00159 // specified by a relative path and a root directory. "pathname" 00160 // should be a relative path. "root_name" is the canonical name 00161 // of an appendable directory "pathname" should be interpreted 00162 // relative to. The optional "hints" parameter specifies 00163 // additional repositories to consult when looking for the master 00164 // copy of any directories. 00165 00166 // If pathname does not already exist below vs_root, the function 00167 // creates the new path by inserting appendable directories. 00168 // Returns a VestaSource object which is the master copy of the 00169 // appendable directory found or created for the full pathname 00170 // within the root. User is responsible for freeing the returned 00171 // object. 00172 static VestaSource* lookupCreatePath(Text root_name, 00173 Text pathname, Text hints = "") 00174 throw(failure, VestaConfig::failure, SRPC::failure); 00175 00176 // Given a VestaSource that is master, return the canonical 00177 // pathname of a directory whose master-repository hint should be 00178 // updated in a non-master replica. It traverses from vs_master 00179 // upward until it finds a directory whose parent is not master. 00180 // (This is used by some tools to automatically update 00181 // master-repository hint attributes.) 00182 static Text getMasterHintDir(VestaSource* vs_master, const Text& cname) 00183 throw (failure, SRPC::failure); 00184 00185 // 00186 // Methods that search directories and return useful information 00187 // 00188 00189 // Return the highest version number in directory vs. That is, 00190 // considering the set of arcs in the directory that are composed 00191 // entirely of decimal digits, interpret each as a decimal number and 00192 // return the value of the largest one. 00193 // Return -1 if the set is empty. 00194 // In the case of non-master stubs with integer version names in 00195 // directory vs, highver will try to find non-stub copies in other 00196 // repositories using the optional "hints" and "path" parameters. 00197 // The "hints" argument is the same format as that used with 00198 // filenameToRealVS above. The "path" parameter should be the 00199 // canonical name of vs if it is known by the caller. 00200 static long highver(VestaSource* vs, Text hints = "", Text path = "") 00201 throw (failure, SRPC::failure); 00202 00203 // Return a unique name in directory vs of the form basename.n, 00204 // where n is an integer. n is chosen so that no basename.m 00205 // exists with m > n. 00206 static Text uniquify(VestaSource* vs, const Text& prefix) 00207 throw (failure, SRPC::failure); 00208 00209 // Return true if the tree rooted at the given mutable working 00210 // directory has changed since the last vcheckout or vadvance. The 00211 // time of the vadvance must be provided as an argument, but the 00212 // checking is not based entirely on time. The tree is deemed to have 00213 // changed if (1) the modified time of any directory in the tree is 00214 // greater than the given time, or (2) any directory in the tree 00215 // contains a mutable file (i.e., a file for which no copy-on-write 00216 // has been performed since the last vcheckout or vadvance). 00217 static bool changed(VestaSource* vs, time_t since) 00218 throw (failure, SRPC::failure); 00219 00220 // Walk the tree rooted at the given mutable working directory. 00221 // Delete every file whose last arc matches the given pattern, and 00222 // then throw failure if any file added since the last advance 00223 // is larger than the given size. The pattern consists of 00224 // multiple fnmatch() patterns separated by spaces. prefix is the 00225 // name used for vs in the messages attached to failure 00226 // exceptions. 00227 static void cleanup(VestaSource* vs, const Text& pattern, 00228 unsigned long maxsize, const Text& prefix) 00229 throw (failure, SRPC::failure); 00230 00231 // 00232 // Miscellaneous 00233 // 00234 00235 // Give a user-friendly error code string instead of just printing 00236 // the name of the enum element. Should perhaps be in VestaSource.H. 00237 static const Text errorCodeText(VestaSource::errorCode) throw (failure); 00238 00239 // Ask the user to enter a text comment. It invokes the command 00240 // specified in the EDITOR environment variable to allow the user 00241 // to enter a message. If EDITOR is not set, it reads the comment 00242 // from standard input. A prompt is printed if the standard input 00243 // is a terminal. 00244 00245 // "description" should be a short string that explains what the 00246 // user is supposed to enter, such as "change history message". 00247 // "in_message" if provided will be an initial value for the 00248 // message given to the user to edit. "in_description" should be 00249 // description of the initial value, such as "Checkout comment". 00250 static Text getMessage(const Text &descripton, 00251 const Text &in_description = "", 00252 const char* in_message = 0) 00253 throw (failure, FS::Failure); 00254 00255 // find the version that an immutable directory is based on. 00256 static Text prevVersion(VestaSource* vs, Text hints = "") 00257 throw (failure, SRPC::failure); 00258 }; 00259 00260 #endif